Stream

第一次看到Stream表达式就深深把我吸引,用它可以使你的代码更加整洁而且对集合的操作效率也会大大提高,如果你还没有用到java8的Stream特性,那就说明你确实out啦。

一、概述

1、什么是Stream

Stream是一种可供流式操作的数据视图有些类似数据库中视图的概念它不改变源数据集合如果对其进行改变的操作它会返回一个新的数据集合。

总的来讲它有三大特性:在之后我们会对照着详细说明

       1、stream不存储数据

       2、stream不改变源数据

       3、stream的延迟执行特性

2、Stream优点

  1. 代码简洁,函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环。

  2. 多核友好,Java函数式编程使得编写并行程序从未如此简单,你需要的全部就是调用一下parallel()方法。

3、Stream API常用方法

Stream操作分类
中间操作(Intermediate operations) 无状态(Stateless) unordered() filter() map() mapToInt() mapToLong() mapToDouble() flatMap() flatMapToInt() flatMapToLong() flatMapToDouble() peek()
有状态(Stateful) distinct() sorted() sorted() limit() skip()
结束操作(Terminal operations) 非短路操作 forEach() forEachOrdered() toArray() reduce() collect() max() min() count()
短路操作(short-circuiting) anyMatch() allMatch() noneMatch() findFirst() findAny()

Stream上的所有操作分为两类:中间操作和结束操作,中间操作只是一种标记,只有结束操作才会触发实际计算。

中间操作又可以分为无状态的和有状态的:

无状态中间操作是指元素的处理不受前面元素的影响,而有状态的中间操作必须等到所有元素处理之后才知道最终结果,比如排序是有状态操作,在读取所有元素之前并不能确定排序结果;

结束操作又可以分为短路操作和非短路操作

短路操作是指不用处理全部元素就可以返回结果,比如找到第一个满足条件的元素。之所以要进行如此精细的划分,是因为底层对每一种情况的处理方式不同。

常用中间件

filter:过滤流,过滤流中的元素,返回一个符合条件的Stream

map:转换流,将一种类型的流转换为另外一种流。(mapToInt、mapToLong、mapToDouble 返回int、long、double基本类型对应的Stream)

flatMap:简单的说,就是一个或多个流合并成一个新流。(flatMapToInt、flatMapToLong、flatMapToDouble 返回对应的IntStream、LongStream、DoubleStream流。)

distinct:返回去重的Stream。

sorted:返回一个排序的Stream。

peek:主要用来查看流中元素的数据状态。

limit:返回前n个元素数据组成的Stream。属于短路操作

skip:返回第n个元素后面数据组成的Stream。

结束操作

forEach: 循环操作Stream中数据。

toArray: 返回流中元素对应的数组对象。

reduce: 聚合操作,用来做统计。

collect: 聚合操作,封装目标数据。

min、max、count: 聚合操作,最小值,最大值,总数量。

anyMatch: 短路操作,有一个符合条件返回true。

allMatch: 所有数据都符合条件返回true。

noneMatch: 所有数据都不符合条件返回true。

findFirst: 短路操作,获取第一个元素。

findAny: 短路操作,获取任一元素。

forEachOrdered: 暗元素顺序执行循环操作。

二、各种案例说明

多举点例子,以后忘记了还可以来找自己的博客,哈哈。

首先写一个领域对象

public class Person {

    private Integer  id;

    private String name;

    private String sex;

    private Integer age;

    //提供get,set,和满参构造函数
}

1、map中间件相关例子

public class TestMap {

    public static void main(String[] args) {
List<Person> persionList = new ArrayList<Person>();
persionList.add(new Person(1,"张三","男",38));
persionList.add(new Person(2,"小小","女",2));
persionList.add(new Person(3,"李四","男",65));
persionList.add(new Person(4,"王五","女",20));
persionList.add(new Person(5,"赵六","男",38));
persionList.add(new Person(6,"大大","男",65)); //1、只取出该集合中所有姓名组成一个新集合
List<String> nameList=persionList.stream().map(Person::getName).collect(Collectors.toList());
System.out.println(nameList.toString()); //2、只取出该集合中所有id组成一个新集合
List<Integer> idList=persionList.stream().mapToInt(Person::getId).boxed().collect(Collectors.toList());
System.out.println(idList.toString()); //3、list转map,key值为id,value为Person对象
Map<Integer, Person> personmap = persionList.stream().collect(Collectors.toMap(Person::getId, person -> person));
System.out.println(personmap.toString()); //4、list转map,key值为id,value为name
Map<Integer, String> namemap = persionList.stream().collect(Collectors.toMap(Person::getId, Person::getName));
System.out.println(namemap.toString()); //5、进行map集合存放,key为age值 value为Person对象 它会把相同age的对象放到一个集合中
Map<Integer, List<Person>> ageMap = persionList.stream().collect(Collectors.groupingBy(Person::getAge));
System.out.println(ageMap.toString()); //6、获取最小年龄
Integer ageMin = persionList.stream().mapToInt(Person::getAge).min().getAsInt();
System.out.println("最小年龄为: "+ageMin); //7、获取最大年龄
Integer ageMax = persionList.stream().mapToInt(Person::getAge).max().getAsInt();
System.out.println("最大年龄为: "+ageMax); //8、集合年龄属性求和
Integer ageAmount = persionList.stream().mapToInt(Person::getAge).sum();
System.out.println("年龄总和为: "+ageAmount); }
}

