JDK1.8新特性:stream

2019-12-01 来源: 山猫大战响尾蛇 发布在  https://www.cnblogs.com/Createsequence/p/11967561.html

一.什么是stream?

1.概述

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

元素流在管道中经过中间操作的处理,最后由最终操作得到前面处理的结果。

简单描述一下大概是这样:

+--------------------+       +----------+    +----------+         +----------+    +--------------+
   获得的stream对象  -----  中间操作1 --  中间操作2 - ... - 最终操作  --  最终返回的对象
+--------------------+       +----------+    +----------+         +----------+    +--------------+

二. 举个例子?

现在有一个字符串集合,我们需要过滤掉集合里头长度小于2的字符串:

public static void main( String[] args ) {
    ListString strings = Arrays.asList(ab, , bc, cd, abcd,, jkl);
    ListString stringList = new ArrayList();
    for (String str  strings){
        如果长度大于2
        if (str.length() = 2){
            将字符串添加至新集合
            stringList.add(str);
        }
    }
    strings = stringList;
}

如果使用stream实现一模一样的效果:

public static void main( String[] args ) {
    ListString strings = Arrays.asList(ab, , bc, cd, abcd,, jkl);
    通过stream操作集合
    strings = strings.stream()
        去掉长度小于2的字符串
        .filter(s - s.length() = 2)
        转回集合
        .collect(Collectors.toList());
}

可见,使用streamAPI可以轻松写出更高效,更简洁,可读性更强的代码

三. 如何使用stream?

简单的说,分两步:生成流,操作流

1. 生成流

Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, 不支持Map

1.1 Collection接口的stream()或parallelStream()方法

将Set或List集合直接转换为stream对象
ListPerson personList = new ArrayList();
SetPerson set = new HashSet();

StreamPerson personStream1 = personList.stream();生成串行流
StreamPerson personStream2 = set.parallelStream();生成并行流

1.2 Stream.of(),Arrays.stream,Stream.empty()方法

String[] strArr = {a,a,a,a,a,a};

Stream.empty()
StreamInteger integerStream = Stream.empty();

Stream.of() (方法内部调用的还是Arrays.stream)
StreamString stringStream = Stream.of(strArr);

Arrays.stream
StreamString stringStream2 = Arrays.stream(strArr);

1.3 Stream.concat()方法

已有的对象
StreamInteger integerStream = Stream.empty();
StreamString stringStream = Stream.of(strArr);
StreamString stringStream2 = Arrays.stream(strArr);

合并两个流
Stream conStream1 = Stream.concat(stringStream,integerStream);
Stream conStream2 = Stream.concat(stringStream,stringStream2);

1.4 静态的Files.lines(path)

File file = new File(Dtest.txt);
StreamString lines = Files.lines(file);

2. 操作流

Stream 操作分为中间操作或者最终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,可以在后头跟上其他中间操作

接下来的示例代码基于此集合
ListString strings = Arrays.asList(ab, , bc, cd, abcd,, jkl);

