目标
-
Function<T, R>函数式接口
-
Predicate<T>函数式接口
-
流与集合相比的优点
-
流的延迟执行特点
-
集合、映射或数组获取流
-
常用的流操作
-
流进行并发操作:并行流
-
流中内容收集到集合中
collect
-
将流中内容收集到数组中
toArray();
主要内容
-
Predicate接口
-
Function接口
-
Stream流
第1章 常用函数式接口
1.1 Predicate接口
1.1.1 概述
需要对某种类型的数据进行判断,从而得到一个boolean值结果。则可以使用java.util.function.Predicate<T>
接口。
1.1.2 抽象方法:test
boolean test(T t) 根据参数t执行判断,返回true或false
-
test
方法示例:-
定义方法:参数是
Predicate
接口类型,返回值是boolean
类型 -
在
main
方法调用方法判断字符串长度是否大于5
-
public class PredicateDemo01 {
public static void main(String[] args){
// 使用匿名内部类调用
testPredicate(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length() > 5;
}
});
// 使用lambda表达式简化
testPredicate(s -> s.length()>5);
}
public static void testPredicate(Predicate<String> predicate){
boolean b = predicate.test("helloworld");
System.out.println(b);
}
}
1.1.3 默认方法:and
条件判断,则存在与、或、非三种常见逻辑关系。将两个Predicate
条件使用“与”逻辑连接起来实现“and”效果时,可以使用default方法and
。其JDK源码为:
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
-
and
方法演示示例-
判断一个字符串包含大写“H”,且包含大写“W”
-
public class PredicateDemo02 {
public static void main(String[] args) {
// 定义字符串
String str = "HelloWorld";
// 条件1:判断是否包含大写H
Predicate<String> one = s -> s.contains("H");
// 条件2:判断是否包含大写W
Predicate<String> two = s -> s.contains("W");
// 判断字符串是否同时满足条件1和条件2
// System.out.println(one.test(str) && two.test(str));
// 简化版
boolean b = one.and(two).test(str);
System.out.println(b);
}
}
1.1.4 默认方法:or
与and
的“与”类似,默认方法or
实现逻辑关系中的“或”。JDK源码为:
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
-
or
方法演示示例-
判断一个字符串包含大写H或者包含大写W”
-
public class PredicateDemo03 {
public static void main(String[] args) {
// 定义字符串
String str = "helloworld";
// 条件1:判断是否包含大写H
Predicate<String> one = s -> s.contains("H");
// 条件2:判断是否包含大写W
Predicate<String> two = s -> {
System.out.println("执行了吗");
return s.contains("W");
};
// 判断字符串是否满足条件1和条件2的其中一个
boolean b = one.or(two).test(str);
System.out.println(b);
}
}
1.3.5 默认方法:negate
默认方法negate
的JDK源代码为:
default Predicate<T> negate() {
return (t) -> !test(t);
}
negate ! : 执行test方法之后,对结果boolean值进行“!”取反。要在test
方法调用之前调用negate
方法,
与and
和or
方法一样:
import java.util.function.Predicate;
public class Demo17PredicateNegate {
private static void method(Predicate<String> predicate) {
boolean veryLong = predicate.negate().test("HelloWorld");
System.out.println("字符串很长吗:" + veryLong);
}
public static void main(String[] args) {
method(s -> s.length() < 5);
}
}
1.3.6 集合信息筛选
1. 需求说明
数组中有多条“姓名+性别”的信息如下,通过Predicate
接口的拼装将符合要求的字符串筛选到集合ArrayList
中
满足两个条件:
-
必须为女生;
-
姓名为4个字。
public class DemoPredicate {
public static void main(String[] args) {
String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };
}
}
2. 代码实现
public class PredicateDemo05 {
public static void main(String[] args) {
String[] array = { "迪丽热巴,女", "古力娜扎,女", "马尔扎哈,男", "赵丽颖,女" };
// 条件1:必须是女生
// boolean test(String t)
Predicate<String> one = s -> s.split(",")[1].equals("女");
// 条件2:姓名为4个字
Predicate<String> two = s -> s.split(",")[0].length() == 4;
// 遍历数组
for (String str : array) {
// 判断str是否同时满足条件1和条件2
if(one.and(two).test(str)){
System.out.println(str);
}
}
}
}
1.2 Function接口
1.2.1 概述
java.util.function.Function<T,R>`接口用于根据一个类型的数据得到另一个类型的数据,前者称为前置条件,后者称为后置条件。有进有出,所以称为“函数Function”。
1.2.2 抽象方法:apply
R apply(T t) 将参数t的类型从T类型转换为R类型。
-
apply
方法示例:将String
类型转换为Integer
类型。
public class FunctionDemo01 {
public static void main(String[] args){
// 字符串数字
String str = "100";
// 将字符串数字转换为整型数字
Function<String,Integer> f = new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.parseInt(s);
}
};
int num = f.apply(str);
System.out.println(num);
// 使用lambda简化匿名内部类
// Integer apply(String t)
Function<String,Integer> f1 = s -> Integer.parseInt(s);
System.out.println(f1.apply("200"));
// 使用方法引用简化lambda表达式
Function<String,Integer> f2 = Integer::parseInt;
System.out.println(f2.apply("300"));
}
}
1.2.3 默认方法:andThen
Function
接口中有一个默认的andThen
方法,用来进行组合操作。JDK源代码如:
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
-
andThen
方法示例:第一个操作是将字符串解析成为int数字,第二个操作是乘以10。两个操作按照前后顺序组合到一起。
public class FunctionDemo02 {
public static void main(String[] args){
// 字符串
String str = "250";
// 操作1:将字符串转换基本数据类型:"250" ==> 250
Function<String,Integer> one = Integer::parseInt;
// 操作2:将操作1执行的结果乘以10
Function<Integer,Integer> two = num -> num * 10;
// 执行操作1和操作2
/* int num = one.apply(str);
int result = two.apply(num);*/
// 执行操作1和操作2:将前一个操作执行的结果作为后一个操作的参数
int result = one.andThen(two).apply(str);
System.out.println(result);
}
}
1.2.4 自定义函数模型拼接
1. 需求说明
使用Function
进行函数模型拼接,按照顺序需要执行的多个函数操作为:
-
将字符串
赵丽颖,20
截取数字年龄部分,得到字符串; -
将上一步的字符串转换成为int类型的数字;
-
将上一步的int数字累加100,得到结果int数字。
2. 代码实现
public class FunctionDemo03 {
public static void main(String[] args){
// 字符串
String str = "赵丽颖,20";
// 操作1:"赵丽颖,20" ==> "20"
Function<String,String> one = s -> s.split(",")[1];
// 操作2:"20" ==> 20
Function<String,Integer> two = Integer::parseInt;
// 操作3:20 ==> 120
Function<Integer,Integer> three = num ->{
System.out.println("执行了吗");
return num + 100;
};
// 按顺序执行三个操作
int result = one.andThen(two).andThen(three).apply(str);
// int result = three.compose(two).compose(one).apply(str);
System.out.println(result);
}
}
1.3 总结:延迟方法与终结方法
常用函数式接口中,方法可分为两种:
-
延迟方法:在拼接Lambda函数模型的方法,并不立即执行得到结果。
-
终结方法:根据拼好的Lambda函数模型,立即执行得到结果值的方法。
通常情况下,常用的函数式接口中唯一的抽象方法为终结方法,而默认方法为延迟方法。但这并不是绝对的。
表格中进行方法分类的整理:
接口名称 | 方法名称 | 抽象/默认 | 延迟/终结 |
---|---|---|---|
Supplier | get | 抽象 | 终结 |
Consumer | accept | 抽象 | 终结 |
andThen | 默认 | 延迟 | |
Predicate | test | 抽象 | 终结 |
and | 默认 | 延迟 | |
or | 默认 | 延迟 | |
negate | 默认 | 延迟 | |
Function | apply | 抽象 | 终结 |
andThen | 默认 | 延迟 | |
compose | 默认 | 延迟 |
备注:JDK中更多内置的常用函数式接口,请参考
java.util.function
包的API文档。
第2章 Stream流
1.1 引言
JDK1.8更新最大的亮点除lamada表达式之外,还有极其惊艳的Stream。但Stream不是IO里面的OutputStream或InputStream之类,而是对java中Collection类功能的增强。Stream API配合lamada表达式,极大的提升了编程效率和程序可读性。Stream中支持并行和串行两种方式。
1.2 Stream流引入案例
-
有如下集合
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
-
按要求执行以下三个操作
-
首先筛选所有姓张的人。
-
然后筛选名字有三个字的人。
-
最后进行对结果进行打印输出。
-
1.2.1 JDK1.8之前的实现方式
public class StreamDemo01 {
public static void main(String[] args){
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
List<String> oneList = new ArrayList<>();
// 使用jdk1.8之前的方式实现
for (String str : list) {
// 判断是否是姓张的
if(str.startsWith("张")){
oneList.add(str);
}
}
List<String> twoList = new ArrayList<>();
for (String name : oneList) {
// 判断是否是三个字
if (name.length() == 3){
twoList.add(name);
}
}
/* // 打印输出twoList集合的元素
for (String name : twoList) {
System.out.println(name);
}
*/
}
}
jdk1.8前:
对集合中的元素进行操作的时,总需要对集合进行多次循环。尤其是:使用线性循环时,意味着只能遍历一次。如果希望再次遍历,只能再使用另一个循环从头开始。
jdk1.8后:
Lambda的衍生物Stream可直接遍历独个循环,未使用到的循环遍历可延迟执行.
1.2.2 Stream流的demo
public class StreamDemo02 {
public static void main(String[] args){
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
// 使用Stream流实现
list.stream()
.filter(s->{
return s.startsWith("张");
})
.filter(s->{
return s.length() == 3;
})
.forEach(System.out::println);
}
}
直接阅读代码的字面意思即可完美展示无关逻辑方式的语义:获取流、过滤姓张、过滤长度为3、逐一打印。
1.3 获取流的方式
java.util.stream.Stream<T>
是Java 8新加入的最常用的流接口。(这并不是一个函数式接口。)
获取一个流
常用方式:
-
所有的
Collection
集合都可以通过stream
默认方法获取流; -
Stream
接口的静态方法of
可以获取数组对应的流。
1.5.1 根据Collection获取流
java.util.Collection
接口中加入了default方法stream
用来获取流,所以其所有实现类均可获取流。
调用集合对象的stream()方法获得Stream对象
1.5.2 根据Map获取流
java.util.Map接口不是
Collection`的子接口,且其K-V数据结构不符合流元素的单一特征,所以获取对应的流需要分key、value或entry等情况:
// 获得键对应Stream流对象
Stream<String> keyStream = map.keySet().stream();
// 获得值对应Stream流对象
Stream<String> valueStream = map.values().stream();
// 获得Entry对象对应Stream流对象
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
1.5.3 根据数组获取流
如果使用的不是集合或映射而是数组,由于数组对象不添加默认方法.
所以Stream
接口中提供静态方法of
:
使用Demo:
* 通过Stream接口的静态方法of来获得
// 字符串数组
String[] strs = {"a"};
// 获得流关联数组
Stream<String> arrayStream = Stream.of(strs);
1.5.4 示例代码
public class StreamDemo01 {
public static void main(String[] args){
// 创建List集合
List<String> list = new ArrayList<>();
// 获得流对象
Stream<String> stream01 = list.stream();
// 创建Set集合
Set<String> set = new HashSet<>();
Stream<String> stream02 = set.stream();
// 创建Map集合
Map<String,String> map = new HashMap<>();
// 获得键对应Stream流对象
Stream<String> keyStream = map.keySet().stream();
// 获得值对应Stream流对象
Stream<String> valueStream = map.values().stream();
// 获得Entry对象对应Stream流对象
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
// 字符串数组
String[] strs = {"a"};
// 获得流关联数组
Stream<String> arrayStream = Stream.of(strs);
// 直接创建流对象
Stream<String> a = Stream.of("a", "b");
}
}
1.4 Stream常用方法
流操作常用方法
分成两种:
-
终结方法
-
非终结方法
1.4.1 过滤:filter
1.4.1.1 方法声明
Stream<T> filter(Predicate<T> predicate)
* 将流中满足条件的元素添加到另一个流中,返回新的流
1.4.1.2 Predicate接口
java.util.stream.Predicate
函数式接口,其中唯一的抽象方法为:
boolean test(T t);
该方法将会产生一个boolean值结果,判断指定的条件是否满足。条件结果为true,则Stream流的filter
方法将留用元素;条件结果为false,则filter
方法将会舍弃元素。
1.4.1.3 基本使用
Stream流中的filter
方法基本使用代码如:
public class StreamDemo02 {
public static void main(String[] args){
// 创建流对象
Stream<String> stream01 = Stream.of("abc", "bbxx", "abcde");
// Predicate函数式接口的抽象方法:boolean test(T t)
Stream<String> stream02 = stream01.filter(s -> s.length() >= 4);
// 获得流的元素个数并输出
System.out.println(stream02.count());
}
}
1.4.2 统计个数:count
1.4.2.1 方法声明如下
long count()
* 获得流中元素的个数
1.4.2.2 基本使用
Stream流中的count
方法基本使用代码如:
public class StreamDemo02 {
public static void main(String[] args){
// 创建流对象
Stream<String> stream01 = Stream.of("abc", "bbxx", "abcde");
// Predicate函数式接口的抽象方法:boolean test(T t)
Stream<String> stream02 = stream01.filter(s -> s.length() >= 4);
// 获得流的元素个数并输出
System.out.println(stream02.count());
}
}
1.4.3 获取前几个:limit
1.4.3.1 方法声明如下
Stream<T> limit(long maxSize)
* 将流中前maxSize个元素获取到另一个流中
* maxSize等于零,则会获取一个空流。
* maxSize大于当前流中元素个数,则会将当前流的所有元素获取到另一个流中
* maxSize必须大于等于0
1.4.3.2 基本使用
Stream流中的limit
方法基本使用代码如:
public class StreamDemo03 {
public static void main(String[] args){
// 创建流对象
Stream<String> stream01 = Stream.of("abc", "dbc", "dde","abe");
// 获取前2个元素放到另一个流中
Stream<String> stream02 = stream01.limit(5);
System.out.println(stream02.count());
}
}
1.4.4 跳过前几个:skip
1.4.4.1 方法声明如下
Stream<T> skip(long n)
* 跳过当前流中的前n个元素,将前n个元素后的所有元素添加到另一流中,返回新流。
* n必须大于等于0
* n大于当前流中的元素个数,则会产生一个空流。
1.4.4.2 基本使用
public class StreamDemo04 {
public static void main(String[] args){
// 创建流对象
Stream<String> stream01 = Stream.of("abc", "dbc", "dde","abe");
// 跳过当前流中的前1个元素,
Stream<String> stream02 = stream01.skip(5);
System.out.println(stream02.count());
}
}
1.4.5 映射:map
使用map操作遍历集合中的每个对象,并对遍历结果进行处理,map之后用.collect(Collectors.toList())会得到操作后的集合。方法声明如下
* Stream<R> map(Function<T,R> mapper)
* 将当前流中元素的类型从T类型转换为R类型,存储到另一个流中返回
该接口需要一个Function
函数式接口参数,可以将当前流中的T类型数据转换为另一种R类型的流。
1.4.5.1 Function接口
java.util.stream.Function
函数式接口,其中唯一的抽象方法为:
R apply(T t);
将一种T类型转换成为R类型,而这转换的过程,则称为“映射”。
1.4.5.2 基本使用
Stream流中的map
方法基本使用的代码如:
public class StreamDemo05 {
public static void main(String[] args){
// 创建流对象
Stream<String> stream01 = Stream.of("aaa", "456", "789","12345");
// 将流中的字符串都转换为整型存储到另一个流中
// Function函数式接口的抽象方法:R apply(T t)
Stream<Integer> stream02 = stream01.map(str -> {
System.out.println(str);
return Integer.parseInt(str);
});
System.out.println(stream02.count());
}
}
1.4.6 组合:concat
1.4.6.1 方法声明如下
concat方法的声明如下:
* static <T> Stream<T> oncat(Stream<T> a, Stream<T> b)
* 将流a和流b合并为一个流
1.4.6.2 基本使用
public class StreamDemo06 {
public static void main(String[] args){
// 创建流对象
Stream<String> streamA = Stream.of("aaa", "456", "789","12345");
Stream<String> streamB = Stream.of("aaa", "456", "789","12345");
// 合并流中元素产生新的流
Stream<String> streamC = Stream.concat(streamA, streamB);
// 将流中的元素传递给消费者逐一处理
streamC.forEach(System.out::println);
}
}
1.4.7 逐一处理:forEach
1.4.7.1 方法声明如下
void forEach(Consumer c);
* 将流中的元素传递给消费者逐一处理
1.4.7.2 基本使用
public class StreamDemo07 {
public static void main(String[] args){
// 创建流对象
Stream<String> streamA = Stream.of("aaa", "456", "789","12345");
// 将流中的元素传递给消费者逐一处理
streamA.forEach(System.out::println);
}
}
方法引用System.out::println便是一个
Consumer`函数式接口的实例。
1.5 小结:非终结方法与终结方法
在上述介绍的各种方法中,凡是返回值仍然为Stream
接口的为非终结方法(函数拼接方法),它们支持链式调用;而返回值不再为Stream
接口的为终结方法,不再支持链式调用。如下表所示:
方法名 | 方法作用 | 方法种类 | 是否支持链式调用 |
---|---|---|---|
count | 统计个数 | 终结 | 否 |
forEach | 逐一处理 | 终结 | 否 |
filter | 过滤 | 函数拼接 | 是 |
limit | 取用前几个 | 函数拼接 | 是 |
skip | 跳过前几个 | 函数拼接 | 是 |
map | 映射 | 函数拼接 | 是 |
concat | 组合 | 函数拼接 | 是 |
1.6 案例
-
案例说明
现在有两个ArrayList
集合存储队伍当中的多个成员姓名
两个队伍(集合)的代码如下:
import java.util.ArrayList;
import java.util.List;
public class DemoArrayListNames {
public static void main(String[] args) {
List<String> one = new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("老子");
one.add("庄子");
one.add("孙子");
one.add("洪七公");
List<String> two = new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("张三丰");
two.add("赵丽颖");
two.add("张二狗");
two.add("张天爱");
two.add("张三");
// ....
}
}
而Person
类的代码如下
public class Person {
private String name;
public Person() {}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{name='" + name + "'}";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
要求如下:
-
使用传统的for循环(或增强for循环)依次进行以下若干操作步骤
-
使用Stream方式依次进行以下若干操作步骤
1. 第一个队伍只要名字为3个字的成员姓名;
2. 第一个队伍筛选之后只要前3个人;
3. 第二个队伍只要姓张的成员姓名;
4. 第二个队伍筛选之后不要前2个人;
5. 将两个队伍合并为一个队伍;
6. 根据姓名创建Person对象;
7. 打印整个队伍的Person对象信息。
1.6.1 Stream流方式
public class StreamDemo01 {
public static void main(String[] args) {
List<String> one = new ArrayList<>();
one.add("迪丽热巴");
one.add("宋远桥");
one.add("苏星河");
one.add("老子");
one.add("庄子");
one.add("孙子");
one.add("洪七公");
List<String> two = new ArrayList<>();
two.add("古力娜扎");
two.add("张无忌");
two.add("张三丰");
two.add("赵丽颖");
two.add("张二狗");
two.add("张天爱");
two.add("张三");
// ....
// 1. 第一个队伍只要名字为3个字的成员姓名;
// 2. 第一个队伍筛选之后只要前3个人;
Stream<String> oneStream = one.stream()
.filter(s -> s.length() == 3)
.limit(3);
// 3. 第二个队伍只要姓张的成员姓名;
// 4. 第二个队伍筛选之后不要前2个人;
Stream<String> twoStream = two.stream()
.filter(s -> s.startsWith("张"))
.skip(2);
// 5. 将两个队伍合并为一个队伍;
// 6. 根据姓名创建Person对象;
// 7. 打印整个队伍的Person对象信息。
Stream.concat(oneStream, twoStream)
.map(Person::new)
.forEach(System.out::println);
}
}
1.7 收集Stream结果
对流操作完成之后,则需要将其结果进行收集.
1.7.1 收集到集合中
Stream流提供collect
方法,其参数需要一个java.util.stream.Collector<T,A, R>
接口对象来指定收集到哪种集合中。java.util.stream.Collectors 类提供一些方法,可以作为
Collector`接口的实例:
public static <T> Collector<T, ?, List<T>> toList():转换为List集合。
public static <T> Collector<T, ?, Set<T>> toSet():转换为Set集合。
基本使用
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Demo15StreamCollect {
public static void main(String[] args) {
Stream<String> stream = Stream.of("10", "20", "30", "40", "50");
List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
}
}
1.7.2 收集到数组中
Stream提供toArray
方法来将结果放到一个数组中,由于泛型擦除的原因,返回值类型是Object[]的:
Object[] toArray();
基本使用
import java.util.stream.Stream;
public class Demo16StreamArray {
public static void main(String[] args) {
Stream<String> stream = Stream.of("10", "20", "30", "40", "50");
Object[] objArray = stream.toArray();
}
}
解决泛型数组问题
有了Lambda和方法引用之后,可以使用toArray
方法的另一种重载形式传递一个IntFunction<A[]>
的函数,继而从外面指定泛型参数。方法声明如下:
<A> A[] toArray(IntFunction<A[]> generator);
上例代码中不再局限于Object[]
结果,则可以得到String[]
结果:
import java.util.stream.Stream;
public class Demo17StreamArray {
public static void main(String[] args) {
Stream<String> stream = Stream.of("10", "20", "30", "40", "50");
String[] strArray = stream.toArray(String[]::new);
}
}
既然数组是有构造器的,则传递一个数组的构造器引用即可。
1.8 并发流
以上例子中使用的是串行流,即单线程执行的,其实Stream API中提供有并行流,即多线程执行操作。
java.util.Collection<E>
新添加两个默认方法
-
default Stream stream() : 返回串行流
-
default Stream parallelStream() : 返回并行流
stream()
和parallelStream()
方法返回的均是java.util.stream.Stream<E>
类型的对象,则说明它们在功能的使用上是没差别的。唯一的差别就是单线程和多线程的执行。
1.8.1 串行流转换为并发流
Stream
的父接口java.util.stream.BaseStream
中定义一个parallel
方法:
S parallel();
在流上调用一下无参数的parallel
方法,则当前流即可改变成为支持并发操作的流,返回值仍然为Stream
类型。例如:
import java.util.stream.Stream;
public class Demo13StreamParallel {
public static void main(String[] args) {
Stream<Integer> stream = Stream.of(10, 20, 30, 40, 50).parallel();
}
}
1.8.2 直接获取并发流
在通过集合获取流时,可以直接调用parallelStream
方法来直接获取支持并发操作的流。方法定义为:
default Stream<E> parallelStream() {...}
应用代码为:
import java.util.ArrayList;
import java.util.Collection;
import java.util.stream.Stream;
public class Demo13StreamParallel {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>();
Stream<String> stream = coll.parallelStream();
}
}
1.8.3 并发流基本使用
/**
* @author pkxing
* @version 1.0
* @description 并发流
* @date 2018/3/5
*/
public class StreamDemo02 {
@Test
public void testStream() {
List<Integer> list = new ArrayList<>();
// 将1000-1存入list中
for (int i = 1000; i >= 1; i--) {
list.add(i);
}
// 使用串行流:不开线程执行,在当前线程执行
// List<String> result = list.stream()
// .map((i)-> {
// System.out.println("i = " +Thread.currentThread().getName());
// return String.valueOf(i);
// }).collect(Collectors.toList());
// 使用并发流:开多个线程执行
List<String> result = list.parallelStream()
.map((i)-> {
System.out.println("i = " +Thread.currentThread().getName());
return String.valueOf(i);
}).collect(Collectors.toList());
System.out.println(result);
}
}