概念

流是字节序列的抽象概念。

文件是数据的静态存储形式,而流是指数据传输时的形态。

流类分为两个大类:节点流类和过滤流类(也叫处理流类)。

程序用于直接操作目标设备所对应的类叫节点流类,程序也可以通过一个间接流类去调用节点流类,以达到更加灵活方便地读取各种类型的数据,这个间接流类就是过滤流类(也叫处理流类),或者称为包装类。

包装类的调用过程如下图:

047Stream流 - 图1

我们先来看看Java里面是怎么定义Stream的:

A sequence of elements supporting sequential and parallel aggregate operations.

我们来解读一下上面的那句话:

  1. Stream是元素的集合,这点让Stream看起来用些类似Iterator;
  2. 可以支持顺序和并行的对原Stream进行汇聚的操作;

大家可以把Stream当成一个高级版本的Iterator。原始版本的Iterator,用户只能一个一个的遍历元素并对其执行某些操作;高级版本的Stream,用户只要给出需要对其包含的元素执行什么操作,比如“过滤掉长度大于10的字符串”、“获取每个字符串的首字母”等,具体这些操作如何应用到每个元素上,就给Stream就好了!(这个秘籍,一般人我不告诉他:))大家看完这些可能对Stream还没有一个直观的认识,莫急,咱们来段代码。

  1. //Lists是Guava中的一个工具类
  2. List<Integer> nums = Lists.newArrayList(1,null,3,4,null,6);
  3. nums.stream().filter(num -> num != null).count();

上面这段代码是获取一个List中,元素不为null的个数。

流分类的关系

不管流的分类是多么的丰富和复杂,其根源来自于四个基本的类。这个四个类的关系如下:

字节流 字符流

输入流 InputStream Reader

输出流 OutputStream Writer

Java内用 Unicode 编码存储字符,字符流处理类负责将外部的其他编码的字符流和java内 Unicode 字符流之间的转换。而类InputStreamReader 和OutputStreamWriter处理字符流和字节流的转换。字符流(一次可以处理一个缓冲区)一次操作比字节流(一次一个字节)效率高。

InputStream

047Stream流 - 图2

由于InputStream和OutputStream是abstact类,所以它们还不能表明具体对应哪种IO设备。它们下面有许多子类,包括网络、管道、内存、文件等具体的IO设备,实际程序中使用的它们的各种子类对象。

注:我们将节点流类所对应的IO源和目标称为流节点(Node)。

注意:将A文件的内容写入B文件,程序对A文件的操作所用的是输出类还是输入类这个问题。输入输出类是相对程序而言的,而不是代表文件的,所以我们应该创建一个输入类来完成对A文件的操作,创建一个输出类来完成对B文件的操作。

OutputStream

047Stream流 - 图3

以字符为导向的 stream Reader/Writer

以 Unicode 字符为导向的 stream ,表示以 Unicode 字符为单位从 stream 中读取或往 stream 中写入信息。同样,Reader/Writer也为abstact类。

Reader

047Stream流 - 图4

Writer

047Stream流 - 图5

IO程序代码的复用:

平时写代码用-1来作为键盘输入的结束,在写的函数中不直接使用System.in,只是在调用该函数时,将System.in作为参数传递进去,这样,我们以后要从某个文件中读取数据,来代替手工键盘输入时,我们可以直接使用这个函数,程序就不用做太多的修改了,达到以不变应万变的效果。

字节流和字符流的相互转换

InputStreamReader和OutputStreamReader:把一个以字节为导向的stream转换成一个以字符为导向的stream。

InputStreamReader类是从字节流到字符流的桥梁:它读入字节,并根据指定的编码方式,将之转换为字符流。

使用的编码方式可能由名称指定,或平台可接受的缺省编码方式。

InputStreamReader的read()方法之一的每次调用,可能促使从基本字节输入流中读取一个或多个字节。

为了达到更高效率,考虑用BufferedReader封装InputStreamReader,

  1. BufferedReaderin = new BufferedReader(new InputStreamReader(System.in));

Stream流的介绍

stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果;
stream不会改变数据源,通常情况下会产生一个新的集合;
stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
对stream操作分为终端操作和中间操作,那么这两者分别代表什么呢?
终端操作:会消费流,这种操作会产生一个结果的,如果一个流被消费过了,那它就不能被重用的。
中间操作:中间操作会产生另一个流。因此中间操作可以用来创建执行一系列动作的管道。一个特别需要注意的点是:中间操作不是立即发生的。相反,当在中间操作创建的新流上执行完终端操作后,中间操作指定的操作才会发生。所以中间操作是延迟发生的,中间操作的延迟行为主要是让流API能够更加高效地执行。
stream不可复用,对一个已经进行过终端操作的流再次调用,会抛出异常。

剖析Stream通用语法

047Stream流 - 图6

图片就是对于Stream例子的一个解析,可以很清楚的看见:原本一条语句被三种颜色的框分割成了三个部分。红色框中的语句是一个Stream的生命开始的地方,负责创建一个Stream实例;绿色框中的语句是赋予Stream灵魂的地方,把一个Stream转换成另外一个Stream,红框的语句生成的是一个包含所有nums变量的Stream,进过绿框的filter方法以后,重新生成了一个过滤掉原nums列表所有null以后的Stream;蓝色框中的语句是丰收的地方,把Stream的里面包含的内容按照某种算法来汇聚成一个值,例子中是获取Stream中包含的元素个数。如果这样解析以后,还不理解,那就只能动用“核武器”–图形化,一图抵千言!

047Stream流 - 图7

在此我们总结一下使用Stream的基本步骤:

  1. 创建Stream;
  2. 转换Stream,每次转换原有Stream对象不改变,返回一个新的Stream对象(可以有多次转换);
  3. 对Stream进行聚合(Reduce)操作,获取想要的结果;

创建流

创建Stream

最常用的创建Stream有两种途径:

  1. 通过Stream接口的静态工厂方法(注意:Java8里接口可以带静态方法);
  2. 通过Collection接口的默认方法(默认方法:Default method,也是Java8中的一个新特性,就是接口中的一个带有实现的方法,后续文章会有介绍)–stream(),把一个Collection对象转换成Stream

使用Stream静态方法来创建Stream

  1. of方法:有两个overload方法,一个接受变长参数,一个接口单一值
  1. Stream<Integer> integerStream = Stream.of(1, 2, 3, 5);
  2. Stream<String> stringStream = Stream.of("taobao");
  1. generator方法:生成一个无限长度的Stream,其元素的生成是通过给定的Supplier(这个接口可以看成一个对象的工厂,每次调用返回一个给定类型的对象)
Stream.generate(new Supplier<Double>() {
@Override
 public Double get() {
            return Math.random();
 }
});
    Stream.generate(() -> Math.random());
    Stream.generate(Math::random);

三条语句的作用都是一样的,只是使用了lambda表达式和方法引用的语法来简化代码。每条语句其实都是生成一个无限长度的Stream,其中值是随机的。这个无限长度Stream是懒加载,一般这种无限长度的Stream都会配合Stream的limit()方法来用。

  1. iterate方法:也是生成无限长度的Stream,和generator不同的是,其元素的生成是重复对给定的种子值(seed)调用用户指定函数来生成的。其中包含的元素可以认为是:seed,f(seed),f(f(seed))无限循环
Stream.iterate(1, item -> item + 1).limit(10).forEach(System.out::println);

这段代码就是先获取一个无限长度的正整数集合的Stream,然后取出前10个打印。千万记住使用limit方法,不然会无限打印下去。

通过Collection子类获取Stream

这个在本文的第一个例子中就展示了从List对象获取其对应的Stream对象,如果查看Java doc就可以发现Collection接口有一个stream方法,所以其所有子类都都可以获取对应的Stream对象。

    public interface Collection<E> extends Iterable<E> {
        //其他方法省略
        default Stream<E> stream() {
            return StreamSupport.stream(spliterator(), false);
        }
    }
