stream


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

一、概述

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));
//只取出该集合所有姓名组成一个新集合
List<String> nameList = persionList.stream().map(Person::getName).collect(Collectors.toList());
System.out.println(nameList.toString());
//只取出该集合中所有id组成一个新的集合
List<Integer> idList = persionList.stream().mapToInt(Person::getId).boxed().collect(Collectors.toList());
System.out.println(idList.toString());
//list转map key值为id,value为person对象
Map<Integer, Person> personMap = persionList.stream().collect(Collectors.toMap(Person::getId, person -> person));
System.out.println(personMap.toString());
//list转map,key值为id,value为name
Map<String, Integer> nameMap = persionList.stream().collect(Collectors.toMap(Person::getName, Person::getAge));
System.out.println(nameMap.toString()); //进行map集合存放,key为age值,value为person对象,它会把相同age的对象放到一个集合中
Map<Integer, List<Person>> ageMap = persionList.stream().collect(Collectors.groupingBy(Person::getAge));
System.out.println(ageMap.toString()); //获取最小年龄
Integer ageMin = persionList.stream().mapToInt(Person::getAge).min().getAsInt();
System.out.println("最小年龄"+ageMin);
//获取最大年龄
Integer ageMax = persionList.stream().mapToInt(Person::getAge).max().getAsInt();
System.out.println("最大年龄"+ageMax); //年龄属性求和
Integer sum = persionList.stream().mapToInt(Person::getAge).sum();
System.out.println("年龄总和为:"+sum);

运行结果:

是不是之前要好几层的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);
//输出:年龄最小的姓名:小小
}
}

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

  1. java List递归排序,传统方式和java8 Stream优化递归,无序的列表按照父级关系进行排序(两种排序类型)

    当有一个List列表是无序的,List中的数据有parentid进行关联,通过java排序成两种排序类型: 所用的测试列表最顶级无parentid,若为特殊值,修改下判断方法即可. 第一种排序:按照树 ...

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

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

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

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

  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】关于Java8 parallelStream并发安全的思考

    背景 Java8的stream接口极大地减少了for循环写法的复杂性,stream提供了map/reduce/collect等一系列聚合接口,还支持并发操作:parallelStream. 在爬虫开发 ...

  7. java 代码

    java 里的 pandas tablesaw DataFrame 再有就是 spark 了 java 代码规范 Java8特性详解 lambda表达式 Stream Sonar 规则检测 sprin ...

  8. java8 Stream的实现原理 (从零开始实现一个stream流)

    1.Stream 流的介绍 1.1 java8 stream介绍 java8新增了stream流的特性,能够让用户以函数式的方式.更为简单的操纵集合等数据结构,并实现了用户无感知的并行计算. 1.2  ...

  9. Java 8系列之Stream的基本语法详解

    本文转至:https://blog.csdn.net/io_field/article/details/54971761 Stream系列: Java 8系列之Stream的基本语法详解 Java 8 ...

  10. 使用yaml+groovy实现Java代码可配置化

    背景与目标 在使用函数接口和枚举实现配置式编程(Java与Scala实现),使用了函数接口和枚举实现了配置式编程.读者可先阅读此文,再来阅读本文. 有时,需要将一些业务逻辑,使用配置化的方式抽离出来, ...

随机推荐

  1. jbpm4.4 timer的使用

    今天学习了jbpm4 的timer使用,一直测试都不成功:配置如下: <?xml version="1.0" encoding="UTF-8"?> ...

  2. 基于 abp vNext 和 .NET Core 开发博客项目 - 完善与美化,Swagger登场

    上一篇文章(https://www.cnblogs.com/meowv/p/12896898.html)已经成功将博客项目跑起来了,那么本篇主要是将之前遗留的问题解决,现在的代码看起来可能还是比较混乱 ...

  3. Spring AOP实现接口验签

    因项目需要与外部对接,为保证接口的安全性需要使用aop进行方法的验签; 在调用方法的时候,校验外部传入的参数进行验证, 验证通过就执行被调用的方法,验证失败返回错误信息: 不是所有的方法都需要进行验签 ...

  4. 「雕爷学编程」Arduino动手做(31)——ISD1820语音模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  5. webpack指南(三)缓存

    缓存 把 /dist 目录中的内容部署到服务器上,客户端(通常是浏览器)就能够访问网站此服务器的网站及其资源.而通过网络获取资源是比较耗时的,这就是为什么浏览器要使用缓存这种技术.可以通过命中缓存,以 ...

  6. vue与其他框架对比

    https://cn.vuejs.org/v2/guide/comparison.html 1. vue 框架的特点? MVVM框架模式 轻量级,灵活,容易上手 数据驱动 组件化(单文件组件) 插件化 ...

  7. redis订阅发布功能

    发布订阅 案例测试

  8. Maven整合JaCoCo和Sonar,看看你的测试写够了没

    1 简介 单元测试是保证代码质量的重要一环,而如何衡量单元测试写得好不好呢?覆盖率(Coverage)是一个重要指标.而JaCoCo则是专门为Java提供的用于检测测试覆盖率的工具,英文全称为Java ...

  9. C# winform DataGridView 绑定数据的的几种方法

    1.用DataSet和DataTable为DataGridView提供数据源 String strConn = "Data Source=.;Initial Catalog=His;User ...

  10. 08-Python之路---初识函数

    Python之路---初识函数️ 程序员三大美德: 懒惰 因为一直致力于减少工作的总工作量. 缺乏耐性 因为一旦让你去做本该计算机完成的事,你将会怒不可遏. 傲慢 因为被荣誉感冲晕头的你会把程序写得让 ...