Java 8 Stream常用的操作符

简介

在Java 8中API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。在Java中只要你应用的版本是java 8以上的话都能使用该API,但是在Android中如果API低于24时,是无法使用该java API,今天我们来介绍在Android中如何使用Stream,还有常用的操作符。

Stream

什么是Stream

在操作之前我们来认识一下什么是Stream? 有什么特性呢? 进入Sream API

  • 支持顺序和并行聚合操作的一系列元素,有丰富的操作符。
  • 除了Stream(对象引用流)之外,还有IntStream,LongStream和DoubleStream的原始特化,所有这些特性都被称为“流”,并且符合此处描述的特征和限制
  • Stream Pipeline 可以顺序执行并行执行。此执行模式是流的属性。通过初始选择的顺序或并行执行来创建流。(例如Collection.stream()创建一个顺序流Collection.parallelStream() 创建一个并行流。)这种执行模式的选择可以通过BaseStream.sequential()或BaseStream.parallel()方法修改,并且可以使用BaseStream.isParallel()方法查询。
  • 和Collections有相似之处,但是Stream不提供直接访问或操纵其元素的手段,而是涉及声明性地描述它们的源以及将在该源上聚合执行的计算操作。
  • 支持lambda,更加方便简洁。

Android 使用Stream

上文已经提及了在默认的Android API中只要在API 24以上才能使用如下:

@RequiresApi(api = Build.VERSION_CODES.N) //必须标志在Android N才能使用,也就是API>=24才能使用
public void testStream() {
  List<String> strings = Arrays.asList("1", "2", "2", "3", "4");
  Stream.of(strings).filter(s -> !strings.isEmpty()).forEach(System.out::println);
}

但是为了使用Stream的话,我们可以引用Stream依赖

//在Project build.gradle中添加
allprojects {
    repositories {
    //...
    maven { url 'https://jitpack.io' }
    }
}
//在Module app build.gradle 中添加 
implementation 'com.annimon:stream:1.2.1' 
  • 注:这里的Stream和java 8的Stream 包名是不一样的,这是一个非官方兼容方案为一个依赖库 ,不过语法是一样的,java 8的包名是java.util.stream.Stream,而依赖库的包是com.annimon.stream.Stream,这里需要大家在使用的时候注意。
  • 我们不能将我们Android API设置为24,那么这样是不可取的,使用选择一个依赖库也是完全可以解决需求的。

操作符使用

我们先来一个简单的例子

List<String> strings = Arrays.asList("1", "2", "2", "3", "4");
//输出list的元素
Stream.of(strings).forEach(System.out::println);

当然了,熟悉lambda表达式的同学肯定觉得这有什么好的呢?List也直接可以输出而且很方便呢?如下:

List<String> strings = Arrays.asList("1", "2", "2", "3", "4");
strings.forEach(System.out::println);

上面两个例子并没有让我们觉得Stream很牛逼是吧,不急,我们继续进行看看,Stream是不是很强大。

of

返回其元素为指定值的顺序有序流。

Stream<Integer> stream = Stream.of(1, 2, 3, 4);
System.out.println(stream.count()); //stream.count():返回此流中元素的数量。
输出:
4

map

返回一个流,该流包含将给定函数应用于此流的元素的结果,对数据类型的转换。

List<String> strings = Arrays.asList("1", "2", "2", "3", "4");
//将字符串转换为int输出
Stream.of(strings).map(Integer::parseInt).forEach(System.out::println);
输出:
1
2
2
3
4

mapToInt

返回一个IntStream,它包含将给定函数应用于此流的元素的结果。
相同的还有mapToLong、mapToDouble

List<String> strings = Arrays.asList("1", "2", "2", "3", "4");
Stream.of(strings).mapToInt(Integer::parseInt).forEach(System.out::println);
输出:
1
2
2
3
4

flatMap

返回一个流,该流包含将此流的每个元素替换为通过将提供的映射函数应用于每个元素而生成的映射流的内容的结果。对一组数据进行数据类型转换。

List<String> strings = Arrays.asList("1", "2", "2", "3", "4");
List<String> strings1 = Arrays.asList("a", "b", "c");
Stream.of(strings,strings1).flatMap(Stream::of).forEach(System.out::println);
输出:
1
2
2
3
4
a
b
c

filter

返回由与此给定谓词匹配的此流的元素组成的流。过滤器,如下下面例子过滤空字符串

List<String> strings = Arrays.asList("1", "2", "2", "", "3", "4");
Stream.of(strings).filter(s -> !s.isEmpty()).map(Integer::parseInt).forEach(System.out::println);
输出:
1
2
2
3
4

distinct

去除List重复的元素,返回由此流的不同元素(根据Object.equals(Object))组成的流。

List<String> strings = Arrays.asList("1", "2", "2", "", "3", "4");
Stream.of(strings).filter(s -> !s.isEmpty()).distinct().map(Integer::parseInt).forEach(System.out::println);
输出:
1
2
3
4

limit

返回由此流的元素组成的流,截断为长度不超过maxSize。如下maxSize=3时。

List<String> strings = Arrays.asList("1", "2", "2", "3", "4");
Stream.of(strings).limit(3).forEach(System.out::println);
输出:
1
2
2

skip

在丢弃流的前n个元素后,返回由此流的其余元素组成的流。如下n=3,则丢弃前面3个元素。

