在使用filter时不要和removeIf弄混淆了:
removeIf中的test方法返回true代表当前元素会被过滤掉;
filter中的test方法返回true代表当前元素会保留下来。

https://blog.csdn.net/qq_33829547/article/details/80279488

引例:

1         List<String> strList = Arrays.asList("zhaojigang","nana","tianya","nana");
2 Stream<String> streamList = strList.stream();//集合转为stream
3 strList = streamList.distinct().filter(str->!str.equals("tianya")).sorted(String::compareTo).collect(Collectors.toList());
4 strList.forEach(System.out::println);

说明:

  • 第一行:创建数组并转为List
  • 第二行:根据List创建stream
  • 第三行:对该stream进行去重-->选择-->排序-->stream转为List
  • 第四行:遍历该List

以上代码显示了stream API的方便。当然,上边的代码可以更为简洁,如下改为一行:

Arrays.asList("zhaojigang","nana","tianya","nana").stream().distinct().filter(str->!str.equals("tianya")).sorted(String::compareTo).collect(Collectors.toList()).forEach(System.out::println);

以上代码有一个易错点:filter是选择而不是过滤,即filter是选择满足条件的元素

一、创建Stream

三种常用API:

  • 集合-->Stream:stream()
  • 数组-->Stream:Stream.of(T t)或者Arrays.stream(T[] t)
  • 任意元素-->Stream:Stream.of(T... values)
 1         List<String> strList = Arrays.asList("zhaojigang","nana","tianya","nana");
2 Stream<String> streamList = strList.stream();//集合转为stream
3
4 String[] strArray = {"java","c++","c"};
5 Stream<String> streamArray = Stream.of(strArray);//数组转为Stream
6 Stream<String> streamArray2 = Arrays.stream(strArray);//数组转为Stream
7
8 Stream<String> streamPartArray = Arrays.stream(strArray, 0, 2);//转换部分数组,范围:[0,2)
9
10 Stream<String> streamSelf = Stream.of("python","basic","php");//任意元素

还有一种:用于产生无限流的,Stream.generate(Supplier<T> s)。

二、Stream 2 array/collection/String/map

1、stream2array

1         Stream<String> strStream = Stream.of("java","c++","c","python");
2 Object[] objectArray = strStream.toArray();//只能返回Object[]
3 String[] strArray = strStream.toArray(String[]::new);//构造器引用(类似于方法引用),可以返回String[]

说明:

通过构造器引用(类似于方法引用),可以构造出具体类型的数组。

2、stream2collection

1         List<String> strList = strStream.collect(Collectors.toList());//返回List
2 Set<String> strSet = strStream.collect(Collectors.toSet());//返回set
3 ArrayList<String> strArrayList = strStream.collect(Collectors.toCollection(ArrayList::new));//收集到指定的List集合,例如收集到ArrayList

说明:

通过构造器引用,可以构造出具体类型的集合。

3、将stream中的元素拼接起来(joining()、joining(","))

1         Stream<String> strStream = Stream.of("java","c++","c","python");
2 String str = strStream.collect(Collectors.joining());//将所有字符串拼接起来,结果:javac++cpython
3 System.out.println(str);
4
5 String str2 = strStream.collect(Collectors.joining(","));//将所有字符串拼接起来,中间用","隔开,结果:java,c++,c,python
6 System.out.println(str2);
arryIds.stream().map(Object::toString).collect(Collectors.joining(","));

4、stream2map(toMap、toConcurrentMap)

 1         Stream<String> strStream = Stream.of("java","c++","c","python");
2 Map<String, Integer> map1 = strStream.collect(Collectors.toMap(Function.identity(), (x)->0));
3 //Function.identity()-->返回strStream中的元素,toMap方法的我两个参数都是Function接口型的,所以第二个参数即使只放0,也不能直接写作0,可以使用如上的方式进行操作
4
5 for(String key : map1.keySet()){
6 System.out.println("key:"+key+"->"+"value:"+map1.get(key));
7 }
8 //结果
9 /*
10 key:python->value:0
11 key:c++->value:0
12 key:c->value:0
13 key:java->value:0
14 */