public class Demo1 {
    public static void main ( String[] args ) {
        //创建stream流,通过Arrays.stream
        int[] arr = {1, 2, 3};
        IntStream stream = Arrays.stream(arr);
        Person[] personStr = {new Person(18, "xiaoliu"), new Person(18, "xiaojing")};
        Stream<Person> personStream = Arrays.stream(personStr);
        // 通过stream.of
        Stream<Integer> integerStream = Stream.of(1, 2, 3, 4);
        // 通过集合创建流
        List<String> stringList = Arrays.asList("123", "456", "789");
        // 创建普通流
        Stream<String> stringStream = stringList.stream();
        // 创建并行流
        Stream<String> parallelStream = stringList.parallelStream();}
        }
 public class Demo2 {
    public static void main ( String[] args ) {
        // 流的筛选
        List<Integer> integerList = Arrays.asList(1, 2, 3,3, 4, 5, 6);
        // 筛选出集合中数字大于4的元素
        List<Integer> collect = integerList.stream().filter(x -> x > 4).collect(Collectors.toList());
        System.out.println(collect); //[5, 6]
        // 集合中的去重
        List<Integer> collect1 = integerList.stream().distinct().collect(Collectors.toList());
        System.out.println(collect1);//[1, 2, 3, 4, 5, 6]
        // 获取流中的第一个元素
        Optional<Integer> first = integerList.stream().filter(x -> x > 4).findFirst();
        Optional<Integer> any = integerList.stream().filter(x -> x > 4).findAny();
        Optional<Integer> any1 = integerList.parallelStream().filter(x -> x > 4).findAny();
        System.out.println(first); //Optional[5]
        System.out.println(any); //Optional[5]
        System.out.println(any1); // 预期结果不稳定

    }
}

Stream流中获取最值 max、min和count

public class Demo3 {
    public static void main(String[] args) {
        List<String> stringList = Arrays.asList("huainvhai", "xiaotiancai", "bennvhai");
        // 获取集合中最长的字符串
        Optional<String> maxString = stringList.stream().max(Comparator.comparing(String::length));
        // 获取集合中最短字符串
        Optional<String> minString = stringList.stream().min(Comparator.comparing(String::length));
        System.out.println(maxString);
        System.out.println(minString);



        // 获取集合中的最大值
        List<Integer> integerList = Arrays.asList(1, 2, 3);
        Optional<Integer> maxInteger = integerList.stream().max((i, j) -> {
            return i - j;
        });
        // 获取集合中的最小值
        Optional<Integer> minInteger = integerList.stream().max((i, j) -> {
            return j - i;
        });
        System.out.println(maxInteger);
        System.out.println(minInteger);




        // 集合泛型是个对象的最值
        ArrayList<Person> personList = new ArrayList<>();
        personList.add(new Person("xiao",12));
        personList.add(new Person("xiao",20));
        personList.add(new Person("xiao",18));
        Optional<Person> max = personList.stream().max(Comparator.comparing(Person::getAge));
        // 获取集合中的元素数量
        long count = personList.stream().filter(p -> p.getAge() > 12).count();
        System.out.println(max);
        System.out.println(count);
    }
}

缩减

缩减:就是把一个流缩减成一个值,比如说对一个集合中求和,求乘积等

Stream流定义了三个reduce

public interface Stream<T> extends BaseStream<T, Stream<T>> {
 // 方法1
 T reduce(T identity, BinaryOperator<T> accumulator);
 // 方法2
 Optional<T> reduce(BinaryOperator<T> accumulator);
 // 方法3
 <U> U reduce(U identity,
          BiFunction<U, ? super T, U> accumulator,
          BinaryOperator<U> combiner);
}

前两种缩减方式

第一种:接收一个BinaryOperator accumulator function(二元累加计算函数)和identity(标示值)为参数,返回值是一个T类型(代表流中的元素类型)的对象。accumulator代表操作两个值并得到结果的函数。identity按照accumulator函数的规则参与计算,假如函数是求和运算,那么函数的求和结果加上identity就是最终结果,假如函数是求乘积运算,那么函数结果乘以identity就是最终结果。

第二种:不同之处是没有identity,返回值是Optional(JDK8新类,可以存放null)。

