Java8中有两大最为重要得改变,其一时Lambda表达式,另外就是 Stream API了。在前面几篇中简单学习了Lambda表达式得语法,以及函数式接口。本文就来简单学习一下Stream API(java.util.stream.*)。

  Stream 是 Java8中处理集合得关键抽象概念,他可以指定你希望对集合进行得操作,可以执行非常复杂得查找、过滤和映射数据等操作。使用Stream API对集合数据进行操作,就类似使用SQL执行得数据库查询。也可以使用S他ream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用得处理数据得方式。

  在Stream操作过程中,可以对数据流做过滤,排序,切片等操作,但是操作之后会产生一个新的流,而数据源则不会发生改变。

一、什么是 Stream

  Stream是数据渠道,用于操作数据源(集合,数组等)所生成得元素序列。而集合讲得是数据,流讲得是计算。

  注意:

    ①. Stream 自己不会存储元素。

    ②. Stream 不会改变源对象。相反,它会返回一个持有结果得新Stream

    ③. Stream 操作时延迟执行得,这意味着它们会等到需要结果时才执行。(延迟加载)

二、Stream 操作的三个步骤

  1). 创建 Stream

    一个数据源(集合,数组),获取一个流。

  2). 中间操作

    一个中间操作链,对数据源的数据进行处理。

  3). 终止操作

    一个终止操作,执行中间操作链,并产生结果。

三、创建Stream 的四种方式

  1). 通过Collection得Stream()方法(串行流)或者 parallelStream()方法(并行流)创建Stream。

   /**
* 创建 Stream的四种方式
* 1.通过Collection得Stream()方法(串行流)
或者 parallelStream()方法(并行流)创建Stream
*/
@Test
public void test1 () { //1. 通过Collection得Stream()方法(串行流)
//或者 parallelStream()方法(并行流)创建Stream
List<String> list = new ArrayList<String>();
Stream<String> stream1 = list.stream(); Stream<String> stream2 = list.parallelStream(); }

  2).通过Arrays中得静态方法stream()获取数组流

     /**
* 创建 Stream的四种方式
* 2. 通过Arrays中得静态方法stream()获取数组流
*/
@Test
public void test2 () { //2. 通过Arrays中得静态方法stream()获取数组流
IntStream stream = Arrays.stream(new int[]{3,5}); }

  3). 通过Stream类中得 of()静态方法获取流

     /**
* 创建 Stream的四种方式
* 3. 通过Stream类中得 of()静态方法获取流
*/
@Test
public void test3 () { //3. 通过Stream类中得 of()静态方法获取流
Stream<String> stream = Stream.of("4645", "huinnj"); }

  4). 创建无限流(迭代、生成)

 /**
* 创建 Stream的四种方式
* 4. 创建无限流(迭代、生成)
*/
@Test
public void test4 () { //4. 创建无限流
//迭代(需要传入一个种子,也就是起始值,然后传入一个一元操作)
Stream<Integer> stream1 = Stream.iterate(2, (x) -> x * 2); //生成(无限产生对象)
Stream<Double> stream2 = Stream.generate(() -> Math.random()); }

四、Stream 中间操作

  多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何得处理!而终止操作时一次性全部处理,称为‘延迟加载’

  1). 筛选与切片

    ①. filter —— 接收Lambda ,从流中排除某些元素。

     /**
* 筛选与切片
* filter —— 接收Lambda ,从流中排除某些元素。
*
*/
@Test
public void test5 () {
//内部迭代:在此过程中没有进行过迭代,由Stream api进行迭代
//中间操作:不会执行任何操作
Stream<Person> stream = list.stream().filter((e) -> {
System.out.println("Stream API 中间操作");
return e.getAge() > 30;
}); //终止操作:只有执行终止操作才会执行全部。即:延迟加载
stream.forEach(System.out :: println); }

  执行上面方法,得到下面结果。

Person [name=张三, sex=男, age=76]
Stream API 中间操作
Stream API 中间操作
Person [name=王五, sex=男, age=35]
Stream API 中间操作
Stream API 中间操作
Person [name=钱七, sex=男, age=56]
Stream API 中间操作
Person [name=翠花, sex=女, age=34]

  我们,在执行终止语句之后,一边迭代,一边打印,而我们并没有去迭代上面集合,其实这是内部迭代,由Stream API 完成。

  下面我们来看看外部迭代,也就是我们人为得迭代。

   @Test
