Java8 stream使用体验

    最近在工作中发现了对于集合操作转换的神器,java8新特性 stream,学习了下发现有很多值得整理的用法,这里记录下。

一、什么是stream

Stream 作为 Java 8 的一大亮点,它与 java.io 包里的 InputStream 和 OutputStream 是完全不同的概念。它也不同于 StAX 对 XML 解析的 Stream,也不是 Amazon Kinesis 对大数据实时处理的 Stream。Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。


二、如何使用stream

我们先看一段demo

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

stream使用结构如下:

Java8 stream使用体验_第1张图片


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


三、用法分类

下面我们通过具体的demo 来看下实际用法吧

forEach() -->对流中的每个元素执行一些操作。
toArray() --> 将流中的元素倾倒入一个数组。
reduce() --> 通过一个二进制操作将流中的元素合并到一起。
collect() --> 将流中的元素倾倒入某些容器,eg:一个Collection或Map.
min() --> 根据一个比较器找到流中元素的最小值。
max() --> 根据一个比较器找到流中元素的最大值。
count() --> 计算流中元素的数量。
anyMatch() --> 判断流中是否至少有一个元素匹配断言。这是一个短路的操作。
allMatch() --> 判断流中是否每一个元素都匹配断言。这是一个短路的操作。
noneMatch()--> 判断流中是否没有一个元素匹配断言。这是一个短路的操作。
findFirst()--> 查找流中的第一个元素。这是一个短路的操作。
findAny() --> 查找流中的任意元素,可能对某些流要比findFirst代价低。这是一个短路的操作


1、filter

  /**
     * filter 对原始 Stream 进行某项测试,通过测试的元素被留下来生成一个新 Stream。
     */
    List nums = Lists.newArrayList(1,null,3,4,null,6);
        nums.stream().filter(num -> num != null).count();

2、reduce

/**
         * reduce 是把 Stream 元素组合起来。
         * 它提供一个起始值(种子),然后依照运算规则(BinaryOperator),
         * 和前面 Stream 的第一个、第二个、第 n 个元素组合。
         */
        // 字符串连接,concat = "ABCD"
        String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
        // 求最小值,minValue = -3.0
        double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
        // 求和,sumValue = 10, 有起始值
        int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
        // 求和,sumValue = 10, 无起始值
        sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
        // 过滤,字符串连接,concat = "ace"
        concat = Stream.of("a", "B", "c", "D", "e", "F").
                filter(x -> x.compareTo("Z") > 0).
                reduce("", String::concat);

3、limit/skip

/**
         * limit 返回 Stream 的前面 n 个元素;
         * skip 则是扔掉前 n 个元素(它是由一个叫 subStream 的方法改名而来)。
         */
        List persons = new ArrayList();
        for (int i = 1; i <= 10000; i++) {
            Person person = new Person(i,"name"+i);
            persons.add(person);
        }
        List personList2 = persons.stream().
                map(Person::getName).limit(10).skip(3).collect(Collectors.toList());
        System.out.println(personList2);

4、foreach

//forEach 方法接收一个 Lambda 表达式,然后在 Stream 的每一个元素上执行该表达式
// Java 8
roster.stream()
 .filter(p -> p.getGender() == Person.Sex.MALE)
 .forEach(p -> System.out.println(p.getName()));
// Pre-Java 8
for (Person p : roster) {
 if (p.getGender() == Person.Sex.MALE) {
 System.out.println(p.getName());
 }
}


5、match

Stream 有三个 match 方法,从语义上说

allMatch:Stream 中全部元素符合传入的 predicate,返回 true

anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true

noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true

List persons = new ArrayList();
persons.add(new Person(1, "name" + 1, 10));
persons.add(new Person(2, "name" + 2, 21));
persons.add(new Person(3, "name" + 3, 34));
persons.add(new Person(4, "name" + 4, 6));
persons.add(new Person(5, "name" + 5, 55));
boolean isAllAdult = persons.stream().
 allMatch(p -> p.getAge() > 18);
System.out.println("All are adult? " + isAllAdult);
boolean isThereAnyChild = persons.stream().
 anyMatch(p -> p.getAge() < 12);
System.out.println("Any child? " + isThereAnyChild);

6、sort

/**
         * 对 Stream 的排序通过 sorted 进行,
         * 它比数组的排序更强之处在于你可以首先对 Stream 进行各类 map、filter、limit、skip 甚至 distinct 来减少元素数量后,
         * 再排序,这能帮助程序明显缩短执行时间。
         */
        List persons = new ArrayList();
       for (int i = 1; i <= 5; i++) {
        Person person = new Person(i, "name" + i);
        persons.add(person);
        }
        List personList2 = persons.stream().limit(2).sorted((p1, p2) -> p1.getName().compareTo(p2.getName())).collect(Collectors.toList());
        System.out.println(personList2);
    }

四、实战用法

(1) 根据List创建Map

List list = IntStream.range(1, 100).boxed().collect(Collectors.toList());
Map map = list.stream().collect(Collectors.toMap(p -> p, q->q*3));
System.out.println(map);

(2)求列表元素的最大数

List list = new Random().ints(-100,100).limit(250).boxed().collect(Collectors.toList());
Optional max = list.stream().reduce(Math::max);
max.ifPresent(value -> System.out.println(value));


(3)把所有的姓名大写、排序,再输出

String[] names = { "Fred Edwards", "Anna Cox", "Deborah Patterson", "Ruth Torres", "Shawn Powell",
                "Rose Thompson", "Rachel Barnes", "Eugene Ramirez", "Earl Flores", "Janice Reed", "Sarah Miller",
                "Patricia Kelly", "Carl Hall", "Craig Wright", "Martha Phillips", "Thomas Howard", "Steve Martinez",
                "Diana Bailey", "Kathleen Hughes", "Russell Anderson", "Theresa Perry" };
Arrays.asList(names)
         .stream()
         .map(String::toUpperCase)
         .sorted().forEach(System.out::println);

(4)依次输入0-9

IntStream.range(0, 10).forEach(value -> System.out.println(value));


(5)根据条件进行分组

Map> collect = persons.stream().collect(Collectors.groupingBy(Person::getAge));


(6)对所有求平均

Double collect = persons.stream().collect(Collectors.averagingInt(Person::getAge));

参考文献:JAVA8初体验

        Java 8 中的 Streams API 详解









你可能感兴趣的:(JAVA)