Java8新特性之Stream
- Stream是对集合操作的增强,流不是集合的元素,不是一种数据结构,不负责数据的存储。流更像一个迭代器,可以单项的遍历一个集合中的元素,并且不可循环。对于使用角度而言,个人觉得最大的好处就是简化代码量。
- 使用流式编程的步骤
- 获取数据源,将数据源中的数据读取到流中
- (中间操作)对流中的数据进行各种各样的处理。如过滤、去重、排序、替换等操作
- (最终操作)对流中的数据进行整合处理
- 数据源的获取
- 常用的数据源是集合或者数组
- 集合:list.stream()
- 数组:Arrays.stream(arr1)
- 中间操作
- 提前预制数据:
private static class Student implements Comparable<Student> { int id; int score; String name; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return id == student.id && score == student.score && Objects.equals(name, student.name); } @Override public int hashCode() { return Objects.hash(id, score, name); } public Student(int id, int score, String name) { this.id = id; this.score = score; this.name = name; } @Override public String toString() { return "Student{" + "id=" + id + ", score=" + score + ", name='" + name + '\'' + '}'; } public int getId() { return id; } public int getScore() { return score; } public String getName() { return name; } @Override public int compareTo(Student o) { return score - o.getScore(); } }
public Stream<Student> getDataSource1() { List<Student> students = new ArrayList<>(); Collections.addAll(students, new Student(1, 90, "zhangsan"), new Student(1, 90, "lisi"), new Student(2, 80, "wangwu"), new Student(3, 85, "zhaoliu"), new Student(4, 80, "qianqi"), new Student(4, 80, "qianqi"), new Student(5, 90, "liuba")); return students.stream(); }
- 每进行一个中间操作,还会得到一个流,即可以一直使用中间操作,直到使用最终操作来终止流
- filter:条件过滤
- 仅保留符合条件的数据,不符合的将会被删除
- 如
@Test public void filterUsage() { Stream<Student> dataSource1 = getDataSource1(); dataSource1.filter(s -> s.getScore() > 80).forEach(System.out::println); }
结果:Student{id=1, score=90, name='zhangsan'}
Student{id=1, score=90, name='lisi'}
Student{id=3, score=85, name='zhaoliu'}
Student{id=5, score=90, name='liuba'}
- distinct:进行去重。其去重规则和HashSet的原理相同,故要重写equals()和hashCode()
-
@Test public void distinctUsage() { Stream<Student> dataSource1 = getDataSource1(); dataSource1.distinct().forEach(System.out::println); }
结果:将Student{id=4, score=80, name='qianqi'}去除一个
Student{id=1, score=90, name='zhangsan'}
Student{id=1, score=90, name='lisi'}
Student{id=2, score=80, name='wangwu'}
Student{id=3, score=85, name='zhaoliu'}
Student{id=4, score=80, name='qianqi'}
Student{id=5, score=90, name='liuba'}
-
- sorted: 进行排序
-
@Test public void sorted() { Stream<Student> dataSource1 = getDataSource1(); // 采用该类重写的排序方法进行排序 dataSource1.sorted().forEach(System.out::println); // 自定义排序规则 // dataSource1.sorted((s1, s2) -> s2.getScore() - s1.getScore()).forEach(System.out::println); }
-
- limit&skip
- limit:从0开始截取,一直到指定的参数位置
- skip:从指定的参数位置开始截取
- 两者经常结合使用,如获取:当score从高往低排序时,截取[3,5]的信息
@Test public void limitAndSkipUsage() { Stream<Student> dataSource1 = getDataSource1(); dataSource1.sorted((s1,s2)->s2.score-s1.score).limit(5).skip(2).forEach(System.out::println); }
结果:
Student{id=5, score=90, name='liuba'}
Student{id=3, score=85, name='zhaoliu'}
Student{id=2, score=80, name='wangwu'}
- map&flatmap
- map对流中的元素进行映射,用新的数据来代替旧的数据
- flatmap也是对集合中的元素来进行映射,通常来进行扁平化映射:对于map进行直接映射完成后,流中的数据是一个容器,而我们需要对流中的数据进行处理,此时,可以使用扁平化映射,将容器中元素直接存入到流中
-
@Test
public void mapUsage() {
// 将流中的student对象,映射成对象的name
Stream<Student> dataSource1 = getDataSource1();
dataSource1.map(Student::getName).forEach(System.out::println);
}结果:
zhangsan
lisi
wangwu
zhaoliu
qianqi
qianqi
liuba/** * 需求:统计字符串中出现的所有字符 */ @Test public void flatMapUsage(){ String [] arr1 = {"zhangsan","lisi"}; // 流经过map之后,变成一个容器,此时可用扁平化映射 Arrays.stream(arr1).map(x->x.split("")).flatMap(Arrays::stream).distinct().forEach(System.out::print); }
结果:zhangsli
- 提前预制数据:
- 最终操作
- 将流中的数据整合到一起,可以放入集合中,也可以遍历打印、数据统计...
- 注意:之所以叫最终操作,是因为,执行完之后,流会关闭,且流中的数据也全都会被销毁,此时如果再使用中间操作或者最终操作,就会报异常
- collect:将流中的数据收集起来,其参数是一个Collector接口,且这个接口并不是函数式接口,实现这个接口,可以自定义收集的规则,但大多数情况下都是不必定义规则,直接使用Collectors工具提供的方法即可。准备数据:
// 获取数据源 public Stream<Integer> getDataSource() { List<Integer> integers = new ArrayList<>(); Collections.addAll(integers, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); return integers.stream(); }
- 转成list、set、map:
/** *转成list、set、map */ @Test public void collectUsage() { Stream<Integer> dataSource = getDataSource(); // List<Integer> collect = dataSource.collect(Collectors.toList()); // System.out.println(collect); // Set<Integer> collect = dataSource.collect(Collectors.toSet()); // System.out.println(collect); Map<String, Integer> collect = dataSource.collect(Collectors.toMap(Object::toString, x -> x)); System.out.println(collect); }
- reduce:将流中的数据按照某种规则收集起来。如求和
@Test public void reduceUsage() { Stream<Integer> dataSource = getDataSource(); Integer integer = dataSource.reduce(Integer::sum).get(); System.out.println(integer); }
- count:求流中元素的个数
@Test public void countUsage() { Stream<Integer> dataSource = getDataSource(); long count = dataSource.count(); System.out.println(count); }
- forEach:循环遍历打印流中的元素
@Test public void forEachUsage() { Stream<Integer> dataSource = getDataSource(); dataSource.forEach(System.out::println); }
- max&min求流中的最大值和最小值
@Test public void maxAndMinUsage() { Stream<Integer> dataSource = getDataSource(); // Integer integer = dataSource.max(Integer::compareTo).get(); Integer integer = dataSource.min(Integer::compareTo).get(); System.out.println(integer); }
- Matching:分为allMatch、anyMatch、noneMatch
- allMatch当所有元素都符合条件,则返回true
- anyMatch当有任一个元素符合条件,都返回true
- noneMatch当所有元素都不符合元素时,才返回true
@Test public void matchUsage() { Stream<Integer> dataSource = getDataSource(); // boolean b = dataSource.allMatch(x -> x <10); // boolean b = dataSource.anyMatch(x -> x >= 9); boolean b = dataSource.noneMatch(x -> x > 10); System.out.println(b); }
- find
- findFirst从流中获取一个元素(一般指第一个)
- findAny从流中获取一个元素(串行流stream是获取第一个,并行流parallelStream则不一定)
@Test public void findUsage() { Stream<Integer> dataSource = getDataSource(); Integer integer = dataSource.findFirst().get(); System.out.println(integer); }
-
相关类:
package stream; import org.junit.jupiter.api.Test; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; /** * 简单描述 * * @author lijie * @data 2021/2/17 21:32 */ public class FinalOperation { // 获取数据源 public Stream<Integer> getDataSource() { List<Integer> integers = new ArrayList<>(); Collections.addAll(integers, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9); return integers.stream(); } private static class Student implements Comparable<Student> { int id; int score; String name; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return id == student.id && score == student.score && Objects.equals(name, student.name); } @Override public int hashCode() { return Objects.hash(id, score, name); } public Student(int id, int score, String name) { this.id = id; this.score = score; this.name = name; } @Override public String toString() { return "Student{" + "id=" + id + ", score=" + score + ", name='" + name + '\'' + '}'; } public int getId() { return id; } public int getScore() { return score; } public String getName() { return name; } @Override public int compareTo(Student o) { return score - o.getScore(); } } public Stream<Student> getDataSource1() { List<Student> students = new ArrayList<>(); Collections.addAll(students, new Student(1, 90, "zhangsan"), new Student(1, 90, "lisi"), new Student(2, 80, "wangwu"), new Student(3, 85, "zhaoliu"), new Student(4, 80, "qianqi"), new Student(4, 80, "qianqi"), new Student(5, 90, "liuba")); students.parallelStream() return students.stream(); } /** *转成list、set、map */ @Test public void collectUsage() { Stream<Integer> dataSource = getDataSource(); // List<Integer> collect = dataSource.collect(Collectors.toList()); // System.out.println(collect); // Set<Integer> collect = dataSource.collect(Collectors.toSet()); // System.out.println(collect); Map<String, Integer> collect = dataSource.collect(Collectors.toMap(Object::toString, x -> x)); System.out.println(collect); } @Test public void reduceUsage() { Stream<Integer> dataSource = getDataSource(); Integer integer = dataSource.reduce(Integer::sum).get(); System.out.println(integer); } @Test public void countUsage() { Stream<Integer> dataSource = getDataSource(); long count = dataSource.count(); System.out.println(count); } @Test public void forEachUsage() { Stream<Integer> dataSource = getDataSource(); dataSource.forEach(System.out::println); } @Test public void maxAndMinUsage() { Stream<Integer> dataSource = getDataSource(); // Integer integer = dataSource.max(Integer::compareTo).get(); Integer integer = dataSource.min(Integer::compareTo).get(); System.out.println(integer); } @Test public void matchUsage() { Stream<Integer> dataSource = getDataSource(); // boolean b = dataSource.allMatch(x -> x <10); // boolean b = dataSource.anyMatch(x -> x >= 9); boolean b = dataSource.noneMatch(x -> x > 10); System.out.println(b); } @Test public void findUsage() { Stream<Integer> dataSource = getDataSource(); Integer integer = dataSource.findFirst().get(); System.out.println(integer); } @Test public void filterUsage() { Stream<Student> dataSource1 = getDataSource1(); dataSource1.filter(s -> s.getScore() > 80).forEach(System.out::println); } @Test public void distinctUsage() { Stream<Student> dataSource1 = getDataSource1(); dataSource1.distinct().forEach(System.out::println); } @Test public void sorted() { Stream<Student> dataSource1 = getDataSource1(); // 采用该类重写的排序方法进行排序 dataSource1.sorted().forEach(System.out::println); // 自定义排序规则 // dataSource1.sorted((s1, s2) -> s2.getScore() - s1.getScore()).forEach(System.out::println); } @Test public void limitAndSkipUsage() { Stream<Student> dataSource1 = getDataSource1(); dataSource1.sorted((s1,s2)->s2.score-s1.score).limit(5).skip(2).forEach(System.out::println); } @Test public void mapUsage() { // 将流中的student对象,映射成对象的name Stream<Student> dataSource1 = getDataSource1(); dataSource1.map(Student::getName).forEach(System.out::println); } /** * 需求:统计字符串中出现的所有字符 */ @Test public void flatMapUsage(){ String [] arr1 = {"zhangsan","lisi"}; // 流经过map之后,变成一个容器,此时可用扁平化映射 Arrays.stream(arr1).map(x->x.split("")).flatMap(Arrays::stream).distinct().forEach(System.out::print); } }
- 转成list、set、map:
参考:
- https://www.jianshu.com/p/3dc56886c2eb
- https://www.jianshu.com/p/7eaa0969b424