一.什么是stream?

1.概述

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

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

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

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

二. 举个例子?

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

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

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

public static void main( String[] args ) {
List<String> 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对象
List<Person> personList = new ArrayList<>();
Set<Person> set = new HashSet<>(); Stream<Person> personStream1 = personList.stream();//生成串行流
Stream<Person> personStream2 = set.parallelStream();//生成并行流

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

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

//Stream.empty()
Stream<Integer> integerStream = Stream.empty(); //Stream.of() (方法内部调用的还是Arrays.stream)
Stream<String> stringStream = Stream.of(strArr); //Arrays.stream
Stream<String> stringStream2 = Arrays.stream(strArr);

1.3 Stream.concat()方法

//已有的对象
Stream<Integer> integerStream = Stream.empty();
Stream<String> stringStream = Stream.of(strArr);
Stream<String> 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("D://test.txt");
Stream<String> lines = Files.lines(file);

2. 操作流

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

//接下来的示例代码基于此集合
List<String> 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):若元素是流,将流摊平为正常元素,再进行元素转换

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

//获取一个两重集合
List<String> strings = Arrays.asList("ab", "", "bc", "cd", "abcd","", "jkl");
List<String> strings2 = Arrays.asList("asd", "", "bzxasdc", "cddsdsd", "adsdsg","", "jvcbl");
List<List<String>> lists = new ArrayList<>();
lists.add(strings);
lists.add(strings2); //获取将两重集合压成一层
List<String> stringList = lists.stream()
//将两重集合的子元素,即集合strings和strings2转成流再平摊
.flatMap(Collection::stream)
//返回集合
.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 ) {
List<Integer> 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

JDK1.8新特性(一):stream的更多相关文章

  1. JDK1.8新特性之Stream类初识

    JDK1.8新特性之Stream类初识 import java.util.Arrays; import java.util.List; import java.util.Optional; impor ...

  2. jdk1.8 新特性之Stream

    --------------------- 作者:码农农码一生 来源:CSDN 原文:https://blog.csdn.net/chenhao_c_h/article/details/8069128 ...

  3. JDK1.8新特性——Stream API

    JDK1.8新特性——Stream API 摘要:本文主要学习了JDK1.8的新特性中有关Stream API的使用. 部分内容来自以下博客: https://blog.csdn.net/icarus ...

  4. JDK1.8新特性(一) ----Lambda表达式、Stream API、函数式接口、方法引用

    jdk1.8新特性知识点: Lambda表达式 Stream API 函数式接口 方法引用和构造器调用 接口中的默认方法和静态方法 新时间日期API default   Lambda表达式     L ...

  5. JDK1.8 新特性

    jdk1.8新特性知识点: Lambda表达式 函数式接口 *方法引用和构造器调用 Stream API 接口中的默认方法和静态方法 新时间日期API https://blog.csdn.net/qq ...

  6. jdk1.8新特性应用之Iterable

    我们继续看lambda表达式的应用: public void urlExcuAspect(RpcController controller, Message request, RpcCallback ...

  7. JDK1.8新特性——Collector接口和Collectors工具类

    JDK1.8新特性——Collector接口和Collectors工具类 摘要:本文主要学习了在Java1.8中新增的Collector接口和Collectors工具类,以及使用它们在处理集合时的改进 ...

  8. JDK1.8新特性之(三)--函数式接口

    在上一篇文章中我们介绍了JDK1.8的新特性有以下几项. 1.Lambda表达式 2.方法引用 3.函数式接口 4.默认方法 5.Stream 6.Optional类 7.Nashorm javasc ...

  9. JDK1.8新特性之(一)--Lambda表达式

    近期由于新冠疫情的原因,不能出去游玩,只能在家呆着.于是闲来无事,开始阅读JDK1.8的源代码.在开始之前也查询了以下JDK1.8的新特性,有针对性的开始了这段旅程. 只看不操作,也是不能心领神会的. ...

  10. JDK1.8新特性之(二)--方法引用

    在上一篇文章中我们介绍了JDK1.8的新特性有以下几项. 1.Lambda表达式 2.方法引用 3.函数式接口 4.默认方法 5.Stream 6.Optional类 7.Nashorm javasc ...

随机推荐

  1. Mysql数据库(二)Mysql数据库管理

    一 .创建数据库 1.通过CREATE DATABASE db_library;创建名称为db_library的数据库. 2.通过CREATE SCHEMA db_library1;创建名称为db_l ...

  2. Java基础(八)对象包装器与自动装箱

    1.对象包装器 有时候,需要将int这样的基本类型转换为对象.所有的基本类型都有一个与之对应的类.通常,这些类被称为包装器(wrapper). 这些对象包装类分别是:Integer.Long.Floa ...

  3. NetworkManager网络通讯_networkReader/Writer(六)

    unet客户端和服务端进行消息发送时可以采用上一节中方法,也可以直接用networkReader/Writer类进行发送 (一)服务端/客户端注册消息 ; m_Server.RegisterHandl ...

  4. 《Effective Java》 读书笔记(七)消除过期的对象引用

    大概看了一遍这个小节,其实这种感觉体验最多的应该是C/C++程序,有多杀少个new就得有多个delete. 一直以为Java就不会存在这个问题,看来是我太年轻. 感觉<Effective Jav ...

  5. 聚类(一)——Kmeans

    Clustering 聚类K-means 聚类是机器学习和数据挖掘领域的主要研究方向之一,它是一种无监督学习算法,小编研究生时期的主要研究方向是“数据流自适应聚类算法”,所以对聚类算法有比较深刻的理解 ...

  6. Tomcat性能调优实战

    今日帮朋友做了tomcat性能调优的实际操作,心得记录一下. 服务器:Windows2017 配置:CPU 4 内存 8G Tomcat8.0+版本. 压力测试工具:apache-jmeter-4.0 ...

  7. Java基础系列5:深入理解Java异常体系

    该系列博文会告诉你如何从入门到进阶,一步步地学习Java基础知识,并上手进行实战,接着了解每个Java知识点背后的实现原理,更完整地了解整个Java技术体系,形成自己的知识框架. 前言: Java的基 ...

  8. UML简明使用

    1.继承 空心三角+实线 2.实现接口 空心三角+虚线 3.关联 箭头+实线 4.聚合 空心菱形+实线+箭头 5.组合 实心菱形+实线+箭头 6.依赖 虚线+箭头 7.关联.聚合.组合.依赖的区别 关 ...

  9. 使用Rider中搭建specflow+xunit+selenium对web页面进行自动化功能测试环境

    运行rider,创建测试解决方案,选择xunit,点击create创建 ​   导入包,由于本人使用chrome浏览器(需先下载好对应的浏览器驱动),所以导入了selenium.webdriver.c ...

  10. c/c++求最大公约数和最小公倍数

    最大公约数GCD(Greatest Common Divisor) 最常见的求两个数的最大公约数的算法是辗转相除法,也叫欧几里得算法 该算法的c++语言实现如下: #include<iostre ...