1. 创建 Stream
- Collection.stream
- Stream.of
- String.chars
- IntStream.range
2. Stream 中间操作
返回 stream 的操作都是中间操作。
collect 等
- 仍然返回 Stream 的操作
- filter
- map
- flatMap 每使用一次,流降低一个维度
- sorted
3. Stream 终结操作
- 返回非 stream 的操作,包括返回 void
- 一个流只能被消费一次
- collect【最强大的操作】
- forEach
- count/max/min
- findFirst/findAny
- anyMatch/noneMatch
4. Collector 与 Collectors
Collector 接口顾名思义收集者,把输入流汇聚到一起成为一个 collection 集合。而 Collectors 则是对应的工具类。
一般配合 stream.collect 使用。Collectors 常用方法:
- toSet/toList/toCollection
- joining
- toMap
- groupingBy
5. 并发流
parallel 并发数是CPU核心数-1,当前CPU核心数是:Runtime.getRuntime().availableProcessors()。
- parallelStream()
- 可以通过并发提高互相独立的操作的性能
- 在正确使用的前提下,可以获得近似线性的性能提升
- 但是需要进行实际测试,盲目的使用可能导致实际上更慢
6. 实战
6.1 filter/count/sorted/map/toCollection
import java.util.Arrays;import java.util.Comparator;import java.util.LinkedList;import java.util.List;import java.util.stream.Collectors;public class Problem1 {static class User {private String name;private int age;User(String name, int age) {this.name = name;this.age = age;}public String getName() { return name; }public int getAge() { return age; }}// 编写一个方法,统计"年龄大于等于60的用户中,名字是两个字的用户数量"public static int countUsers(List<User> users) {return (int) users.stream().filter(user -> user.getAge() >= 60).filter(user -> user.getName().length() == 2).count();}// 编写一个方法,筛选出年龄大于等于60的用户,然后将他们按照年龄从大到小排序,将他们的名字放在一个LinkedList中返回public static LinkedList<String> collectNames(List<User> users) {return users.stream().filter(user -> user.getAge() >= 60).sorted(Comparator.comparing(User::getAge).reversed()).map(User::getName).collect(Collectors.toCollection(LinkedList::new));}public static void main(String[] args) {System.out.println(countUsers(Arrays.asList(new User("张三", 60),new User("李四", 61),new User("张三丰", 300),new User("王五", 12))));System.out.println(collectNames(Arrays.asList(new User("张三", 60),new User("李四", 61),new User("张三丰", 300),new User("王五", 12))));}}
6.2 anyMatch
import java.util.Arrays;import java.util.List;public class Problem2 {// 判断一段文本中是否包含关键词列表中的文本,如果包含任意一个关键词,返回true,否则返回false// 例如,text="catcatcat,boyboyboy", keywords=["boy", "girl"],返回true// 例如,text="I am a boy", keywords=["cat", "dog"],返回falsepublic static boolean containsKeyword(String text, List<String> keywords) {// return keywords.stream().filter(text::contains).findAny().isPresent(); // 笨办法return keywords.stream().anyMatch(text::contains);}public static void main(String[] args) {System.out.println(containsKeyword("catcatcat,boyboyboy", Arrays.asList("boy", "girl")));System.out.println(containsKeyword("I am a boy", Arrays.asList("cat", "dog")));}}
6.3 String.chars/filter/count
public class Problem3 {// 使用流的方法,再把之前的题目做一遍吧// 统计一个给定的字符串中,大写英文字母(A,B,C,...,Z)出现的次数。// 例如,给定字符串"AaBbCc1234ABC",返回6,因为该字符串中出现了6次大写英文字母ABCABCpublic static int countUpperCaseLetters(String str) {return (int) str.chars().filter(Character::isUpperCase).count();}public static void main(String[] args) {System.out.println(countUpperCaseLetters("AaBbCc1234ABC"));}}
6.4 orted/groupingBy
import java.util.Arrays;import java.util.Comparator;import java.util.List;import java.util.Map;import java.util.Objects;import java.util.stream.Collectors;public class Problem4 {// 再用流的方法把之前的题目做一遍吧:// 请编写一个方法,对传入的List<Employee>进行如下处理:// 返回一个从部门名到这个部门的所有用户的映射。同一个部门的用户按照年龄进行从小到大排序。// 例如,传入的employees是[{name=张三, department=技术部, age=40 }, {name=李四, department=技术部, age=30 },// {name=王五, department=市场部, age=40 }]// 返回如下映射:// 技术部 -> [{name=李四, department=技术部, age=30 }, {name=张三, department=技术部, age=40 }]// 市场部 -> [{name=王五, department=市场部, age=40 }]public static Map<String, List<Employee>> collect(List<Employee> employees) {return employees.stream().sorted(Comparator.comparing(Employee::getAge)).collect(Collectors.groupingBy(Employee::getDepartment));}public static void main(String[] args) {System.out.println(collect(Arrays.asList(new Employee(1, "张三", 40, "技术部"),new Employee(2, "李四", 30, "技术部"),new Employee(3, "王五", 40, "市场部"))));}static class Employee {// 用户的idprivate final Integer id;// 用户的姓名private final String name;// 用户的年龄private final int age;// 用户的部门,例如"技术部"/"市场部"private final String department;Employee(Integer id, String name, int age, String department) {this.id = id;this.name = name;this.age = age;this.department = department;}@Overridepublic String toString() {return "Employee{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", department='" + department + '\'' +'}';}public Integer getId() { return id; }public String getName() { return name; }public int getAge() { return age; }public String getDepartment() { return department; }@Overridepublic boolean equals(Object o) {if (this == o) {return true;}if (o == null || getClass() != o.getClass()) {return false;}Employee person = (Employee) o;return Objects.equals(id, person.id);}@Overridepublic int hashCode() {return Objects.hash(id);}}}
6.5 toMap
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Problem5 {
// 使用流的方法,把订单处理成ID->订单的映射
// 例如,传入参数[{id=1,name='肥皂'},{id=2,name='牙刷'}]
// 返回一个映射{1->Order(1,'肥皂'),2->Order(2,'牙刷')}
public static Map<Integer, Order> toMap(List<Order> orders) {
return orders.stream()
.collect(Collectors.toMap(Order::getId, order -> order));
}
public static void main(String[] args) {
System.out.println(toMap(Arrays.asList(new Order(1, "肥皂"), new Order(2, "牙刷"))));
}
static class Order {
private Integer id;
private String name;
Order(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() { return id; }
public String getName() { return name; }
@Override
public String toString() {
return "Order{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
}
6.6 filter/joining
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
public class Problem6 {
// 使用流的方法,把所有长度等于1的单词挑出来,然后用逗号连接起来
// 例如,传入参数words=['a','bb','ccc','d','e']
// 返回字符串a,d,e
public static String filterThenConcat(Set<String> words) {
return words.stream()
.filter(word -> word.length() == 1)
.collect(Collectors.joining(","));
}
public static void main(String[] args) {
Set<String> set = new LinkedHashSet<>(Arrays.asList("a", "bb", "ccc", "d", "e"));
System.out.println(filterThenConcat(set));
}
}
7. 参考
- Effective Java Item 42-48
- IDEA stream 调试器