public class Demo4 {
    public static void main(String[] args) {
        List<Integer> integers = Arrays.asList(1, 2, 3, 4);
        // 写法一 集合中的元素求和 (就是集合中的元素求和再加上1)
        Integer integer = integers.stream().reduce(1, Integer::sum);
        // 写法二
        integers.stream().reduce(1,(x,y)->x+y);
        System.out.println(integer); // 11

        // 第二种缩减方式 集合中的元素求和
        Optional<Integer> reduce = integers.stream().reduce(Integer::sum);
        // 写法二
        Optional<Integer> reduce1 = integers.stream().reduce((x, y) -> x + y);
        System.out.println(reduce); //Optional[10]
        System.out.println(reduce1); //Optional[10]

        // 集合中使用reduce求最值问题
        Optional<Integer> reduce2 = integers.stream().reduce(Integer::max);
        System.out.println(reduce2);

        /**
         * 对象集合求和 求最值问题
         */
        ArrayList<Person> personList = new ArrayList<>();
        personList.add(new Person("xiao",12));
        personList.add(new Person("xiao",20));
        personList.add(new Person("xiao",18));
        // 求集合中对象的年龄的总和
        Optional<Integer> reduce3 = personList.stream().map(p -> p.getAge()).reduce(Integer::sum);
        System.out.println(reduce3);  //Optional[50]

        // 求集合中年龄最大的对象
        Optional<Person> reduce4 = personList.stream().reduce((p1, p2) -> p1.getAge() > p2.getAge() ? p1 : p2);
        Optional<Person> max = personList.stream().max(Comparator.comparingInt(Person::getAge));
        System.out.println(reduce4);
        System.out.println(max);
    }
}

collect

collect操作可以接受各种方法作为参数,将流中的元素汇集,

public class Demo5 {
    public static void main(String[] args) {
        ArrayList<Person> personList = new ArrayList<>();
        personList.add(new Person("xiao",12));
        personList.add(new Person("xiao",20));
        personList.add(new Person("xiao",18));
        // 获取平均年龄 averaging
        Double collect = personList.stream().collect(Collectors.averagingInt(Person::getAge));
        System.out.println(collect); //16.666666666666668

        // summarizing
        DoubleSummaryStatistics collect1 = personList.stream().collect(Collectors.summarizingDouble(Person::getAge));
        System.out.println(collect1); // DoubleSummaryStatistics{count=3, sum=50.000000, min=12.000000, average=16.666667, max=20.000000}

        //joining
        String collect2 = personList.stream().map(p -> p.getName()).collect(Collectors.joining(","));
        System.out.println(collect2);  //xiao,xiao,xiao

        // reduce
        Integer collect3 = personList.stream().collect(Collectors.reducing(0, Person::getAge, (x, y) -> x + y));
        Optional<Integer> reduce = personList.stream().map(Person::getAge).reduce(Integer::sum);
        System.out.println(collect3); //50
        System.out.println(reduce);   //Optional[50]

        // groupingBy
        // 以名字进行分组
        Map<String, List<Person>> collect4 = personList.stream().collect(Collectors.groupingBy(Person::getName));
        System.out.println(collect4); //{xiao=[Person(name=xiao, age=12), Person(name=xiao, age=20), Person(name=xiao, age=18)]}
        // 先以名字分组,再以年龄分组
        Map<String, Map<Integer, List<Person>>> collect5 = personList.stream().collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getAge)));
        System.out.println(collect5); //{xiao={18=[Person(name=xiao, age=18)], 20=[Person(name=xiao, age=20)], 12=[Person(name=xiao, age=12)]}}

        // toList、toSet、toMap
        Set<Person> collect6 = personList.stream().collect(Collectors.toSet());
        System.out.println(collect6);//[Person(name=xiao, age=18), Person(name=xiao, age=20), Person(name=xiao, age=12)]

    }
}

映射

Stream流中,map可以将一个流的元素按照一定的映射规则映射到另一个流中。

public class Demo6 {
    public static void main(String[] args) {
        String[] strArr = { "abcd", "bcdd", "defde", "ftr" };
        Arrays.stream(strArr).map(x->x.toUpperCase()).forEach(System.out::print); //ABCDBCDDDEFDEFTR
        List<String> collect = Arrays.stream(strArr).map(x -> x.toUpperCase()).collect(Collectors.toList());
        System.out.println(collect); // [ABCD, BCDD, DEFDE, FTR]

    }
}

排序

Sorted方法是对流进行排序,并得到一个新的stream流,是一种中间操作。Sorted方法可以使用自然排序或特定比较器。