说明:

  • toMap-->stream转为map
  • Function.identity()-->返回stream中的元素

如果key重复的话,这时就会出现问题"duplicate key",采用如下方式解决(增加第三个参数):

1         Stream<String> strStream = Stream.of("java","c++","c","python","java");
2 Map<String, Integer> map1 = strStream.collect(Collectors.toMap(Function.identity(), //key
3 (x)->0, //value
4 (existingValue, newValue) -> existingValue));//如果key重复,取旧值

需要指定返回map的具体类型(增加第四个参数)。

1         Map<String, Integer> map1 = strStream.collect(Collectors.toMap(Function.identity(), //key
2 (x)->0, //value
3 (existingValue, newValue) -> existingValue,//如果key重复,取旧值
4 TreeMap::new));//返回TreeMap

注意:每一个toMap就会对应一个相应的toConcurrentMap

5、groupingBy partitioningBy

 1         /***************************groupingBy partitioningBy**************************/
2 Stream<Locale> localeStream = Stream.of(Locale.getAvailableLocales());
3 Map<String, List<Locale>> country2localeList = localeStream.collect(Collectors.groupingBy(Locale::getCountry));//根据国家分组,groupBy的参数是分类器
4 List<Locale> locales = country2localeList.get("CH");
5
6 Map<String, Set<Locale>> country2localeSet = localeStream.collect(Collectors.groupingBy(Locale::getCountry, Collectors.toSet()));//根据国家分组,groupBy的参数是分类器,返回set
7 Set<Locale> localeSet = country2localeSet.get("CH");
8
9 Map<Boolean, List<Locale>> country2locales = localeStream.collect(Collectors.partitioningBy(locale->locale.getLanguage().equals("en")));//分成两组,一组为true(即语言是en的),一组为false(即语言不是en的)
10 List<Locale> trueLocale = country2locales.get(true);

三、filter(Predicate p)

注意:是选择而非过滤

1         Stream<String> streamSelf = Stream.of("python","basic","php");
2 streamSelf.filter(str->str.startsWith("p")).forEach(System.out::println);

注意:

  • stream也是可以foreach的,没必要一定要转化成集合再foreach

更好的写法可能是下边这种:

1         Predicate<String> startCondition = str->str.startsWith("p");
2 streamSelf.filter(startCondition).forEach(System.out::println);

说明:将条件(通常是lambda表达式)抽取出来。这种方式在多个条件的情况下比较清晰。

注意:函数式接口 = lambda表达式 (即lambda表达式只能返回为函数式接口)

1         Stream<String> s = Stream.of("java1","java3","java","php12");
2 Predicate<String> condition1 = str->str.length()==5;//条件1
3 Predicate<String> condition2 = str->str.startsWith("j");//条件2
4 s.filter(condition1.and(condition2)).forEach(System.out::println);//and条件

说明:

多条件运算:and or

四、map(Function mapper)

作用:对流中的每一个元素进行操作。

1         Stream<String> streamSelf = Stream.of("python","basic","php");
2 streamSelf.map(String::toUpperCase).forEach(System.out::println);

说明:将流内的每一个String全部转换为了大写。

五、reduce 

作用:对stream中的每一个元素做聚合操作。

1         Stream<Integer> reduceStream = Stream.of(1,2,3,4,5);
2 Optional<Integer> sumOption = reduceStream.reduce((x,y)->x+y);//计算1+2+3+4+5,即对元素中的元素进行聚合计算,而map是对元素中的每一个元素分别计算(注意:如果stream为null的话,就会产生无效的结果,需要使用Optional接收)
3 //Optional<Integer> sumOption = reduceStream.reduce(Integer::sum);//计算1+2+3+4+5,即对元素中的元素进行聚合计算,而map是对元素中的每一个元素分别计算
4
5 Integer result = reduceStream.reduce(0, Integer::sum);//0为标识值,即计算:0+1+2+。。+5,如果整个stream为null,就返回标识值。
6 System.out.println(result);