public void test6 () {
//外部迭代
Iterator<Person> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
} }

    ②. limit —— 截断流,使其元素不超过给定数量。

     /**
* limit —— 截断流,使其元素不超过给定数量。
*/
@Test
public void test7 () {
//过滤之后取2个值
list.stream().filter((e) -> e.getAge() >30 ).
limit(2).forEach(System.out :: println); }

  在这里,我们可以配合其他得中间操作,并截断流,使我们可以取得相应个数得元素。而且在上面计算中,只要发现有2条符合条件得元素,则不会继续往下迭代数据,可以提高效率。

  2). 跳过元素

    skip(n),返回一个扔掉了前n个元素的流。若流中元素不足n个,则返回一个空,与limit(n)互补。

     /**
* skip(n)—— 跳过元素,返回一个扔掉了前n个元素的流。
* 若流中元素不足n个,则返回一个空,与limit(n)互补。
*/
@Test
public void test8 () {
//跳过前2个值
list.stream().skip(2).forEach(System.out :: println); }

  3).  筛选

    distinct 通过流所生成元素的hashCode()和equals()去除重复元素

     /**
* distinct —— 筛选,通过流所生成元素的hashCode()和equals()去除重复元素
*/
@Test
public void test9 () { list.stream().distinct().forEach(System.out :: println); }

  注意:distinct 需要实体中重写hashCode()和 equals()方法才可以使用

  4). 映射

    ① . map ,将元素转换成其他形式或者提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

     /**
* map —— 映射 ,将元素转换成其他形式或者提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
*/
@Test
public void test10 () {
//将流中每一个元素都映射到map的函数中,每个元素执行这个函数,再返回
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
list.stream().map((e) -> e.toUpperCase()).forEach(System.out::printf); //获取Person中的每一个人得名字name,再返回一个集合
List<String> names = this.list.stream().map(Person :: getName).
collect(Collectors.toList());
}

    ② . flatMap —— 接收一个函数作为参数,将流中的每个值都换成一个流,然后把所有流连接成一个流

     /**
* flatMap —— 接收一个函数作为参数,将流中的每个值都换成一个流,然后把所有流连接成一个流
*/
@Test
public void test11 () {
StreamAPI_Test s = new StreamAPI_Test();
List<String> list = Arrays.asList("aaa", "bbb", "ccc", "ddd");
list.stream().flatMap((e) -> s.filterCharacter(e)).forEach(System.out::println); //如果使用map则需要这样写
list.stream().map((e) -> s.filterCharacter(e)).forEach((e) -> {
e.forEach(System.out::println);
});
} /**
* 将一个字符串转换为流
* @param str
* @return
*/
public Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}

  其实map方法就相当于Collaction的add方法,如果add的是个集合得话就会变成二维数组,而flatMap 的话就相当于Collaction的addAll方法,参数如果是集合得话,只是将2个集合合并,而不是变成二维数组。

  5). 排序

     sorted有两种方法,一种是不传任何参数,叫自然排序,还有一种需要传Comparator 接口参数,叫做定制排序。

     /**
* sorted有两种方法,一种是不传任何参数,叫自然排序,还有一种需要传Comparator 接口参数,叫做定制排序。
*/
@Test
public void test12 () {
// 自然排序
List<Person> persons = list.stream().sorted().collect(Collectors.toList()); //定制排序
List<Person> persons1 = list.stream().sorted((e1, e2) -> {
if (e1.getAge() == e2.getAge()) {
return 0;
} else if (e1.getAge() > e2.getAge()) {
return 1;
} else {
return -1;
}
}).collect(Collectors.toList());
}

