带你认识不一样的Stream,Java8就该这么玩!

云栖号资讯:【点击查看更多行业资讯】
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!

相信Java8的Stream 大家都已听说过了,但是可能大家不会用或者用的V ] 0 *不熟,文章将带大家从零开始使S V + ; G ^ M ] 8用,循序渐进,带你走向Stream的巅峰。

操作符

什么是操作符呢?操作符就是对数据进行的一种处理工作,一道加工程序;就好像工厂的工人对流水线上的产品进行一道加工程序一0 I V 7 f v v样。

带你认识不一样的Stream,Java8就该这么玩!

Stream的操作符大体上分为两种:中间操作符和终止操作符

中间操作符

对于数据流来说,中间操作符在执行制定处理程序后,a Q & K x U x E数据流依然可以传递给下一级的操作符。

中间操作符包含8种(排除了parallel,sequential,这两个操作并不涉及到对数据流的加工操作):

map(mapToIntA q k !,mapToLong,mapToDouble) 转换操作符,把比H } # ; 1 / Q R如A->B,这里默认提供了转int,long,double的操作符。
flatmap(flatmapToInt,flatmapToLong,flatmapToDouble) 拍平操作比如把; 8 int[]{2,3,4} 拍平 变成 2,3,4 也就是从原来的一个数据变成了3个数据,这里默认提供了拍平成int,long,doubq [ a (le的操作符。
limit 限流操作,比如 $ ] # Z数据流中有10个 我只要出前3个就可以使用。
distint 去重操作,对重复元素去重,底层使用了equals方法。
filter 过滤操作,把不想要的数据过滤。
peek 挑出操作,如果想对数据进行某些操作,如:读取、编{ _ = U & C L q e辑修改等。
skip 跳过操作,跳过某些元素。
sorted(unordered) 排序操作,对元素排序,前提是实现Compa Q P 4rable接口,当然也可以自定义比较器。

终止操作符

数据经过中间加工操作,就轮到终止操作符上场了;终止操作符就是用来对数据进行收集或者消费` 2 I U W D _的,数据到了终止操作这里就不+ f , b z + V 4 会向下流动了,终止操作符只能使用一次。

collecw st 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的CollectoS 6 m qrs 提供了非常多收集器,可以说Stream 的核心在于Collectors。D | E v
count 统计操作,统计最终的数据个数。
findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为Optional。
nonG 3 f ieMatch、allMatch、anyMatch 匹配操作,数据流中a r Z [ C l G是否存在符合条件的元素 返回值为bo{ p 6 + , R 2 A Jolo ! U 0 g ~ 7 值。
min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值。
reduce 规约操作,将整个数据流的值规约为E ) k n O r m , w一个值,couH 7 ] v ( pnt、min、max底层就是使用reduce。
forEach、forEachOrdered 遍历操作,这里就是对最终P / Q b k的数据进行消费A } x P } N了。
toAW z i Yrray 数组操作,将数据流的元素转换成数组。

这里只介绍了Stream,并没有涉及到IntStream、LoD M h v % } 6 v ^ngStream、DoubleStream,这三w I M 6 I $ `个流实现了一些特有的操作符,我将在后续文章中介绍到。

说了这么多,只介绍这T @ 4 C # v { b些操l V f T X作符还远远不够;俗话说,实践出真知。那么,Let‘s go。

代码演练

Stream 的一系列操1 2 J N W作必须要使用终止操作,否者整个数据流是不会流动起来的,即处理操作不会执行。

map,可以看到 map 操作符要求输入一个Fun& x $ n pction的函数是接口实例,功能是将T类型转换成R类型的。

带你认识不一样的Stream,Java8就该这么玩!

map操作将原来的单词 转换成了每个单的长度,利用了String自身的length()方法,该方法返回类型U s W &为int。这里我直接使用了lambda表达式,关于lambda表达式 还请读者们自行了解吧。

public class Main {
public sR D * [ X O n + etatic void main(String[] args) {
Stream.of("apple","bank F 9 L d T ~ Fana","orange","waltermaleon","grape")
.map(e->e.length()) //转成单词的长度 int
.forEach(e->System.out.println(e)); //输出
}
}

当然也可以这样,这里. : *使用c + n s x ]了成员函数引用,为了便于读者们理解,后续的例子中将使用lambda表达式而非函数引用。

public class Main {
public static void@ ! m main(String[] args) {
Stream.of("apple","banana","orange","waltermaleon","grapeW 7 b ; 1 U  o")
.map(String::lenT q $ qgth) //转成单词的长度 int
.forEach(System.out::println);
}
}

结果如图:

public class Main {
public static void main(String[] args) {
Strei y 1am.of("apple", "banana",q - n d a g a . "orange", "waltermalq J weon", "grape"c + i z i Z)
.mapToInt(e -> e.length()) //转成int
.forEach(e -> System.out.println(e));
}
}

mapToInt如图:

带你认识不一样的Stream,Java8就该这么玩!

puE C I ! 2 | & Iblic class Main {
publ/ . C 5 a ` Ric static void main(String[] args) {
Stream.of("apple", "banana", "orange", "waltermaleon", "grape")
.mapToLong(e -> e.lengt5 % d d 2h()) //转成long ,本质上是int 但是存在类型自动转换
.forEach(e -> System.out.prinR  r ] 2 ] F 2tln(e));
}
}

mapToLong9 . i 如图:

带你认识不一样的Stream,Java8就该这么玩!

public class Main {
puE [ M , { q  l `blic static void main(String[] args) {
Stream.of("apple", "banana", "orf + + y W 3 T {ange", "waltermaleon", "grape| Z U S P V J %")
.mapToDouble(e -> e.length()) //转成Double ,自动类型转换$ L V # P l 6成Double
.forEach(e -> System.out.println(e));
}
}

带你认识不一样的Stream,Java8就该这么玩!

带你认识不一样的Stream,Java8就该这么玩!

public class Main {
public static void main(String[] args) {b z l ^ s
Stream.of("a-bR O I e S / t-c-d* , # 9","e-f-i-g-h")
.flatMap(e->Stream.of(e.split("-")))
.forEach(eJ x @ | + b w a->Sa B # e b Y A L eystem.out.printlu @ C & y , { Xn(e));
}
}

flatmap 如图:

带你认识不一样的Stream,Java8就该这么玩!

public class Main {
public static void main(String[] args) {
Stream.of(1,2,3,4,5,6)
.limit(3) //限制三个I Z * s
.forEach(e->System.out.println(e)); //将输出 前三个 1,2,3
}
}

limit如图:

带你认识不一样的Stream,Java8就该这么玩!

publi# 9 @ 5 V d Xc class Main {
public static void mai~  J !n(String[] args) {
Stream.of(1,2,3,1,2,5,6,7,8,0,0,1U @ 7,2,3,1)
.distinct() //去重
.forEach(e->System.out.println(e));
}
}

distinct 如图:

带你认识不一样的Stream,Java8就该这么玩!

public class Main {
publS 7 F d ` | L (ic sU y $ V btatic void main(String[]Z } l ) ) i { args) {
Stream.of(1,2,3,1,2,5,6 Q , & 9 g j6,y M @ & L $7,8,0,0,1,2,3,1)
.filter(e->e>=5) //过滤小于5的
.forEach(e->System.out.println(e));
}
}

带你认识不一样的Stream,Java8就该这么玩!

public class Main {
public static void main(Str6 h ^ 1 % M 5ing[] args) {
User w = new User("w",10);
User x = new User("x",11)4 U ~;
User y = new User("y",12)| w C F Y ~ {;
Stream.of(w,x,y)
.peek(w @ & 1e->{e.setName(e.gez J 3tAge()+e.getName());}) //重新设置名字 变成 年龄+名字
.forEach(e->System.out.println(e.toString()));
}
static class User {
private String name;
private int age;
pub9 L I % c N Elic User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = namec W s c a W;
}
public int getAge() {
return age;
}, 3 = 9
public void setAge(int age) {
this. X i ~ i G.age = age;
}
@Override
public String toString() {
ret3 u 0 ` y ] ` 0urn "User{" +
"name='" + name + ''L G p c 0 K ' +
", age=" + age +
'}';
}
}
}

带你认识不一样的Stream,Java8就该这么玩!

public class Main {
public static void main(String[] args) {
Str* F t O Ieam.of(1T c ~ % N,2,9 1 t K V z3,4,5,6,7,8,9)
.skip(4) //跳过前四个
.forEach(e->SystP 6 t Pem.out.println(e))? I  *; //输出的结果应该只有5,6,7, ~  ( o P K q,8,9
}
}

skip 如图:

带你认识不一样的Stream,Java8就该这么玩!

public class MA a  D ~ain {
public static void main(String[] args) {
Stream.of(2,1,3,6,4,9,6,8,0)
.sorted()
.forEach(2 v A } 5 & 7eo I 1 6 x E 4 b r->System.out.println(e));
}
}

带你认识不一样的Stream,Java8就该这么玩!

publi4 D ~ _ , _ U Ac class Main {
public static void main(String[] args) {
User x = new User("x",11);
User y = new User("y",12);
User w = new User("w",10);
Stream.of(w,x,y)
.sorted((e1,e2)->e1.age>e2.age?1:e1.age==e2.age?0:-1)
.forEach(e->System.out.printx ! @ u U Oln(e.toString()));
}
static class User {
pL / i & n 0rivate String name;
private int age;
publi7 P 3 c User(Strin. B  8 g &g name~ x P, int age) {
this.name = name;
this.age = age;
}
public String getJ A { y = 2 c nName() {
return name;
}
pub.  r H ( X - Dlic void setName(String name) {
this.name = name;
}
public int getAge()I  [ 9 I R {
return age;
}
public void setAge(int ag^ ] N 1 K { $ ze) {2 a { F D 8 ;
this.age = age;
}
@OverridG % . ce
public StringM y P R toStrr 2 ; 8  8 6ing() {
return "User{" +
"name='" +8 D (  } J name + ''' +
", age=" + age +
'}';
}
}
}

带你认识不一样的Stream,Java8就该这么玩!

public class Main {
public static void main(String[] args) {
Stream.of(R z 4  z { v y"apple", "banana", "orange", "waltermaleon", "grape")
.collec4 X p u E j jt(Colp 8 - 5 5 : O O *lectors.toSet()) //set 容器
.forEach(e -> System.out.println(e));
}
}

咦?,不是说终止操作符只能使用一次吗,为什么这里调用了forEach 呢?

forEach不仅仅是是Stream 中得操作符还是各种集合中得一个语法糖,不信咋们试试。

public classp  % A J Main {
public static void main(String[] args) {
Set<String> stringSet = Stream.of("apple", "banana", "orange", "waltermaleon", [ X D 0 S ( ; k R"grape")
.collect(ColleE U =  ] 7 / N Xctors.toSet()); // N m {收集的结果就是set
stringSet.forEach(e->System.out.println(e)); setx , * ^ 0 % v C的语法糖forEach
}

![3825B37B_D04B_49ac_A0B2_CB08DA5D5616](https://yqfile.a/ # c # Y 6 ) } Glis 3 cdn.com/df18d416a1666dc1d1d9511602a16c2d3e7ea352.png

public class Main {
public static void main(String[] args) {
long count = Stream.of("appleV I J | A b U  8", "banana", "orange", "wV 4 V ` | _ $altermaleon", "grape")
.count();
System.out.println(count);
}
}