注意:以上是reduce的简单形式,即内联函数是(T,T)->T,即返回值和参数类型是一样的,返回值和参数类型不同的场景需要自己编写函数(用的较少)

六、Optional

两种用法:

  • ifPresent(xxx):存在的就执行xxx,不存在就什么都不执行
  • orElse(xxx):存在就返回存在的值,不存在就返回xxx(可以理解为是默认值)
1         Stream<String> optionalStream = Stream.of("java","python","basic");
2 Optional<String> optionValue = optionalStream.filter(str->str.startsWith("p")).findFirst();
3 optionValue.ifPresent(str->System.out.println(str));//if optionalValue为true,即str存在,则输出str,当然也可以使用如下
4 String str = optionValue.orElse("xxx");//如果optionValue为false,即不存在以p开头的字符串时,使用"xxx"来替代
5 System.out.println(str);

Optional是Java8提供的为了解决null安全问题的一个API。善用Optional可以使我们代码中很多繁琐、丑陋的设计变得十分优雅。这篇文章是建立在你对Optional的用法有一定了解的基础上的,如果你还不太了解Optional,可以先去看看相关教程,或者查阅Java文档。

使用Optional,我们就可以把下面这样的代码进行改写。

public static String getName(User u) {
if (u == null)
return "Unknown";
return u.name;
}

不过,千万不要改写成这副样子。

public static String getName(User u) {
Optional<User> user = Optional.ofNullable(u);
if (!user.isPresent())
return "Unknown";
return user.get().name;
}

这样改写非但不简洁,而且其操作还是和第一段代码一样。无非就是用isPresent方法来替代u==null。这样的改写并不是Optional正确的用法,我们再来改写一次。

public static String getName(User u) {
return Optional.ofNullable(u)
.map(user->user.name)
.orElse("Unknown");
}

这样才是正确使用Optional的姿势。那么按照这种思路,我们可以安心的进行链式调用,而不是一层层判断了。看一段代码:

public static String getChampionName(Competition comp) throws IllegalArgumentException {
if (comp != null) {
CompResult result = comp.getResult();
if (result != null) {
User champion = result.getChampion();
if (champion != null) {
return champion.getName();
}
}
}
throw new IllegalArgumentException("The value of param comp isn't available.");
}

由于种种原因(比如:比赛还没有产生冠军、方法的非正常调用、某个方法的实现里埋藏的大礼包等等),我们并不能开心的一路comp.getResult().getChampion().getName()到底。而其他语言比如kotlin,就提供了在语法层面的操作符加持:comp?.getResult()?.getChampion()?.getName()。所以讲道理在Java里我们怎么办!

让我们看看经过Optional加持过后,这些代码会变成什么样子。

public static String getChampionName(Competition comp) throws IllegalArgumentException {
return Optional.ofNullable(comp)
.map(c->c.getResult())
.map(r->r.getChampion())
.map(u->u.getName())
.orElseThrow(()->new IllegalArgumentException("The value of param comp isn't available."));
}

这就很舒服了。Optional给了我们一个真正优雅的Java风格的方法来解决null安全问题。虽然没有直接提供一个操作符写起来短,但是代码看起来依然很爽很舒服。更何况?.这样的语法好不好看还见仁见智呢。

还有很多不错的使用姿势,比如为空则不打印可以这么写:

string.ifPresent(System.out::println);

Optional的魅力还不止于此,Optional还有一些神奇的用法,比如Optional可以用来检验参数的合法性。

public void setName(String name) throws IllegalArgumentException {
this.name = Optional.ofNullable(name).filter(User::isNameValid)
.orElseThrow(()->new IllegalArgumentException("Invalid username."));
}

这样写参数合法性检测,应该足够优雅了吧。