五、Stream 终止操作

  1). 查找与匹配

    首先我们先创建一个集合。

         List<Person> persons = Arrays.asList(
new Person("张三", "男", 76, Status.FREE),
new Person("李四", "女", 12, Status.BUSY),
new Person("王五", "男", 35, Status.BUSY),
new Person("赵六", "男", 3, Status.FREE),
new Person("钱七", "男", 56, Status.BUSY),
new Person("翠花", "女", 34, Status.VOCATION),
new Person("翠花", "女", 34, Status.FREE),
new Person("翠花", "女", 34, Status.VOCATION)
);

    ①. allMatch —— 检查是否匹配所有元素。

     /**
* allMatch —— 检查是否匹配所有元素。
* 判断所有状态是否都是FREE
*/
@Test
public void test13 () {
boolean b = persons.stream().allMatch((e) -> Status.FREE.equals(e.getStatus()));
System.out.println(b);
}

    ②. anyMatch —— 检查是否至少匹配所有元素。

     /**
* anyMatch —— 检查是否至少匹配所有元素。
* 判断是否有一个是FREE
*/
@Test
public void test14 () {
boolean b = persons.stream().anyMatch((e) -> Status.FREE.equals(e.getStatus()));
System.out.println(b);
}

    ③. noneMatch —— 检查是否没有匹配所有元素。

     /**
* noneMatch —— 检查是否没有匹配所有元素。
* 判断是否没有FREE
*/
@Test
public void test15 () {
boolean b = persons.stream().noneMatch((e) -> Status.FREE.equals(e.getStatus()));
System.out.println(b);
}

    ④. findFirst —— 返回第一个元素。

     /**
* findFirst —— 返回第一个元素。
*
*/
@Test
public void test16 () {
Optional<Person> person = persons.stream().findFirst();
System.out.println(person); person.orElse(new Person("王五", "男", 35, Status.BUSY));
}

  注意:上面findFirst 返回的是一个Optional的对像,他将我们的Person封装了一层,这是为了避免空指针。而且这个对象为我们提供了一个orElse方法,就是当我们得到的这个对象为空时,我们可以传入一个新得对象去替代它。

    ⑤. findAny —— 返回当前流中任意元素。

     /**
* findAny —— 返回当前流中任意元素。
*/
@Test
public void test17 () {
Optional<Person> person = persons.stream().findAny();
System.out.println(person); person.orElse(new Person("王五", "男", 35, Status.BUSY));
}

    ⑥. count —— 返回流中元素总个数。

     /**
* count —— 返回流中元素总个数。
*/
@Test
public void test18 () {
long count = persons.stream().count();
System.out.println(count); }

    ⑦. max —— 返回流中最大值。

     /**
* max —— 返回流中最大值。
*/
@Test
public void test18 () {
Optional<Person> person = persons.stream().max((e1, e2) -> Double.compare(e1.getAge(), e2.getAge()));
System.out.println(person); }

    ⑧. min —— 返回流中最小值。

     /**
* min —— 返回流中最小值。
*/
@Test
public void test20 () {
Optional<Person> person = persons.stream().min((e1, e2) -> Double.compare(e1.getAge(), e2.getAge()));
System.out.println(person); }

  2). 归约(可以将流中元素反复结合在一起,得到一个值)

    ①. reduce(T identitty,BinaryOperator)首先,需要传一个起始值,然后,传入的是一个二元运算。

     /**
* reduce(T identitty,BinaryOperator)首先,需要传一个起始值,然后,传入的是一个二元运算。
*/
@Test
public void test21 () {
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream().reduce(0, (x, y) -> x + y);
}

    ②. reduce(BinaryOperator)此方法相对于上面方法来说,没有起始值,则有可能结果为空,所以返回的值会被封装到Optional中。

     /**
* reduce(BinaryOperator)此方法相对于上面方法来说,没有起始值,则有可能结果为空,所以返回的值会被封装到Optional中
*/
@Test
public void test22 () {
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Optional<Integer> sum = list.stream().reduce(Integer :: sum);
}

  备注:map和reduce的连接通常称为map-reduce模式,因Google用它来进行网络搜索而出名。

  3). 收集collect(将流转换为其他形式。接收一个Collector接口得实现,用于给其他Stream中元素做汇总的方法)

    Collector接口中方法得实现决定了如何对流执行收集操作(如收集到List,Set,Map)。但是Collectors实用类提供了很多静态方法,可以方便地创建常见得收集器实例。

    ①. Collectors.toList() 将流转换成List

     /**
* Collectors.toList() 将流转换成List
*/
@Test
public void test23() {
List<String> names = this.list.stream().map(Person :: getName).collect(Collectors.toList());
}

    ②. Collectors.toSet()将流转换为Set

     /**
* Collectors.toSet() 将流转换成Set
*/
@Test
public void test24() {
Set<String> names = this.list.stream().map(Person :: getName).collect(Collectors.toSet());
}

    ③. Collectors.toCollection()将流转换为其他类型的集合

     /**
* Collectors.toCollection()将流转换为其他类型的集合
*/
@Test
public void test25() {
LinkedList<String> names = this.list.stream().map(Person :: getName).collect(Collectors.toCollection(LinkedList :: new));
}

    

    ④. Collectors.counting()  元素个数

     /**
* Collectors.counting() 总数
*/
@Test
public void test26() {
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Long count = list.stream().collect(Collectors.counting());
}

    ⑤. Collectors.averagingDouble()、Collectors.averagingDouble()、Collectors.averagingLong() 平均数,这三个方法都可以求平均数,不同之处在于传入得参数类型不同,返回值都为Double

     /**
* Collectors.averagingInt() 、
* Collectors.averagingDouble()、
* Collectors.averagingLong() 平均数,
* 者三个方法都可以求平均数,不同之处在于传入得参数类型不同,
* 返回值都为Double
*/
@Test
public void test27() {
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Double avg = list.stream().collect(Collectors.averagingInt((x) -> x));
}

    ⑥. Collectors.summingDouble()、Collectors.summingDouble()、Collectors.summingLong() 求和,不同之处在于传入得参数类型不同,返回值为Integer, Double, Long

     /**
* Collectors.summingInt() 、
* Collectors.summingDouble()、
* Collectors.summingLong() 求和,
* 者三个方法都可以求总数,不同之处在于传入得参数类型不同,
* 返回值为Integer, Double, Long
*/
@Test
public void test28() {
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Integer sum = list.stream().collect(Collectors.summingInt((x) -> x));
}

  ⑦. Collectors.maxBy() 求最大值

     /**
* Collectors.maxBy() 求最大值
*/
@Test
public void test29() {
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Optional<Integer> max = list.stream().collect(Collectors.maxBy((x, y) ->Integer.compare(x, y)));
}

  ⑧. Collectors.minBy() 求最小值