2.1 filter(Predicate:将结果为false的元素过滤掉

去掉长度小于2的字符串
strings = strings.stream()
    .filter(s - s.length() = 2)
    返回集合
    .collect(Collectors.toList());

System.out.println(strings);

打印strings
[ab, bc, cd, abcd, jkl]

2.2 map(fun):转换元素的值,可以用方法引元或者lambda表达式

strings = strings.stream()
    为每个字符串加上“???”
    .map(s - s += ???)
    返回集合
    .collect(Collectors.toList());

System.out.println(strings);

打印strings
[ab???, ???, bc???, cd???, abcd???, ???, jkl???]

2.3 limit(n):保留前n个元素

strings = strings.stream()
    保留前3个
    .limit(3)
    返回集合
    .collect(Collectors.toList());

System.out.println(strings);

打印strings
[ab, , bc]

2.4 skip(n):跳过前n个元素

strings = strings.stream()
    跳过前2个
    .skip(2)
    返回集合
    .collect(Collectors.toList());

System.out.println(strings);

打印strings
[bc, cd, abcd, , jkl]

2.5 distinct():剔除重复元素

strings = strings.stream()
    过滤重复元素
    .distinct()
    返回集合
    .collect(Collectors.toList());

System.out.println(strings);

打印strings(过滤掉了一个空字符串)
[ab, , bc, cd, abcd, jkl]

2.6 sorted():将Comparable元素的流排序

strings = strings.stream()
    按字符串长度排序
    .sorted(
        比较字符串长度
        Comparator.comparing(s - s.length())
    )
    返回集合
    .collect(Collectors.toList());

System.out.println(strings);

打印strings(过滤掉了一个空字符串)
[, , ab, bc, cd, jkl, abcd]

2.7 peek(fun):流不变,但会把每个元素传入fun执行,可以用作调试

strings = strings.stream()
    为字符串增加“???”
    .peek(s - s += )
    返回集合
    .collect(Collectors.toList());

System.out.println(strings);

打印strings,和map对比,实际并没有改变集合
[ab, , bc, cd, abcd, , jkl]

2.8 flatMap(fun):若元素是流,将流摊平为正常元素,再进行元素转换

将具有多重嵌套结构的集合扁平化

获取一个两重集合
ListString strings = Arrays.asList(ab, , bc, cd, abcd,, jkl);
ListString strings2 = Arrays.asList(asd, , bzxasdc, cddsdsd, adsdsg,, jvcbl);
ListListString lists = new ArrayList();
lists.add(strings);
lists.add(strings2);

获取将两重集合压成一层
ListString stringList = lists.stream()
    将两重集合的子元素,即集合strings和strings2转成流再平摊
    .flatMap(Collectionstream)
    返回集合
    .collect(Collectors.toList());

System.out.println(stringList);

打印stringList
[ab, , bc, cd, abcd, , jkl, asd, , bzxasdc, cddsdsd, adsdsg, , jvcbl]

2.9 anyMatch(fun),allMatch(fun):判断流中的元素是否匹配 【最终操作】

allMatch
Boolean isAllMatch = strings.stream()
    判断元素中是否有匹配“ab”的字符串,返回true或fals
    判断元素中的字符串是否都与“ab”匹配,返回true或fals
    .allMatch(str - str.equals(ab));

System.out.println(isMatch);

anyMatch
Boolean isAnyMatch = strings.stream()
    判断元素中是否有匹配“ab”的字符串,返回true或fals
    .anyMatch(str - str.equals(ab));

System.out.println(isAnyMatch: + isAnyMatch);
System.out.println(isAllMatch: + isAllMatch);

打印结果
isAnyMatch:true
isAllMatch:false

2.10 forEach(fun): 迭代流中的每个数据 【最终操作】

strings.stream()
    遍历每一个元素
    .forEach(s - System.out.print(s + ; ));

2.11 collect():返回结果集 【最终操作】

strings = strings.stream()
    返回集合
    .collect(Collectors.toList());

四. 使用IntSummaryStatistics类处理数据

1. IntSummaryStatistics类

IntSummaryStatistics类,在 java8中配合Stream使用,是用于收集统计信息(例如计数,最小值,最大值,总和和平均值)的状态对象。

这个类长这样:

public class IntSummaryStatistics implements IntConsumer {
    private long count;
    private long sum;
    private int min = Integer.MAX_VALUE;
    private int max = Integer.MIN_VALUE;

    public IntSummaryStatistics() { }

    @Override
    public void accept(int value) {
        ++count;
        sum += value;
        min = Math.min(min, value);
        max = Math.max(max, value);
    }

    public void combine(IntSummaryStatistics other) {
        count += other.count;
        sum += other.sum;
        min = Math.min(min, other.min);
        max = Math.max(max, other.max);
    }

    public final long getCount() {
        return count;
    }

    public final long getSum() {
        return sum;
    }

    public final int getMin() {
        return min;
    }

    public final int getMax() {
        return max;
    }

    public final double getAverage() {
        return getCount()  0  (double) getSum()  getCount()  0.0d;
    }

    @Override
    public String toString() {
        return String.format(
            %s{count=%d, sum=%d, min=%d, average=%f, max=%d},
            this.getClass().getSimpleName(),
            getCount(),
            getSum(),
            getMin(),
            getAverage(),
            getMax());
    }
}

2.使用

这个类的理解起来很简单,内部有这几个方法:

2.1 获取总条数:getCount(),

2.2 获取和:getSum(),

2.3 获取最小值:getMin(),

2.4 获取最大值:getMax(),

2.5 获取平均值:getAverage()

示例如下:

public static void main( String[] args ) {
    ListInteger integerList = Arrays.asList(3, 4, 22, 31, 75, 32, 54);

    IntSummaryStatistics sta = integerList
        .stream()
        将元素映射为对应的数据类型(int,double,long)
        .mapToInt(i - i)
        转换为summaryStatistics类
        .summaryStatistics();

    System.out.println(总共有  + sta.getCount());
    System.out.println(列表中最大的数   + sta.getMax());
    System.out.println(列表中最小的数   + sta.getMin());
    System.out.println(所有数之和   + sta.getSum());
    System.out.println(平均数   + sta.getAverage());
}

打印结果
总共有  7
列表中最大的数  75
列表中最小的数  3
所有数之和  221
平均数  31.571428571428573

相关文章