参考资料

  • 使用 Java8 Optional 的正确姿势 – 隔叶黄莺 Unmi Blog (https://unmi.cc/proper-ways-of-using-java8-optional/)

https://mp.weixin.qq.com/s/p_vwjlpK6GxQBk5_nSbeQA

七、limit skip contact

1、limit(long size)

作用:截取stream的前size个元素。

1         Stream<String> streamSelf = Stream.of("python","basic","php");
2 streamSelf.limit(2).forEach(System.out::println);//截取前两个

2、skip(long size)

作用:跳过stream的钱size个元素

1         Stream<String> streamSelf = Stream.of("python","basic","php");
2 streamSelf.skip(2).forEach(System.out::println);//跳过前两个

3、contact(Stream<T>,Stream<T>)

作用:拼接两个stream

1         Stream<String> streamSelf = Stream.of("python","basic","php");
2 Stream<String> streamSelf2 = Stream.of("python2","basic2","php2");
3 Stream.concat(streamSelf, streamSelf2).forEach(System.out::println);

八、聚合函数 count max min findFirst findAny anyMatch allMatch noneMatch

1         Stream<String> streamSelf = Stream.of("python","basic","php","b");
2 System.out.println(streamSelf.count());//计算流中的元素个数
3 Optional<String> largest = streamSelf.max(String::compareToIgnoreCase);//寻找最大值
4 if(largest.isPresent()){
5 System.out.println(largest.get());
6 }

说明:min函数也一样。

注意:Optional的使用,上边的是最差的一种形式,见"六"。

 1         Optional<String> firstMatch = streamSelf.filter(str->str.startsWith("b")).findFirst();//寻找第一个符合条件的元素
2 firstMatch.ifPresent(System.out::println);//这是Optional的第一种用法
3
4 Optional<String> anyMatch = streamSelf.parallel().filter(str->str.startsWith("b")).findAny();//返回集合中符合条件的任意一个元素,对于并行处理非常好(因为多个线程只要有一个线程找到了,整个计算就会结束)
5 if(anyMatch.isPresent()){
6 System.out.println(anyMatch.get());//这里的结果可能是b,有可能是basic
7 }
8
9 boolean isAnyMatch = streamSelf.parallel().anyMatch(str->str.startsWith("c"));//集合中是否有一个满足条件
10 System.out.println(isAnyMatch);
11
12 Stream<String> streamSelf3 = Stream.of("basic","b");
13 boolean isAllMatch = streamSelf3.parallel().allMatch(str->str.startsWith("b"));//集合中是否所有元素都满足条件
14 System.out.println(isAllMatch);
15
16 boolean isAllNotMatch = streamSelf.parallel().noneMatch(str->str.startsWith("p"));//集合中是否没有一个元素满足条件
17 System.out.println(isAllNotMatch);

注意:

  • optional的最佳用法:ifPresent()-->如果有就输出,如果没有,什么都不做
  • parallel():将stream转为并行流,并行流的使用一定要注意线程安全

九、原始类型流

  • IntStream:int、short、char、byte、boolean
  • LongStream:long
  • DoubleStream:double、float

http://www.cnblogs.com/java-zhao/p/5492122.html

第二章 Stream API的更多相关文章

  1. 3分钟看完Java 8——史上最强Java 8新特性总结之第二篇 Stream API

    目录 · 概况 · 切片(Slicing) · 映射(Mapping) · 匹配(Matching) · 查找(Finding) · 归约(Reducing) · 排序(Sorting) · 数值流( ...

  2. Java8新特性第3章(Stream API)

    Stream作为Java8的新特性之一,他与Java IO包中的InputStream和OutputStream完全不是一个概念.Java8中的Stream是对集合功能的一种增强,主要用于对集合对象进 ...

  3. HBase第二章 基本API

    1.pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...

  4. HTML5 WebSocket 权威指南 学习一 (第二章 WebSocket API)

    WebSocket 协议两种URL方案 ws 客户端和服务器之间的非加密流量 wss 客户端和服务器之间的加密流量 WebSocket Secure 表示使用传输层安全性(SSL)的WebSocket ...

  5. Upgrading to Java 8——第四章 The Stream API

    在这章中我们将学习Stream API,在JDK 8 中的一项新的特性.为了理解这一章的主题,你需要知道如何使用Lambda表达式和java.util.function里的预定义的函数式接口. 一个S ...

  6. ArcGIS API for JavaScript 4.2学习笔记[10] 2D添加指北针widget、视图保存、视图padding(第二章完结)

    这几个例子是第二章除了入门之外比较简单的几个,就做个合集,把最核心的代码(第二参数)和 引用放上来即可,不作多解释. 2D地图添加指北针widget 2D地图一般修正方向为正北方就需要这个widget ...

  7. ArcGIS API for JavaScript 4.2学习笔记[3] 官方第二章Mapping and Views概览与解释

    目录如下: 连接:第二章 Mapping and Views 根据本人体会, [这一章节主要是介绍地图(Map)和视图(View)的.] 其中,Get started with MapView(2D) ...

  8. Java8新特性之三:Stream API

    Java8的两个重大改变,一个是Lambda表达式,另一个就是本节要讲的Stream API表达式.Stream 是Java8中处理集合的关键抽象概念,它可以对集合进行非常复杂的查找.过滤.筛选等操作 ...

  9. 《Getting Started with WebRTC》第二章 WebRTC技术介绍

    <Getting Started with WebRTC>第二章 WebRTC技术介绍 本章作WebRTC的技术介绍,主要讲下面的概念:   .  怎样建立P2P的通信   .  有效的信 ...

随机推荐

  1. JMX 与系统管理--转

    前言 在 Java 程序的运行过程中,对 JVM 和系统的监测一直是 Java 开发人员在开发过程所需要的.一直以来,Java 开发人员必须通过一些底层的 JVM API,比如 JVMPI 和 JVM ...

  2. iOS 使用Charts框架 折线,柱状,K线,饼状,雷达全攻略

    我是前言: 大约几个月前我在某平台写了一篇文章, 文中简单地介绍了Charts两种图表的样式的使用, 不过有种意犹未尽的感觉, 利用周末的空闲时间再次看了看, 有了新的收获, 今天发出来,分享给大家, ...

  3. CTE在Oracle和Sqlserver中使用的差异

    CTE是一个很好用的工具,他可以帮助我们清晰代码结构,减少临时表使用,同时oracle和sqlserver都提供支持.但在oracle和sqlserver中使用CTE也存在一定区别. Oracle使用 ...

  4. htmlentities() 函数

    Definition and Usage定义和用法 The htmlentities() function converts characters to HTML entities.htmlentit ...

  5. CakePHP之Model

    模型 模型在应用程序中是作为业务层而存在的(怎么感觉是数据层......).这就意味着,模型应当负责管理几乎所有涉及数据的事情,其合法性,以及你的业务领域中数据在工作流程中的演化和互动 . 通常模型类 ...

  6. android 简单的开机自启

    今天我们主要来探讨android怎么让一个service开机自动启动功能的实现.Android手机在启动的过程中会触发一个Standard Broadcast Action,名字叫android.in ...

  7. Linux软件

    网上下载:Chrome Browser for Linux; sqlite;  WPS; symbol-fonts; 软件中心:Terminator; Code::Blocks IDE;  新立得软件 ...

  8. Gprinter Android SDK V2.1.4 使用说明

    佳博打印机Android的SDK开发包,已更新到Gprinter Android SDK V2.1.4. IOS的SDK开发包更新为GprinterSDKandDemoforIOS_v1.0.8. 根 ...

  9. Swift中可选类型(Optional)的用法 以及? 和 ! 的区别 (转载博客,知识分享)

    本文转载自:代码手工艺人的博客,原文名称:Swift之 ? 和 ! Swift语言使用var定义变量,但和别的语言不同,Swift里不会自动给变量赋初始值,也就是说变量不会有默认值,所以要求使用变量之 ...

  10. 【转】Entity Framework教程

    转自:http://www.cnblogs.com/xray2005/category/189491.html   Entity Framework系列文章导航 摘要: 本节集合了Entity Fra ...