流(Stream)

流是java 8 中新引入的特性,用来处理集合中的数据,Stream 是一个来自数据源的元素队列并支持聚合操作。

  • Java 中 Stream 不会存储元素。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

Stream操作还有几个特征:

  • 只遍历一次。我们可以把流想象成一条流水线,流水线的源头是我们的数据源(一个集合),数据源中的元素依次被输送到流水线上,我们可以在流水线上对元素进行各种操作。一旦元素走到了流水线的另一头,那么这些元素就被“消费掉了”,我们无法再对这个流进行操作。当然,我们可以从数据源那里再获得一个新的流重新遍历一遍。
  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

流的使用

流的使用过程有三步:

  • 获取流;
  • 中间操作,得到一个新的流;
  • 最终操作,获取结果。

获取流

流有两种:

  • stream() : 创建串行流。
  • parallelStream() : 创建并行流。

并行流的特点就是将一个大任务切分成多个小任务,无序一起执行,当然如果我们需要顺序输出的话可以使用forEachOrdered,速度会比串行流快一些。它通过默认的ForkJoinPool,可能提高你的多线程任务的速度。

从集合获取流
List<FarmEntity> list = service.getBySql(sql1);
Stream<FarmEntity> stream = list.stream();
从数组获取流
String[] arrays = {"你", "我", "她"};
Stream<String> stream = Arrays.stream(arrays);
从值获取流
Stream<String> stream = Stream.of("你", "我", "她");
从文件获取流
try {
Stream<String> file =Files.lines(Paths.get("D:\\zhangkai\\WorkSpace\\Git\\hexo\\_config.yml"));
file.forEach(System.out::println);
} catch (Exception e) { }

使用NIO获取流,可以打印出文本文件的内容。

流的操作

filter 过滤

filter函数接收一个Lambda表达式作为参数,该表达式返回boolean,在执行过程中,流将元素逐一输送给filter,并筛选出执行结果为true的元素。

String[] strings = {"珊瑚", "阳光", "细腻", "冷暖", "阳光"};
Arrays.stream(strings).filter(n -> n.startsWith("冷")).forEach(System.out::print);
distinct 去重
Arrays.stream(strings).distinct().forEach(System.out::print);
limit 截取

截取前面两个单位:

Arrays.stream(strings).limit(2).forEach(System.out::print);
skip 跳过

和上面的limit 相反,跳过前面两个


map 映射

map 方法用于映射每个元素到对应的结果。

给每个词语后面加个 “兮”

        Arrays.stream(strings).map(s -> s + "兮").forEach(System.out::println);

输出:

珊瑚兮
阳光兮
细腻兮
冷暖兮
阳光兮
sorted 排序
//Arrays.stream(strings).sorted((x, y) -> x.compareTo(y)).forEach(System.out::println);
Arrays.stream(strings).sorted(String::compareTo).forEach(System.out::println);

输出:

冷暖
珊瑚
细腻
阳光
阳光

java8 以前排序:

 // Before Java 8 sorted
System.out.println("java8以前排序:");
List<String> list1 = Arrays.asList(strings);
list1.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
System.out.printf("java8 以前的排序:%s%n", list1);

输出:

java8以前排序:
java8 以前的排序:[冷暖, 珊瑚, 细腻, 阳光, 阳光]

HashMap根据value值排序key:

Map<String, Integer> map = new HashMap<>();
map.put("spring", 1);
map.put("summer", 2);
map.put("autumn", 3);
map.put("winter", 4);
map.entrySet().stream()
.sorted((a, b) -> b.getValue().compareTo(a.getValue()))
.forEach(a -> System.out.println(a.getKey()));

输出结果:

winter
autumn
summer
spring
统计
//统计
List<Integer> list4 = Arrays.asList(1, 2, 3, 4, 1);
IntSummaryStatistics stats = list4.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Highest number in List : " + stats.getMax());
System.out.println("Lowest number in List : " + stats.getMin());
System.out.println("Sum of all numbers : " + stats.getSum());
System.out.println("Average of all numbers : " + stats.getAverage());

运行结果:

Highest number in List : 4
Lowest number in List : 1
Sum of all numbers : 11
Average of all numbers : 2.2
match 匹配
  • anyMatch用于判断流中是否存在至少一个元素满足指定的条件,这个判断条件通过Lambda表达式传递给anyMatch,执行结果为boolean类型。
  • noneMatch与allMatch恰恰相反,它用于判断流中的所有元素是否都不满足指定条件
  • findAny能够从流中随便选一个元素出来,它返回一个Optional类型的元素。
 Boolean result1 = Arrays.stream(strings).allMatch(s -> s.equals("java"));
