Java8

Java8 Stream流

2019-12-17  本文已影响0人  超天大圣JR

一、Stream流的特性

关于应用在Stream流上的操作,可以分成两种:Intermediate(中间操作)和Terminal(终止操作)。中间操作的返回结果都是Stream,故可以多个中间操作叠加;终止操作用于返回我们最终需要的数据,只能有一个终止操作。

二、Stream的操作分类

Stream的操作有Intermediate、Terminal和Short-circuiting:

三、惰性求值和及早求值方法

像filter这样只描述Stream,最终不产生新集合的方法叫作惰性求值方法;而像count这样最终会从Stream产生值的方法叫作及早求值方法。

long count = allArtists.stream()
    .filter(artist -> {
        System.out.println(artist.getName());
            return artist.isFrom("London");
        })
    .count();

如何判断一个操作是惰性求值还是及早求值,其实很简单,只需要看其返回值即可:如果返回值是Stream,那么就是惰性求值;如果返回值不是Stream或者是void,那么就是及早求值。上面的示例中,只是包含两步:一个惰性求值filter和一个及早求值count。
在一个Stream操作中,可以有多次惰性求值,但有且仅有一次及早求值。

四、对Stream的操作一般可以归纳为3个部分

1. 创建Stream

- of(T... values):返回含有多个T元素的Stream
- of(T t):返回含有一个T元素的Stream
示例:
Stream<Integer> integerStream = Stream.of(1, 2, 3);
Stream<String> stringStream = Stream.of("A");
- generate(Supplier<T> s):返回一个无限长度的Stream
示例:
Stream<Double> generateA = Stream.generate(new Supplier<Double>() {
    @Override
    public Double get() {
        return java.lang.Math.random();
    }
});

Stream<Double> generateB = Stream.generate(()-> java.lang.Math.random());
Stream<Double> generateC = Stream.generate(java.lang.Math::random);

以上三种形式达到的效果是一样的,只不过是下面的两个采用了Lambda表达式,简化了代码,其实际效果就是返回一个随机值。一般无限长度的Stream会与filter、limit等配合使用,否则Stream会无限制的执行下去。

- iterate(T seed, UnaryOperator<T> f)
示例:
Stream.iterate(1, item -> item + 1)
        .limit(10)
        .forEach(System.out::println); 
        // 打印结果:1,2,3,4,5,6,7,8,9,10

上面示例,种子为1,也可认为该Stream的第一个元素,通过f函数来产生第二个元素。接着,第二个元素,作为产生第三个元素的种子,从而产生了第三个元素,以此类推下去。需要主要的是,该Stream也是无限长度的,应该使用filter、limit等来截取Stream,否则会一直循环下去。

    public interface Collection<E> extends Iterable<E> {
        ***
        default Stream<E> stream() {
            return StreamSupport.stream(spliterator(), false);
        }
        ***
    }

在Arrays类,封装了一些列的Stream方法,不仅针对于任何类型的元素采用了泛型,更对于基本类型作了相应的封装,以便提升Stream的处理效率。

public class Arrays {
    ***
    public static <T> Stream<T> stream(T[] array) {
        return stream(array, 0, array.length);
    }

   public static LongStream stream(long[] array) {
        return stream(array, 0, array.length);
    }
    ***
}
示例:
int ids[] = new int[]{1, 2, 3, 4};
Arrays.stream(ids)
        .forEach(System.out::println);

2. Intermediate:通过一系列中间(Intermediate)方法,对数据集进行过滤、检索等数据集的再次处理,实际上是将源Stream转换为一个新的Stream,以达到需求效果。

Stream.concat(Stream.of(1, 2, 3), Stream.of(4, 5))
       .forEach(integer -> System.out.print(integer + "  "));
// 打印结果:  1  2  3  4  5  
Stream.of(1,2,3,1,2,3)
        .distinct()
        .forEach(System.out::println); 
// 打印结果:1,2,3
Stream.of(1, 2, 3, 4, 5)
        .filter(item -> item > 3)
        .forEach(System.out::println);
// 打印结果:4,5

\color{red}{filter传入的Lambda表达式必须是Predicate实例,参数可以为任意类型,而其返回值必须是boolean类型。}