List<String> strings = Arrays.asList("1", "2", "2", "3", "4");
Stream.of(strings).skip(3).limit(3).forEach(System.out::println);
输出:
3
4

sorted

返回由此流的元素组成的流,按照自然顺序排序。默认为升序

List<String> strings = Arrays.asList("1", "5", "2", "6", "4");
Stream.of(strings).sorted().forEach(System.out::println);
输出:
1
2
4
5
6

allMatch

返回此流的所有元素是否与提供的断言匹配。boolean值

List<String> strings = Arrays.asList("1", "5", "2", "6", "4");
System.out.println(Stream.of(strings).allMatch(s -> strings.contains("a")));
输出:
false

System.out.println(Stream.of(strings).allMatch(s->strings.contains("1")));
输出:
true

anyMatch

返回此流的任何元素是否与提供的断言匹配。

List<String> strings = Arrays.asList("1", "5", "2", "6", "4");
System.out.println(Stream.of(strings).anyMatch(s -> s.contains("1")));
输出:
true

noneMatch

Stream 中没有一个元素符合传入的 断言

List<String> strings = Arrays.asList("1", "5", "", "6", "4");
System.out.println(Stream.of(strings).noneMatch(s -> s.contains("8")));
输出:
true

collect

输出为一个新的集合数据。

List<String> strings = Arrays.asList("1", "5", "", "6", "4");
List<String> strings1 = Stream.of(strings).filter(s -> !s.isEmpty()).collect(Collectors.toList());
strings1.forEach(System.out::println);
输出:
1
5
6
4

List<String> string = Arrays.asList("1", "5", "6", "6", "4");
Stream.of(string).filter(s -> !s.isEmpty()).collect(Collectors.toSet()).forEach(System.out::println);//Collectors.toSet() 不能出现重复元素,并进行排序输出。hashSet类似,但是Collectors.toSet()会进行排序
输出:
1
4
5
6

concat

创建一个延迟连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素。

List<String> strings = Arrays.asList("1", "5", "", "6", "4");
Stream strings1 = Stream.of(strings).filter(s -> !s.isEmpty());
List<String> string = Arrays.asList("8", "5", "6", "6", "4");
Stream strings2 = Stream.of(string).filter(s -> !s.isEmpty());
Stream.concat(strings1, strings2).forEach(System.out::println);
输出:
1
5
6
4
8
5
6
6
4

reduce

使用关联累加函数对此流的元素执行减少,并返回描述减少值的Optional(如果有)。

int sum = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
System.out.println(sumValue1);
int sum1 = Stream.of(1, 2, 3, 4).reduce(2, Integer::sum);//表示identity=2,即该sum的初始值,所以Stream中的总和等于2+(1+2+3+4)=12
System.out.println(sumValue);
输出:
10
12

sum、max、min

输出Stream流的和、最大值、最小值,返回的是Optional

System.out.println(Stream.of(1, 2, 3, 4).reduce(Integer::sum).get());
List<Integer> num = Arrays.asList(1, 3, 8, 5);
System.out.println(Stream.of(num).reduce(Integer::max).get());
System.out.println(Stream.of(num).reduce(Integer::min).get());
输出:
10
8
1

empy

返回一个空的顺序Stream。

Stream<Integer> stream = Stream.of(1, 2, 3, 4);
Stream<Integer> stream1 = stream.empty();
System.out.println(stream1.count());
输出:
0

findFirst

返回描述此流的第一个元素的Optional,如果流为空,则返回空Optional。

Stream<Integer> stream = Stream.of(1, 2, 3, 4);
System.out.println(stream.findFirst().get());
输出:
1

peek

返回由此流的元素组成的流,另外在每个元素上执行提供的操作,因为元素是从结果流中消耗的。

Stream<String> stream = Stream.of("a", "c", "C", "f");
List<String> list = stream.peek(e -> System.out.println("value: " + e)).map(String::toUpperCase).collect(Collectors.toList());
list.forEach(System.out::println);
输出:
value: a
value: c
value: C
value: f
A
C
C
F

toArray

Object[] array = Stream.of(1, 2, 3, 4).toArray();
Integer[] n = Stream.of(1, 2, 4, 5, 7, 3, 11).skip(3).toArray(Integer[]::new);
Stream.of(n).forEach(System.out::println);
输出:
5
7
3
11

下载

案例下载

总结

Stream 常用的操作符,我们在这里的案例都差别多测试了,是不是感觉Stream给我们的感觉是一种很棒的开发案例,我们可以在开发中使用它,这样方便我们对集合的操作。

可能有些同学看到第一个的时候就觉得在哪里见过?是的,没错,是不是和RxJava的操作符的作用差不多都是非常类似的。当然了,RxJava的操作是非常丰富的,希望大家可以多多去了解。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • 本文采用实例驱动的方式,对JAVA8的stream API进行一个深入的介绍。虽然JAVA8中的stream AP...
    浮梁翁阅读 25,597评论 3 50
  • Streams 的背景,以及 Java 8 中的使用详解 为什么需要 Stream Stream 作为 Java ...
    Java黎先生阅读 792评论 0 8
  • 转自: Java 8 中的 Streams API 详解 为什么需要 Stream Stream 作为 Java ...
    普度众生的面瘫青年阅读 2,892评论 0 11
  • 2018年的某一天,我的潜意识里冒出来有一种渴望改变自己的想法,但是不知道怎么改变,我都已经四十岁了,算了吧想的。...
    夏尔把提阅读 144评论 1 1