带你认识不一样的Stream,Java8就该这么玩!

public class FiA 4 @ 9ndFirst {
publv [ G ! q 2 (ic static void main(String[] args) % i * q ~ T {
Optional<String> c Z & I ] t r c; stringOptional = Stream.of("apple", "banana. v ` N", "orange", "waltermaleon", "grape")
.findFirst();
stringOptional.ifPresent(e->System.out.prin3 k 5 u g + Itln(e));
}
}

public clJ - E O k Pass FindAny {
public stat O 3ic void mc +  yain(String[] args) {
Optional<String> stringOptional = Stream.of("apple", "banana", "orange", "waltermaleon", "g= J wrape")
.parallel()
.findAny(); //在并行流下每次返回的q 4 w $ % g结果可能一样也可能不一样
stringOptional.ifPresent(e->System.out.println(e));
}
}

带你认识不一样的Stream,Java8就该这么玩!

这里 的作用是是判断数据流中 一个都没有与aa 相等元素 ,但是流中存在 aa ,所以最终结果应该是false。

public class NoneMatch {
public static void main(String[] args) {
boolean result = Stream.of("aa","bb"Q K S V W !,"cc","aa")
.nonn j f # *eMatch(e->e.equals("aa"));
System.out.println(result);
}
}

带你认识不一样的Stream,Java8就该这么玩!

public class Main {
public static void main(String[] argQ F x 1 M 3 z % *s) {
Optional<Integer> integerOptional = Stream.of(0,9,8,4,5,6,-1)
.min((e1,e2)->e1 K T ] ; 2 v f.compareTo(e2));D B ~ v J
integerOptional.ifPrese^ C W =nt(e->System.out.println(e));
}

带你认识不一样的Stream,Java8就该这么玩!

public class Main {
public static void maX E Tin(String[] args) {
Optional<Integer> integerOptional = Stream@ e o 9 ! J /.of(0,9,8,4,5,6,-1)
.max((e1,D 6 q B Z [ c & se2)->e1.compareTo(e2));
integerOptional.ifPresent(e->System.out.println(e));
}
}

带你认识不一样的Stream,Java8就该这么玩!

public class Main {
public static void main(Sty G  Y Yring[] args) {
int sum = Stream.of(0,9,8,4,5,6,-1)
.reduce(0,(e1,e2)->e1+e2);
System.out.println(sum);
}
}

带你认识不一样的Stream,Java8就该这么玩!

public class ForEachOrdered {
public static void m9 E ) 8 | m / Bain(String[] args) {
Stream.of(0,2,6,5,4,9,8,-1)
.parallel()
.forEachOrdered(e-&E 9 S # Rgt;{
System.outZ w ..println(Thread.currentThread().getB 6 A G U # D . LName()+": "+V G {e);});
}
}

带你认识不一样的Stream,Java8就该这么玩!

public class ToArray {
public static void main(String[] args) {
Obje: w G k z mct[R @ q  e] objects=Stream.of(0,2,6,5,4,+ } 5 s9,8,-1)
.toArray();
for (int i = 0; i < objects.length;a ; N ` - ! r o i++) {
System.out.println(o6 | x |bjects[i]);
}
}
}

带你认识不一样的Stream,Java8就该这么玩!

【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun: 0 o J ?.com/zhibo

立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c% . Y z 1 b s ~ G.tb.cn/F3.Z8gvnK

原文发布时间:2020-07-03
本文作者:li^ 0 ? L 9 Ttesky
本文来自:“互联网架构师”,了解相关信息可以关注“互联网架构师”