一.什么是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