System.out.println(result1); Boolean reslut2 = Arrays.stream(strings).noneMatch(s -> s.equals("java"));
System.out.println(reslut2);
//随机读取一个
Optional<String> getResult = Arrays.stream(strings).findAny();
System.out.println(getResult);
System.out.printf("获取Optional中的值:%s%n", getResult.get());

运行结果:

false
true
Optional[冷暖]
获取Optional中的值:冷暖

Optional是Java8新加入的一个容器,这个容器只存1个或0个元素,它用于防止出现NullpointException,它提供如下方法:

  • isPresent() 判断容器中是否有值。
  • ifPresent(Consume lambda) 容器若不为空则执行括号中的Lambda表达式。
  • T get() 获取容器中的元素,若容器为空则抛出NoSuchElement异常。
  • T orElse(T other) 获取容器中的元素,若容器为空则返回括号中的默认值。
reduce 归约

求和:

//归约
//第一种方法求和
String connectStrings = Arrays.stream(strings).reduce("", (x, y) -> x + y);
System.out.println(connectStrings); // 第二种方法求和
String connectStrings1 = Arrays.stream(strings).reduce("", TestStream::getConnectStrings);
System.out.println(connectStrings1);

getConnectStrings方法:

/**
* Connect Strings
* @param s1 参数1
* @param s2 参数2
* @return java.lang.String
*/
private static String getConnectStrings(String s1, String s2) {
return s1 + s2;
}

reduce中第一个参数是初始值,第二个参数是方法引用。

数据流

StreamAPI提供了三种数值流:IntStream、DoubleStream、LongStream,也提供了将普通流转换成数值流的三种方法:mapToInt、mapToDouble、mapToLong。

每种数值流都提供了数值计算函数,如max、min、sum等。

下面使用 mapToInt 为例:

        String[] numberStrings = {"1", "2", "3"};
// mapToInt参数: 需要转换成相应的类型方法
IntStream intStream = Arrays.stream(numberStrings).mapToInt(Integer::valueOf);
//使用对应的 Optional 接收
OptionalInt optionalNumber = intStream.max();
// 取值,给默认值 0,为空结果为0
System.out.printf("numberStrings's max number is: %s%n", optionalNumber.orElse(0));

打印结果:

numberStrings's max number is: 3

由于数值流可能为空,并且给空的数值流计算最大值是没有意义的,因此max函数返回OptionalInt,它是Optional的一个子类,能够判断流是否为空,并对流为空的情况作相应的处理。 所以可以直接使用 OptionalInt.getAsInt()获取容器的值。

为空的话捕捉异常:

java.util.NoSuchElementException: No value present
at java.util.OptionalInt.getAsInt(OptionalInt.java:118)
at com.wuwii.test.TestStream.main(TestStream.java:105)

此外,mapToInt、mapToDouble、mapToLong进行数值操作后的返回结果分别为:OptionalInt、OptionalDouble、OptionalLong。

Collectors 集合归约

将流转换成集合和聚合元素。

 //Collectors 集合归约
// toList
List<String> list2 = Arrays.stream(strings).collect(Collectors.toList());
// Get String by connected
String connectStrings2 = Arrays.stream(strings).collect(Collectors.joining(","));
System.out.printf("Collectors toList: %s , Conlletors Join Strings: %s%n", list2, connectStrings2);

打印结果:

Collectors toList: [冷暖, 珊瑚, 细腻, 阳光, 阳光] , Conlletors Join Strings: 冷暖,珊瑚,细腻,阳光,阳光

后面补充: Collectors中还有一个groupingBy() 方法,比较实用,例子来源网上使用Java 8中的Stream

  1. groupingBy()表示根据某一个字段或条件进行分组,返回一个Map,其中key为分组的字段或条件,value默认为list,groupingByConcurrent()是其并发版本
Map<String, List<Locale>> countryToLocaleList = Stream.of(Locale.getAvailableLocales())
.collect(Collectors.groupingBy(l -> l.getDisplayCountry()));
  1. 如果groupingBy()分组的依据是一个bool条件,则key的值为true/false,此时与partitioningBy()等价,且partitioningBy()的效率更高
// predicate
Map<Boolean, List<Locale>> englishAndOtherLocales = Stream.of(Locale.getAvailableLocales())
.collect(Collectors.groupingBy(l -> l.getDisplayLanguage().equalsIgnoreCase("English"))); // partitioningBy
Map<Boolean, List<Locale>> englishAndOtherLocales2 = Stream.of(Locale.getAvailableLocales())
.collect(Collectors.partitioningBy(l -> l.getDisplayLanguage().equalsIgnoreCase("English")));
  1. groupingBy()提供第二个参数,表示downstream,即对分组后的value作进一步的处理
