Java -> Stream入门


学习Stream的目的

  • 函数式编程渐渐变成主流,为了看懂同事的代码。

  • 相对于传统的编程方式,代码更为简洁清晰易懂。

  • 使得并发编程变得如此简单。

  • 有效的避免了代码嵌套地狱。(见样例)

    if (条件1) {
        if (条件2) {
            if (条件3) {
                // 再嵌套下去都快见到Diablo了。
            }
        }
    }
    

Stream的特点

  • 不修改数据源:任何对于Stream对象的操作都不会修改数据源的数据。
  • 延迟执行:中间操作只是对于一系列操作细节的定义,而非执行。只有在终端操作被调用的同时执行中间操作。
  • 可消费:任何一个Stream对象执行了终端操作后都将不可再利用。只能操作由数据源生成的新的Stream。

Stream的分类

  • 串行流:单项环境下的Stream,基础。

    List.of().stream();
    
  • 并行流:多线程环境下的Stream,重点难点。本文中未涉及。

    List.of().parallelStream();
    

Stream对象的创建

总共有三种方式:

  • 经由集合对象创建

    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream();
    
  • 经由数组对象创建(两种)

    String[] strs = new String[10];
    // 将数组所有元素装入stream
    Stream<String> stream1 = Arrays.stream(strs);
    // 将数组指定区间的元素装入stream
    Stream<String> stream2 = Arrays.stream(strs, 1, 7);
    
  • 使用Stream的静态方法创建(三种)

    // 由单个元素创建Stream,元素不允许为null
    Stream<String> stream1 = Stream.of("Test");
    // 由单个元素创建stream,元素允许为null
    Stream<String> stream2 = Stream.ofNullable(null);
    // 由多个元素创建stream,内部其实调用的是Arrays.stream(T[] array)
    Stream<String> stream3 = Stream.of("Test1", "Test2", "Test3");
    

方法的分类

  • 中间操作:根据调用的方法,返回各种各样的stream对象。传入的各种Lambda只是修改了该对象中对应方法的定义,而非执行。
  • 终端操作:执行终端操作的方法,并且其间也执行中间操作对应的方法。

常用方法(入门)

中间操作

distinct

方法签名:Stream<T> distinct()
作用:返回一个去重后的Stream。

List<String> list = List.of("1", "1");
list.stream().distinct()
    .forEach(t -> System.out.println(t)); // 输出:1

filter

方法签名:Stream<T> filter(Predicate<? super T> predicate)
作用:返回一个由满足predicate条件的元素构成的Stream。

List<Integer> list = List.of(1, 3, 5);
list.stream().filter(t -> t >= 3)
    .forEach(t -> System.out.println(t)); // 输出:3, 5

sorted

因为sorted存在两种重载,并且在jdk源码的实现并不相同,所以我们分开讨论。

方法签名:Stream<T> sorted()
作用:通过调用T类型重写Comparable接口的compareTo方法排序,返回排序后的Stream。

// 此处省略了一些java文件定义的结构,请着眼于一下核心代码
// NG例, 不实现Comparable接口
class MyInteger {
    int value;
    MyInteger(int value) {
    	this.value = value;
    }
}
List<MyInteger> list = new ArrayList<>();
list.add(new MyInteger(4));
list.add(new MyInteger(1));
list.add(new MyInteger(3));
list.stream().sorted() // 不报错
    .forEach(t -> System.out.println(t.value)); // ClassCastException:不能被强转成Comparable类型

// OK例, 实现Comparable接口(Integer实现了Comparable接口)
List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().sorted()
    .forEach(t -> System.out.println(t)); // 输出:1 3 4

方法签名:Stream<T> sorted(Comparator<? super T> comparator)
作用:通过调用传入的comparator的compare方法排序,返回排序后的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().sorted((o1, o2) -> o2 - o1) // 传入一个比较器的实现
    .forEach(t -> System.out.println(t.value)); // 输出:4 3 1

skip

方法签名:Stream<T> skip(long n)
作用:返回一个不包含前n项的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().skip(2) // 跳过前两个元素
    .forEach(t -> System.out.println(t.value)); // 输出:3

limit

方法签名:Stream<T> limit(long n)
作用:返回一个包含前n项的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().limit(2) // 跳过前两个元素
    .forEach(t -> System.out.println(t.value)); // 输出:4 1

peek