/**
* Collectors.minBy() 求最小值
*/
@Test
public void test29() {
List<Integer> list = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
Optional<Integer> min = list.stream().collect(Collectors.minBy((x, y) ->Integer.compare(x, y)));
}

  ⑨. Collectors.groupingBy()分组 ,返回一个map

     /**
* Collectors.groupingBy()分组 ,返回一个map
*/
@Test
public void test30() {
Map<String, List<Person>> personMap = list.stream().collect(Collectors.groupingBy(Person :: getSex));
}

      Collectors.groupingBy()还可以实现多级分组

     /**
* Collectors.groupingBy()多级分组 ,返回一个map
*/
@Test
public void test31() {
Map<String, Map<Status, List<Person>>> personMap = list.stream().collect(Collectors.groupingBy(Person :: getSex, Collectors.groupingBy(Person :: getStatus)));
}

  ⑩. Collectors.partitioningBy() 分区,参数中传一个函数,返回true,和false 分成两个区

     /**
* Collectors.partitioningBy() 分区,参数中传一个函数,返回true,和false 分成两个区
*/
@Test
public void test32() {
Map<Boolean, List<Person>> personMap = list.stream().collect(Collectors.partitioningBy((x) -> x.getAge() > 30));
}

  上面就是Stream的一些基本操作,只要勤加练习就可以灵活使用,而且效率大大提高。