// 返回set,而不是list:
Map<String, Set<Locale>> countryToLocaleSet = Stream.of(Locale.getAvailableLocales())
.collect(Collectors.groupingBy(l -> l.getDisplayCountry(), Collectors.toSet())); // 返回value集合中元素的数量:
Map<String, Long> countryToLocaleCounts = Stream.of(Locale.getAvailableLocales())
.collect(Collectors.groupingBy(l -> l.getDisplayCountry(), Collectors.counting())); // 对value集合中的元素求和:
Map<String, Integer> cityToPopulationSum = Stream.of(cities)
.collect(Collectors.groupingBy(City::getName, Collectors.summingInt(City::getPopulation))); // 对value的某一个字段求最大值,注意value是Optional的:
Map<String, Optional<City>> cityToPopulationMax = Stream.of(cities)
.collect(Collectors.groupingBy(City::getName,
Collectors.maxBy(Comparator.comparing(City::getPopulation)))); // 使用mapping对value的字段进行map处理:
Map<String, Optional<String>> stateToNameMax = Stream.of(cities)
.collect(Collectors.groupingBy(City::getState, Collectors.mapping(City::getName,
Collectors.maxBy(Comparator.comparing(String::length))))); Map<String, Set<String>> stateToNameSet = Stream.of(cities)
.collect(Collectors.groupingBy(City::getState,
Collectors.mapping(City::getName, Collectors.toSet()))); // 通过summarizingXXX获取统计结果:
Map<String, IntSummaryStatistics> stateToPopulationSummary = Stream.of(cities)
.collect(Collectors.groupingBy(City::getState, Collectors.summarizingInt(City::getPopulation)));
reducing() // 可以对结果作更复杂的处理,但是reducing()却并不常用:
Map<String, String> stateToNameJoining = Stream.of(cities)
.collect(Collectors.groupingBy(City::getState, Collectors.reducing("", City::getName,
(s, t) -> s.length() == 0 ? t : s + ", " + t))); // 比如上例可以通过mapping达到同样的效果:
Map<String, String> stateToNameJoining2 = Stream.of(cities)
.collect(Collectors.groupingBy(City::getState,
Collectors.mapping(City::getName, Collectors.joining(", ")
)));

完整代码

package com.wuwii.test;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream; public class TestStream { public static void main(String[] args) {
// Get Stream from file
System.out.println("读取文件:");
try {
Stream<String> file = Files.lines(Paths.get("D:\\zhangkai\\WorkSpace\\Git\\hexo\\_config.yml"));
file.forEach(System.out::println);
} catch (Exception e) { } // Get Stream by Filter
String[] strings = {"珊瑚", "阳光", "细腻", "冷暖", "阳光"};
Arrays.stream(strings).filter(n -> n.startsWith("冷")).forEach(System.out::print); // Get Stream by Distinct
System.out.println("去重:");
Arrays.stream(strings).distinct().forEach(System.out::print); // Get Stream by Limit
System.out.println("截取:");
Arrays.stream(strings).limit(2).forEach(System.out::print); // Get Stream by Skip
System.out.println("跳过:");
Arrays.stream(strings).skip(2).forEach(System.out::print); // Java 8 sorted
System.out.println("排序:");
//Arrays.stream(strings).sorted((x, y) -> x.compareTo(y)).forEach(System.out::println);
Arrays.stream(strings).sorted(String::compareTo).forEach(System.out::println); // Before Java 8 sorted
System.out.println("java8以前排序:");
List<String> list1 = Arrays.asList(strings);
list1.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
System.out.printf("java8 以前的排序:%s%n", list1); //Handle map
System.out.println("map 映射:");
Arrays.stream(strings).map(s -> s + "兮").forEach(System.out::println); //Match
Boolean result1 = Arrays.stream(strings).allMatch(s -> s.equals("java"));
System.out.println(result1); Boolean reslut2 = Arrays.stream(strings).noneMatch(s -> s.equals("java"));
System.out.println(reslut2);
//findAny to find anyone
Optional<String> getResult = Arrays.stream(strings).findAny();
System.out.println(getResult);
System.out.printf("获取Optional中的值:%s%n", getResult.get()); //统计
List<Integer> list4 = Arrays.asList(1, 2, 3, 4, 1);
IntSummaryStatistics stats = list4.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Highest number in List : " + stats.getMax());
System.out.println("Lowest number in List : " + stats.getMin());
System.out.println("Sum of all numbers : " + stats.getSum());
System.out.println("Average of all numbers : " + stats.getAverage()); //归约
//第一种方法求和
String connectStrings = Arrays.stream(strings).reduce("", (x, y) -> x + y);
System.out.println(connectStrings); // 第二种方法求和
String connectStrings1 = Arrays.stream(strings).reduce("", TestStream::getConnectStrings);
System.out.println(connectStrings1); //Collectors 集合归约
// toList
List<String> list2 = Arrays.stream(strings).collect(Collectors.toList());
// Get String by connected
String connectStrings2 = Arrays.stream(strings).collect(Collectors.joining(","));
System.out.printf("Collectors toList: %s , Conlletors Join Strings: %s%n", list2, connectStrings2); String[] numberStrings = {"1", "2", "3"};
// mapToInt参数: 需要转换成相应的类型方法
IntStream intStream = Arrays.stream(numberStrings).mapToInt(Integer::valueOf);
//使用对应的 Optional 接收
OptionalInt optionalNumber = intStream.max();
// 取值,给默认值 0,为空结果为0
System.out.printf("numberStrings's max number is: %s%n", optionalNumber.orElse(0));
} /**
* 拼接字符串
*
* @param s1 参数1
* @param s2 参数2
* @return java.lang.String
*/
private static String getConnectStrings(String s1, String s2) {
return s1 + s2;
} }