public class Demo7 {
    public static void main(String[] args) {
        String[] strArr = { "ab", "bcdd", "defde", "ftr" };
        // 自然排序
        List<String> collect = Arrays.stream(strArr).sorted().collect(Collectors.toList());
        System.out.println(collect);  // [ab, bcdd, defde, ftr]

        // 自定义排序
        // 按照字符串的长度 长度 从小到大
        List<String> collect1 = Arrays.stream(strArr).sorted(Comparator.comparing(String::length)).collect(Collectors.toList());
        System.out.println(collect1); //[ab, ftr, bcdd, defde]
        // 按照字符串的长度逆序排序
        List<String> collect2 = Arrays.stream(strArr).sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList());
        System.out.println(collect2); //[defde, bcdd, ftr, ab]

        // 首字母倒序
        List<String> collect3 = Arrays.stream(strArr).sorted(Comparator.reverseOrder()).collect(Collectors.toList());
        System.out.println(collect3); //[ftr, defde, bcdd, ab]
        // 首字母自然排序
        List<String> collect4 = Arrays.stream(strArr).sorted(Comparator.naturalOrder()).collect(Collectors.toList());
        System.out.println(collect4); //[ab, bcdd, defde, ftr]
    }
}

提取流和组合流

public class Demo8 {
    public static void main(String[] args) {
        String[] arr1 = {"a","b","c","d"};
        String[] arr2 = {"d","e","f","g"};
        String[] arr3 = {"i","j","k","l"};

        Stream<String> stream1 = Arrays.stream(arr1);
        Stream<String> stream2 = Arrays.stream(arr2);
        Stream<String> stream3 = Arrays.stream(arr3);
        // 可以把两个stream合并成一个stream(合并的stream类型必须相同),只能两两合并
//        List<String> collect = Stream.concat(stream1, stream2).collect(Collectors.toList());
//        System.out.println(collect); //[a, b, c, d, d, e, f, g]
        // 合并去重
        List<String> collect1 = Stream.concat(stream1, stream2).distinct().collect(Collectors.toList());
        System.out.println(collect1); //[a, b, c, d, e, f, g]

        // limit,限制从流中获得前n个数据
//        List<String> collect = collect1.stream().limit(3).collect(Collectors.toList());
//        System.out.println(collect); //[a, b, c]

        // skip,跳过前n个数据
        List<String> collect = collect1.stream().skip(1).limit(3).collect(Collectors.toList());
        System.out.println(collect);//[b, c, d]
    }
}

汇聚(Reduce)Stream

汇聚这个词,是我自己翻译的,如果大家有更好的翻译,可以在下面留言。在官方文档中是reduce,也叫fold。

在介绍汇聚操作之前,我们先看一下Java doc中对于其定义:

A reduction operation (also called a fold) takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation, such as finding the sum or maximum of a set of numbers, or accumulating elements into a list. The streams classes have multiple forms of general reduction operations, called reduce() and collect(), as well as multiple specialized reduction forms such as sum(), max(), or count().

简单翻译一下:汇聚操作(也称为折叠)接受一个元素序列为输入,反复使用某个合并操作,把序列中的元素合并成一个汇总的结果。比如查找一个数字列表的总和或者最大值,或者把这些数字累积成一个List对象。Stream接口有一些通用的汇聚操作,比如reduce()和collect();也有一些特定用途的汇聚操作,比如sum(),max()和count()。注意:sum方法不是所有的Stream对象都有的,只有IntStream、LongStream和DoubleStream是实例才有。

下面会分两部分来介绍汇聚操作:

  1. 可变汇聚:把输入的元素们累积到一个可变的容器中,比如Collection或者StringBuilder;
  2. 其他汇聚:除去可变汇聚剩下的,一般都不是通过反复修改某个可变对象,而是通过把前一次的汇聚结果当成下一次的入参,反复如此。比如reduce,count,allMatch;

可变汇聚

可变汇聚对应的只有一个方法:collect,正如其名字显示的,它可以把Stream中的要有元素收集到一个结果容器中(比如Collection)。先看一下最通用的collect方法的定义(还有其他override方法):

    <R> R collect(Supplier<R> supplier,
                      BiConsumer<R, ? super T> accumulator,
                      BiConsumer<R, R> combiner);

先来看看这三个参数的含义:Supplier supplier是一个工厂函数,用来生成一个新的容器;BiConsumer accumulator也是一个函数,用来把Stream中的元素添加到结果容器中;BiConsumer combiner还是一个函数,用来把中间状态的多个结果容器合并成为一个(并发的时候会用到)。看晕了?来段代码!