运行结果:

是不是之前要好几层的for循环解决的问题,通过Stream只要一行代码就可以解决了。

这里要注意,如果你list转map的key如果不唯一,会报错,所以如果你不确定你的key是否唯一,可以改成如下:

 Map<Integer, String> map = persionList.stream().collect(
Collectors.toMap(Person::getAge, Person::getName, (key1, key2) -> key1)
);

2、filter相关例子

public class TestFilter {

    public static void main(String[] args) {
List<Person> persionList = new ArrayList<Person>();
persionList.add(new Person(1, "张三", "男", 8));
persionList.add(new Person(2, "小小", "女", 2));
persionList.add(new Person(3, "李四", "男", 25));
persionList.add(new Person(4, "王五", "女", 8));
persionList.add(new Person(5, "赵六", "女", 25));
persionList.add(new Person(6, "大大", "男", 65)); //1、查找年龄大于20岁的人数
long age=persionList.stream().filter(p->p.getAge()>20).count();
System.out.println(age); //2、查找年龄大于20岁,性别为男的人数
List<Person> ageList=persionList.stream().filter(p->p.getAge()>20).filter(p->"男".equals(p.getSex())).collect(Collectors.toList());
System.out.println(ageList.size()); }
/*
*运行结果:
* 3
* 2
*/
}

3、sorted相关例子

对于数组举例

public class TestSort {

    String[] arr1 = {"abc","a","bc","abcd"};

    /**
* 按照字符长度排序
*/
@Test
public void testSorted1_(){
Arrays.stream(arr1).sorted(Comparator.comparing(String::length)).forEach(System.out::println);
//输出:a、bc、abc、abcd
} /**
* 倒序
* reversed(),java8泛型推导的问题,所以如果comparing里面是非方法引用的lambda表达式就没办法直接使用reversed()
* Comparator.reverseOrder():也是用于翻转顺序,用于比较对象(Stream里面的类型必须是可比较的)
* Comparator. naturalOrder():返回一个自然排序比较器,用于比较对象(Stream里面的类型必须是可比较的)
*/
@Test
public void testSorted2_(){
Arrays.stream(arr1).sorted(Comparator.comparing(String::length).reversed()).forEach(System.out::println);
//输出:abcd、abc、bc、a
Arrays.stream(arr1).sorted(Comparator.reverseOrder()).forEach(System.out::println);
//输出:bc、abcd、abc、a
Arrays.stream(arr1).sorted(Comparator.naturalOrder()).forEach(System.out::println);
//输出:a、abc、abcd、bc
} /**
* 先按照首字母排序
* 之后按照String的长度排序
*/
@Test
public void testSorted3_(){
Arrays.stream(arr1).sorted(Comparator.comparing(this::com1).thenComparing(String::length)).forEach(System.out::println);
}
//输出:a、abc、abcd、bc
public char com1(String x){
return x.charAt(0);
}
}

对于集合举例

public class TestSort {

    public static void main(String[] args) {
List<Person> persionList = new ArrayList<Person>();
persionList.add(new Person(1, "张三", "男", 8));
persionList.add(new Person(2, "小小", "女", 2));
persionList.add(new Person(3, "李四", "男", 25));
persionList.add(new Person(4, "王五", "女", 8));
persionList.add(new Person(5, "赵六", "女", 25));
persionList.add(new Person(6, "大大", "男", 65)); //1、找到年龄最小的岁数
Collections.sort(persionList, (x, y) -> x.getAge().compareTo(y.getAge()));
Integer age = persionList.get(0).getAge();
System.out.println("年龄最小的有:" + age);
//输出:年龄最小的有:2 //2、找到年龄最小的姓名
String name = persionList.stream()
.sorted(Comparator.comparingInt(x -> x.getAge()))
.findFirst()
.get().getName();
System.out.println("年龄最小的姓名:" + name);
//输出:年龄最小的姓名:小小
}
}

其它的就不具体写了。以后遇到特殊的再往里面补充。

参考

1、跟上 Java 8 – Stream API 快速入门

2、java8之stream

3、[Java进阶篇][函数式编程][Java 8+ Stream API]

4、深入理解Java Stream流水线

想太多,做太少,中间的落差就是烦恼。想没有烦恼,要么别想,要么多做。中校【10】