Java8 新特性Stream 的学习和使用方法的更多相关文章

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

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

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

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

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

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

  4. Java8 新特性 Stream() API

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

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

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

  6. java8新特性--Stream的基本介绍和使用

    什么是Stream? Stream是一个来自数据源的元素队列并可以进行聚合操作. 数据源:流的来源. 可以是集合,数组,I/O channel, 产生器generator 等 聚合操作:类似SQL语句 ...

  7. Java8新特性Stream流应用示例

    Java8新特性介绍 过滤集合 List<String> newList = list.stream().filter(item -> item != null).collect(C ...

  8. Java8 新特性 Stream 练习实例

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

  9. 【Java8新特性】接口中的默认方法和静态方法,你都掌握了吗?

    写在前面 在Java8之前的版本中,接口中只能声明常量和抽象方法,接口的实现类中必须实现接口中所有的抽象方法.而在Java8中,接口中可以声明默认方法和静态方法,本文,我们就一起探讨下接口中的默认方法 ...

随机推荐

  1. [Unity] unity5.3 assetbundle打包及加载

    Unity5.3更新了assetbundle的打包和加载api,下面简单介绍使用方法及示例代码. 在Unity中选中一个prefab查看Inspector窗口,有两个位置可以进行assetbundle ...

  2. OpenGL学习笔记(1) 画一个三角形

    最近找实习有一丢丢蛋疼,沉迷鬼泣5,四周目通关,又不想写代码,写篇笔记复习一下,要好好学图形学啊 用OpenGL画一个三角形 项目的简介 记录一下跟着learnOpenGL学习的过程 笔记里的代码放在 ...

  3. vue mock(模拟后台数据) 最简单实例(一)——适合小白

    开发是前后端分离,不需要等待后台开发.前端自己模拟数据,经本人测试成功. 我们在根目录新建存放数据的json文件,存放我们的数据data.json //data.json{ "status& ...

  4. 学习笔记 | Set

    目录 Set Set 前言 不会数据结构选手 当几乎没写过什么数据结构的菜鸡遇上了毒瘤的splay和treap 时间正一点一点地被续走TAT 听说set有时候可以替代treap和splay 那么菜鸡L ...

  5. Leetcode_6. Zigzag convertion

    6. Zigzag convertion 对输入的字符串做锯齿形变换,并输出新的字符串,所谓zigzag变化如下图所示. 将"ABCDEFGHIJKL"做4行的锯齿变换,新的字符串 ...

  6. zookeeper客户端相关命令

    windows环境:    本机 直接 点机zkcli.cmd linux环境: 连接到zookeeper server ./zkCli.sh -server localhost:2181 help命 ...

  7. LeetCode 657. Robot Return to Origin (C++)

    题目: There is a robot starting at position (0, 0), the origin, on a 2D plane. Given a sequence of its ...

  8. Buaaclubs项目介绍

    简介 首先,它是社团资讯的集散地,任何希望了解北航社团信息或活动情况的同学都可以在这个平台上获取自己需要的信息,并且可以随时随地地参与社团互动,方便快捷地实现网上报名.在线咨询.活动参与等多种功能. ...

  9. 第10章 系统级I/O(下)

    10.7  I/O重定向 Unix外壳提供了I/O重定向操作符,允许用户将磁盘文件和标准输出输入联系起来. 例如:unix>ls>foo.txt,使得外壳加载和执行ls程序,将标准输出重定 ...

  10. c# 程序重启设定

    问题情境: 程序随着时间运行,越来越大.暂时想到的两种方法,一是反攻代码,查看占内存大的函数,是不是没有回收.再就是暴力设定程序定时重启. 解决原理: 定时重启:暂设定timer,时间匹配执行rest ...