java8新特性——Stream API的更多相关文章

  1. Java8 新特性 Stream() API

    新特性里面为什么要加入流Steam() 集合是Java中使用最多的API,几乎每一个Java程序都会制造和处理集合.集合对于很多程序都是必须的,但是如果一个集合进行,分组,排序,筛选,过滤...这些操 ...

  2. Java8新特性 - Stream API

    Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找.过滤和映射数据等操作.使用Stream API对集合进行操作,就类似与使用SQL执行的数据库 ...

  3. Java8 新特性 Stream Api 之集合遍历

    前言 随着java版本的不断更新迭代,java开发也可以变得甜甜的,最新版本都到java11了,但是后面版本也是不在提供商用支持,需要收费,但是java8 依然是持续免费更新使用的,后面版本也更新很快 ...

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

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

  5. Java8 新特性 Stream 非短路终端操作

    非短路终端操作 Java8 新特性 Stream 练习实例 非短路终端操作,就是所有的元素都遍厉完,直到最后才结束.用来收集成自己想要的数据. 方法有: 遍厉 forEach 归约 reduce 最大 ...

  6. Java8 新特性 Stream 短路终端操作

    短路终端操作 Java8 新特性 Stream 练习实例 传入一个谓词,返回传为boolean,如果符合条件,则直接结束流. 匹配所有 allMatch 任意匹配 anymMatch 不匹配 none ...

  7. Java8 新特性 Stream 无状态中间操作

    无状态中间操作 Java8 新特性 Stream 练习实例 中间无状态操作,可以在单个对单个的数据进行处理.比如:filter(过滤)一个元素的时候,也可以判断,比如map(映射)... 过滤 fil ...

  8. Java8 新特性 Stream 练习实例

    练习实例 配合Java8 新特性 Steam() API 使用 //没有写get set 构造方法 public class Sku { private Integer skuId; private ...

  9. 这可能是史上最好的 Java8 新特性 Stream 流教程

    本文翻译自 https://winterbe.com/posts/2014/07/31/java8-stream-tutorial-examples/ 作者: @Winterbe 欢迎关注个人微信公众 ...

随机推荐

  1. Linux下常用命令汇总

    1.ls 1.1 统计文件夹下文件数量 ls -l | wc -l 1.2 将文件夹下文件名输出到文件 ls -l > list.txt -F | grep - v[/$] 2.find 2.1 ...

  2. [转]C语言指针详解(经典,非常详细)

    博文地址:https://blog.csdn.net/constantin_/article/details/79575638 写得很好啊! 这里写一下笔记好了 int p; //这是一个普通的整型变 ...

  3. js写弹窗

    1.先来看弹窗的模样 点击“弹出窗口”后会弹出下面窗口 2.下面是实现弹出窗口的代码,其中引入的jquery一般自己有,没有的话可以从网上下载.tanchuang.js和tanchuang.css写在 ...

  4. 谈一谈我所了解的https

    一. http协议 首先我并不会很深入的去探讨这个东西,即使我曾经花了很长的时间去研究这个东西.主要是我考虑到1. 自己没有系统的去学习这一块的知识,讲解的会比较的肤浅.2. 就算是懂这个东西也不一定 ...

  5. 爬虫--Scrapy之Downloader Middleware

    下载器中间件(Downloader Middleware) 下载器中间件是介于Scrapy的request/response处理的钩子框架. 是用于全局修改Scrapy request和respons ...

  6. 搭建自己的PHP框架心得——转载

    原文:http://www.cnblogs.com/zhenbianshu/p/5331165.html 前言 说到写PHP的MVC框架,大家想到的第一个词--“造轮子”,是的,一个还没有深厚功力的程 ...

  7. Mac 下安装 ruby 环境解决 brew 安装 yarn 问题

    在brew安装yarn提示 ruby的版本过低.在网上搜了一下发现 1. mac下自带的ruby 在 system 目录下 2. 其实可以用brew安装一个ruby brew install ruby ...

  8. java中String的==和equals的区别

    首先看代码1: public static void main(String[] args) { List<String> list=new ArrayList<String> ...

  9. 函数参数 f_arg, *args, **kwargs

    当需要给函数传参时,可以通过运用不同的形参来传递,达到参数不同的使用目的. 简单来说:f_arg就是传递的第一个参数,类似于C++中的普通参数: *args 传递的是一个参数的list: **kwar ...

  10. ie7浏览器兼容问题

    win10 下如何调试Ie 网上有很多ie的测试工具,包括ms自己出的有,但是如果是win10系统,压根不需要这些玩意. win10 浏览器edge虽然是重写过的,但是win10并没有完全抛弃ie,可 ...