方法签名:Stream<T> peek(Consumer<? super T> action)
作用:执行消费操作,返回原Stream。虽然有消费操作,但是Stream的状态并不会改变。并不会真正消费Stream这一特点是的peek方法常用于调试。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Stream<Integer> stream = list.stream();
stream.peek(t -> System.out.println(t)); // 输出:4 1 3, 并且不消费stream
stream.forEach(t -> System.out.println(t)); // 输出:4 1 3, 并且消费stream(消费后stream不可再次使用)
stream.forEach(t -> System.out.println(t)); // IllegalStateException:stream已经被操作或关闭

map

方法签名:Stream<T> map(Function<? super T, ? extends R> mapper)
作用:将原Stream中的所有元素类型从T转化为R(不是强转,是通过一些操作得到R类型),返回封装R类型元素的Stream。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().map(t -> String.valueOf(t)) // 将元素都转换成String
    .forEach(t -> System.out.println(t)); // 输出:4 1 3

flatMap

方法签名:Stream<T> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
作用:将原Stream中的所有元素类型从T转化为R,返回Stream<R>。与map的主要区别在于,适配一对多的数据类型。比如,类型T中存在一个List<String>,使用map返回一个Stream<List<String>>,而是用flatMap则返回一个Stream<String>,实现一对多的映射。

List<Integer[]> list = new ArrayList<>();
list.add(new Integer[] {1, 2, 3});
list.add(new Integer[] {4, 5, 3});
list.stream().flatMap(t -> Stream.of(t)) // 将各个数组中的元素都放入stream, 实现 1 → n 的转换
    .forEach(t -> System.out.println(t)); // 输出:1 2 3 4 5 3

终端操作

forEach

方法签名:void forEach(Consumer<? super T> action)
作用:迭代消费Stream里的所有元素,比如打印,写入文件,写入DB等。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
list.stream().forEach(t -> System.out.println(t)); // 输出:4 1 3

toArray

方法签名:Object[] toArray()
作用:将Stream中的所有元素封装成Object[]返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Object[] objects = list.stream().toArray(); // 与元素类型无关, 固定返回Object[]
Integer[] ints = (Integer[])objects; // 使用时你可能需要类型强转

count

方法签名:long count()
作用:返回Stream中的元素个数。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
long count = list.stream().count(); // 返回stream中的元素个数, 当前为3

findFirst

方法签名:Optional<T> findFirst()
作用:Stream的第一个元素封装在Optional中返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> first = list.stream().findFirst(); // 返回stream中的第一个元素, 当前为4
/* 
	Optional类内容比较多所以现在不做赘述, 大家姑且就认为是个只能存放一个元素的容器就好,以后会开一个新的博文详细为	大家讲解用法
 */

anyMatch

方法签名:boolean anyMatch(Predicate<? super T> predicate)
作用:当存在符合predicate条件的元素时返回true,否则返回false。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().anyMatch(t -> t <= 1); // 当一个元素小于等于1时就返回true, 当前true

allMatch

方法签名:boolean allMatch(Predicate<? super T> predicate)
作用:当所有元素都符合predicate条件时返回true,否则返回false。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().allMatch(t -> t <= 1); // 当所有元素小于等于1时才返回true, 当前false

noneMatch

方法签名:boolean noneMatch(Predicate<? super T> predicate)
作用:当所有元素都不符合predicate条件时返回true,否则返回false。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
boolean bool = list.stream().noneMatch(t -> t <= 1); // 当所有元素都不小于等于1时才返回true, 当前false

min

方法签名:Optional<T> min(Comparator<? super T> comparator)
作用:按照传入的比较器将最小的元素封装在Optional中返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> min = list.stream().min((o1, o2) -> o2 - o1); // 根据传入的比较器实现返回最小值, 当前4
/*
	这个方法可以认为stream按照传入的比较器排序, 返回排序后的第一个元素
 */

max

方法签名:Optional<T> max(Comparator<? super T> comparator)
作用:按照传入的比较器将最大的元素封装在Optional中返回。

List<Integer> list = new ArrayList<>();
list.add(4);
list.add(1);
list.add(3);
Optional<Integer> max = list.stream().max((o1, o2) -> o2 - o1); // 根据传入的比较器实现返回最大值
/*
	这个方法可以认为stream按照传入的比较器排序, 返回排序后的最后一个元素
 */

本文只讨论了串行流的使用方法,对于并行流等进阶的使用方法请参考 Java -> Stream进阶(尚未更新)

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/282263.html

(0)
上一篇 2022年8月26日
下一篇 2022年8月26日

相关推荐

发表回复

登录后才能评论