List<Integer> nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);
        List<Integer> numsWithoutNull = nums.stream().filter(num -> num != null).
                collect(() -> new ArrayList<Integer>(),
                        (list, item) -> list.add(item),
                        (list1, list2) -> list1.addAll(list2));

上面这段代码就是对一个元素是Integer类型的List,先过滤掉全部的null,然后把剩下的元素收集到一个新的List中。进一步看一下collect方法的三个参数,都是lambda形式的函数(上面的代码可以使用方法引用来简化,留给读者自己去思考)。

  • 第一个函数生成一个新的ArrayList实例;
  • 第二个函数接受两个参数,第一个是前面生成的ArrayList对象,二个是stream中包含的元素,函数体就是把stream中的元素加入ArrayList对象中。第二个函数被反复调用直到原stream的元素被消费完毕;
  • 第三个函数也是接受两个参数,这两个都是ArrayList类型的,函数体就是把第二个ArrayList全部加入到第一个中;

但是上面的collect方法调用也有点太复杂了,没关系!我们来看一下collect方法另外一个override的版本,其依赖Collector

    <R, A> R collect(Collector<? super T, A, R> collector);

这样清爽多了!少年,还有好消息,Java8还给我们提供了Collector的工具类–Collectors,其中已经定义了一些静态工厂方法,比如:Collectors.toCollection()收集到Collection中, Collectors.toList()收集到List中和Collectors.toSet()收集到Set中。这样的静态方法还有很多,这里就不一一介绍了,大家可以直接去看JavaDoc。下面看看使用Collectors对于代码的简化:

List<Integer> numsWithoutNull = nums.stream().filter(num -> num != null).
                    collect(Collectors.toList());

其他汇聚

– reduce方法:reduce方法非常的通用,后面介绍的count,sum等都可以使用其实现。reduce方法有三个override的方法,本文介绍两个最常用的,最后一个留给读者自己学习。先来看reduce方法的第一种形式,其方法定义如下:

1 Optional<T> reduce(BinaryOperator<T> accumulator);

接受一个BinaryOperator类型的参数,在使用的时候我们可以用lambda表达式来。

    List<Integer> ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
    System.out.println("ints sum is:" + ints.stream().reduce((sum, item) -&gt; sum + item).get());

可以看到reduce方法接受一个函数,这个函数有两个参数,第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数。要注意的是:第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素。这个方法返回值类型是Optional,这是Java8防止出现NPE的一种可行方法,后面的文章会详细介绍,这里就简单的认为是一个容器,其中可能会包含0个或者1个对象。
这个过程可视化的结果如图:
047Stream流 - 图8
reduce方法还有一个很常用的变种:

1 T reduce(T identity, BinaryOperator<T> accumulator);

这个定义上上面已经介绍过的基本一致,不同的是:它允许用户提供一个循环计算的初始值,如果Stream为空,就直接返回该值。而且这个方法不会返回Optional,因为其不会出现null值。下面直接给出例子,就不再做说明了。

1 List<Integer> ints = Lists.newArrayList(``1``,``2``,``3``,``4``,``5``,``6``,``7``,``8``,``9``,``10``);
2 System.out.println(``"ints sum is:" + ints.stream().reduce(``0``, (sum, item) -> sum + item));

– count方法:获取Stream中元素的个数。比较简单,这里就直接给出例子,不做解释了。

1 List<Integer> ints = Lists.newArrayList(``1``,``2``,``3``,``4``,``5``,``6``,``7``,``8``,``9``,``10``);
2 System.out.println(``"ints sum is:" + ints.stream().count());

– 搜索相关
– allMatch:是不是Stream中的所有元素都满足给定的匹配条件
– anyMatch:Stream中是否存在任何一个元素满足匹配条件
– findFirst: 返回Stream中的第一个元素,如果Stream为空,返回空Optional
– noneMatch:是不是Stream中的所有元素都不满足给定的匹配条件
– max和min:使用给定的比较器(Operator),返回Stream中的最大|最小值
下面给出allMatch和max的例子,剩下的方法读者当成练习。

查看源代码

List<Integer&gt; ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);
    System.out.println(ints.stream().allMatch(item -> item < 100));
    ints.stream().max((o1, o2) -&gt; o1.compareTo(o2)).ifPresent(System.out::println);