java代码之美(2)---Java8 Stream的更多相关文章

  1. java代码之美(16) ---Java8 Optional

    Java8 Optional 一句话介绍Optional类:使用JDK8的Optional类来防止NullPointerException(空指针异常)问题. 一.前言 在我们开放过程中,碰到的异常中 ...

  2. java代码(2)---Java8 Stream

    stream Java8新特性Stream流,那Stream表达式到底是什么呢,为什么可以使你的代码更加整洁而且对集合的操作效率也会大大提高? 一.概述 1.什么是Stream Stream是一种可供 ...

  3. java代码之美(17) ---Java8 LocalDateTime

    Java8 LocalDateTime 在java8之前我们在处理时间的时候都是用的Date,但它其实有很明显的缺点. 1.我们也会对日期做一些操作,比如加几天.加几分,当月的最后一天等等.有些计算实 ...

  4. java代码(15) ---java8 Function 、Consumer 、Supplier

    Java8 Function.Consumer.Supplier 有关JDK8新特性之前还有三篇博客: 1,java代码(1)---Java8 Lambda 2,java代码(2)---Java8 S ...

  5. java代码之美(14)---Java8 函数式接口

    Java8 函数式接口 之前写了有关JDK8的Lambda表达式:java代码之美(1)---Java8 Lambda 函数式接口可以理解就是为Lambda服务的,它们组合在一起可以让你的代码看去更加 ...

  6. java代码之美(15)---Java8 Function、Consumer、Supplier

    Java8 Function.Consumer.Supplier 有关JDK8新特性之前写了三篇博客: 1.java代码之美(1)---Java8 Lambda 2.java代码之美(2)---Jav ...

  7. java代码(14) --Java8函数式接口

    Java8函数式接口 之前有关JDK8的Lambda表达式 Java代码(1)--Java8 Lambda 函数式接口可以理解就是为Lambda服务的,它们组合在一起可以让你的代码看去更加简洁 一.概 ...

  8. java代码之美(11)---java代码的优化

    java代码的优化 随着自己做开发时间的增长,越来越理解雷布斯说的: 敲代码要像写诗一样美.也能理解有一次面试官问我你对代码有洁癖吗? 一段好的代码会让人看就像诗一样,也像一个干净房间会让人看去很舒服 ...

  9. java代码之美(3)---guava 复写Object常用方法

    guava 复写Object常用方法 Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,这个库提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和验证的实用方 ...

随机推荐

  1. SourceTree推送分支时遇到ArgumentException encountered错误的解决办法

    下载并安装: https://github.com/Microsoft/Git-Credential-Manager-for-Windows/releases/tag/v1.17.2 然后重新推送即可 ...

  2. 浅谈Java线程安全

    浅谈Java线程安全 - - 2019-04-25    17:37:28 线程安全 Java中的线程安全 按照线程安全的安全程序由强至弱来排序,我们可以将Java语言中各种操作共享的数据分为以下五类 ...

  3. idea:程序包javax.servlet.http不存在

    原因:IntelliJ IDEA 缺少servlet-api.jar 这个.jar包 解决方法:由于tomcat的lib自带servlet-api.jar,可以直接导入tomcat中的jar包 1.F ...

  4. python kafka权限校验client.id

    kafka集群有权限校验,在连接时需要加入client.id.但pykafka不能配置该选项.搜索了一下,需要使用confluent-kafka 链接: https://blog.csdn.net/l ...

  5. [sublime] 利用sublime搭建C/C++编译器

    gcc/g++配置 先去下载TDM-GCC安装包,这里附下载地址(可能会有弹出界面,不用管他). 现在c盘中建立文件夹 g++,然后以管理员运行,点击Create傻瓜式安装, 这里要改一下安装路径,保 ...

  6. js基础知识易错点(一)

    最近替另一个项目招人,要求基础知识好,随便问了一些基础题,发现了一些易错的点,总结一下. 1.判断一个空数组 var arr = []; 1)JSON.stringify(arr) == " ...

  7. FoxMail邮件设置

    最近部门变动,要求所有的沟通及交流都需要用企业邮箱,对于一般不喜欢看邮箱的我,经常会错过很多邮件.为了统一接收企业邮件及个人邮件,开始使用Foxmail(以前不喜欢整这些东西).下面分享一下FoxMa ...

  8. vue-cli 2篇官方文档记录收藏

    https://cli.vuejs.org/guide/ http://vuejs-templates.github.io/webpack/

  9. Javascript 获取文档元素

    一.getElementById() 参数:id 属性,必须唯一. 返回:元素本身.若 id 不唯一,则返回第一个匹配的元素. 定义的位置:仅 document(即:除 document 之外的元素调 ...

  10. NOIP2013提高组 T2 火柴排队

    一开始看也想不到这居然要用到逆序对,归并排序. 先来看看题目: 涵涵有两盒火柴,每盒装有 n 根火柴,每根火柴都有一个高度. 现在将每盒中的火柴各自排成一列, 同一列火柴的高度互不相同, 两列火柴之间 ...