Stream.of("a", "b", "hello")
        .map(item-> item.toUpperCase())     // 这里与flatMap不同
        .forEach(System.out::println);
        // 打印结果
        // A, B, HELLO

\color{red}{map传入的Lambda表达式必须是Function实例,参数可以为任意类型,而其返回值也是任性类型,javac会根据实际情景自行推断。}

Stream.of(1, 2, 3)
    .flatMap(integer -> Stream.of(integer * 10))   //这里与map不同
    .forEach(System.out::println);
    // 打印结果
    // 10,20,30

传给flatMap中的表达式接受了一个Integer类型的参数,通过转换函数,将原元素乘以10后,生成一个只有该元素的流,该流取代原流中的元素。
\color{red}{flatMap传入的Lambda表达式必须是Function实例,参数可以为任意类型,而其返回值类型必须是一个Stream。}

Stream.of(1, 2, 3, 4, 5)
        .peek(integer -> System.out.println("accept:" + integer))
        .forEach(System.out::println);
// 打印结果
// accept:1
//  1
//  accept:2
//  2
//  accept:3
//  3
//  accept:4
//  4
//  accept:5
//  5
Stream.of(1, 2, 3,4,5)
.skip(2)
.forEach(System.out::println);
// 打印结果
// 3,4,5
Stream.of(5, 4, 3, 2, 1)
        .sorted()
        .forEach(System.out::println);
        // 打印结果
        // 1,2,3,4,5

Stream.of(1, 2, 3, 4, 5)
        .sorted((o1, o2) -> o2 - o1)    //逆序
        .forEach(System.out::println);
        // 打印结果
        // 5, 4, 3, 2, 1

3. Terminal通过最终(terminal)方法完成对数据集中元素的处理。

long count = Stream.of(1, 2, 3, 4, 5)
        .count();
System.out.println("count:" + count);// 打印结果:count:5
Stream.of(5, 4, 3, 2, 1)
    .sorted()
    .forEach(System.out::println);
    // 打印结果
    // 1,2,3,4,5
Stream.of(5,2,1,4,3)
        .forEachOrdered(integer -> {
            System.out.println("integer:"+integer);
        }); 
        // 打印结果
        // integer:5
        // integer:2
        // integer:1
        // integer:4
        // integer:3

原Stream根据比较器Comparator,进行排序(升序或者是降序),所谓的最大值就是从新进行排序的,max就是取重新排序后的最后一个值,而min取排序后的第一个值。

Optional<Integer> max = Stream.of(1, 2, 3, 4, 5)
        .max((o1, o2) -> o2 - o1);
System.out.println("max:" + max.get());// 打印结果:max:1
Optional<Integer> max = Stream.of(1, 2, 3, 4, 5)
        .max((o1, o2) -> o1 - o2);
System.out.println("max:" + max.get());// 打印结果:min:5

五、Short-circuiting操作

boolean allMatch = Stream.of(1, 2, 3, 4)
    .allMatch(integer -> integer > 0);
System.out.println("allMatch: " + allMatch); // 打印结果:allMatch: true 
Optional<Integer> any = Stream.of(1, 2, 3, 4).findAny();
 System.out.println(any.get());
//输出结果:1
Optional<Integer> any = Stream.of(1, 2, 3, 4).findFirst();
Stream.of(1, 2, 3,4,5)
        .limit(2)
        .forEach(System.out::println);
        // 打印结果
        // 1,2

传入limit的值为2,也就是说被截取后的Stream的最大长度为2,又由于原Stream中有5个元素,所以将截取原Stream中的前2个元素,生成一个新的Stream。

    boolean noneMatch = Stream.of(1, 2, 3, 4, 5)
        .noneMatch(integer -> integer > 10);
    System.out.println("noneMatch:" + noneMatch); // 打印结果 noneMatch:true

    boolean noneMatch_ = Stream.of(1, 2, 3, 4, 5)
            .noneMatch(integer -> integer < 3);
    System.out.println("noneMatch_:" + noneMatch_); // 打印结果 noneMatch_:false
上一篇下一篇

猜你喜欢

热点阅读