Java函数式编程入门

Java函数式编程入门

Lambda表达式

Lambda 表达式介绍

是没有声明的方法,也即没有访问修饰符、返回值声明和名字。

一般使用场景

当某个方法只使用一次,而且定义很简短,使用这种速记替代之尤其有效。

Lambda 表达式语法

当方法没有形参的时候,使用 () 表示

1
() -> log.info("hehe");

当方法只有一个形参的时候,可以直接省略括号

1
p -> log.info("number : {}",p);

当方法有多个参数时,需要使用 () 括起来

1
(a,b) -> return a + b;

参数可以省略类型,也可以写上

1
2
3
4
5
(a,b) -> return a + b;

//等同于

(int a ,int b) -> return a + b;

通过两个例子初步体验 Lambda

创建一个线程

1
2
3
4
5
6
7
8
9
10
11
//        原写法
// new Thread(new Runnable() {
// @Override
// public void run() {
// log.info("hello lambda");
// }
// }).start();

// 使用 lambda 表达式创建一个线程
Thread thread = new Thread(() -> log.info("hello lambda"));
thread.start();

实现 List 排序

1
2
3
4
5
6
7
8
9
10
11
12
        List<String> list = Arrays.asList(new String[]{"y","z","x"});

// 原写法
// Collections.sort(list, new Comparator<String>() {
// @Override
// public int compare(String o1, String o2) {
// return o1.compareTo(o2);
// }
// });

// 使用 lambda 表达式 完成排序
Collections.sort(list,(o1,o2) -> o1.compareTo(o2));

深入解析 Lambda

Lambda 本身是语法糖,起的作用是重写函数式接口(只包含一个抽象方法声明的接口) 的抽象方法,Java中常用到的比如Comparator或者Runnable接口,这些接口都增加了@FunctionalInterface 注解以便能用在lambda上。

1
2
3
// new Runnable 只有 run 一个抽象方法,这里是 Lambda 的语法糖效果,自动重写了这个抽象方法
Thread thread = new Thread(() -> log.info("hello lambda"));
thread.start();

通过一个自定义函数式接口来理解 Lambda

使用 @FunctionalInterface 来声明一个接口是函数式接口,该注解只能标记在”有且仅有一个抽象方法”的接口上,但它不是必须的,只是为了编译器更好地检测

1
2
3
4
5
6
7

//函数式接口
@FunctionalInterface
public interface LambdaInterface {
// 一个求和抽象方法,当然后面重写可以自定义,不一定是求和
public Integer sum(int a ,int b);
}

一个调用这个函数式接口的类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

import com.zyy.consumer.bean.User;
import lombok.Data;

import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

// lombok 中 @Data ,自动填充 setter 和 getter
@Data
public class FirstLambda {

private Integer first;

private Integer second;

public Integer getSum(LambdaInterface lambdaInterface){
return lambdaInterface.sum(first,second);
}

}

开始表演

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   @Test
public void testLambdaInterface() {
Integer c = 0;
FirstLambda firstLambda = new FirstLambda();
firstLambda.setFirst(22);
firstLambda.setSecond(33);

// 原生态操作
// c = firstLambda.getSum(new LambdaInterface() {
// @Override
// public Integer sum(int a, int b) {
// return a + b;
// }
// });

// 这个时候我们可以使用箭头函数去重写 sum 的实现
c = firstLambda.getSum((a,b) -> {return a + b;});

log.info("number : {}",c);
}

java.util.function 包

使用场景

由于这个包都是 函数式接口,和 Lambda 搭配使用效果更佳

拥有的方法

参考:https://blog.csdn.net/huo065000/article/details/78964382

name type description
Consumer Consumer< T > 接收T对象,不返回值
Predicate Predicate< T > 接收T对象并返回boolean
Function Function< T, R > 接收T对象,返回R对象
Supplier Supplier< T > 提供T对象(例如工厂),不接收值
UnaryOperator UnaryOperator< T > 接收T对象,返回T对象
BiConsumer BiConsumer<T, U> 接收T对象和U对象,不返回值
BiPredicate BiPredicate<T, U> 接收T对象和U对象,返回boolean
BiFunction BiFunction<T, U, R> 接收T对象和U对象,返回R对象
BinaryOperator BinaryOperator< T > 接收两个T对象,返回T对象

###


具体操作

Predicate 用于实现一个条件语句,而 Consumer 用于实现操作,不返回值,两者往往搭配使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

import com.zyy.consumer.bean.User;
import lombok.Data;

import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;

@Data
public class FirstLambda {

private Integer first;

private Integer second;

public Integer getSum(LambdaInterface lambdaInterface){
return lambdaInterface.sum(first,second);
}

// 写一个 筛选list 的方法
public void checkNumberBigger(List<Integer> list,Predicate<Integer> predicate,Consumer<Integer> consumer){
for(Integer integer : list){
if(predicate.test(integer)){
consumer.accept(integer);
}
}

}
}

调用该方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    @Test
public void testLambdaPredicate(){
List<Integer> list = new ArrayList<>();
for(int i = 0 ; i < 10;i++){
list.add(i);
}

// 这里重写了 Predicate 的test 方法,以完成逻辑的判断,重写了 Consumer 的 accept 方法,完成处理操作
new FirstLambda().checkNumberBigger(list,
p -> p > 5,
p -> log.info("number : {}",p));
}

// 此时 Predicate

boolean test(Integer p){
return p > 5 ? true : false;
}

// 此时 Consumer

void accept(Integer p){
log.info("number : {}",p))
}

Function<R,T> 类似一个一元函数,通过输入一个 R 类型的参数,通过处理以后 返回 T 类型的返回值,这里的使用例子是通过输入的字符串 返回 该字符串的长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 之前 FirstLambda 中新的方法
public Integer getStringLength(String string,Function<String,Integer> function){
return function.apply(string);
}

// 测试该方法
@Test
public void testFunction(){
FirstLambda firstLambda = new FirstLambda();
Integer length = firstLambda.getStringLength("Hello World",
p -> {return p.length();});

log.info("length : {}",length);
}

Function 中 compose 可以结合两个函数,以下是它的源码

1
2
3
4
5
// 可以看出,它是依赖于apply类的,所以这不是一个抽象方法,不影响函数式接口的定义,本质是执行完before 方法以后,继续执行this.apply,从而实现两个函数结合使用    
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}

实例就采用先进行字符串处理,在计算字符串大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 之前 FirstLambda 中新的方法
public Integer getStringLengthSecond(String string,Function<String,String> before,Function<String,Integer> function){
return function.compose((Function<? super String, ? extends String>) before).apply(string);
}

// 测试该方法
@Test
public void testFunctionCompose(){
FirstLambda firstLambda = new FirstLambda();

Integer length = firstLambda.getStringLengthSecond("Hello",
p -> {return p + " World";},
p -> {return p.length();});

log.info("length : {}",length);
}

Function 中 的 andThen 方法则是先执行 this 方法,再去执行 after 方法,也是结合两个Function

1
2
3
4
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}

测试例子是先求字符串的和,再将长度加上100

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 之前 FirstLambda 中新的方法
public Integer getStringLengthThird(String string,Function<Integer,Integer> after,Function<String,Integer> function){
return function.andThen(after).apply(string);
}


// 测试该方法
@Test
public void testFunctionAndThen(){
FirstLambda firstLambda = new FirstLambda();

Integer length = firstLambda.getStringLengthThird("Hello World",
p -> {return p + 100;},
p -> {return p.length();});

log.info("length : {}",length);
}

Supplier 不接受参数,表示一个工厂类,实现工厂的作用,下面是调用User的静态方法返回实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// User 类
import lombok.Data;

@Data
public class User {
private String name;
private Integer age;
private Double weight;
private String sexy;
private Double height;

public static User getSimpleUser(){
User user = new User();
user.setName("simple");
user.setSexy("male");
user.setAge(21);
return user;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 之前 FirstLambda 中新的方法
public User getUser(Supplier<User> supplier){
return supplier.get();
}

// 测试该方法
@Test
public void testSupplier(){
FirstLambda firstLambda = new FirstLambda();

User user = firstLambda.getUser(() -> {return User.getSimpleUser();});

log.info("user : {}",user);
}

UnaryOperatorFuntion 有些相似,不同的是它只能返回传入参数同种类型的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
   // 对字符串进行加工
public String getString(String string,UnaryOperator<String> unaryOperator){
return unaryOperator.apply(string);
}

// 实现实例
@Test
public void testUnaryOperator(){
FirstLambda firstLambda = new FirstLambda();

String string = firstLambda.getString("Hello",
p -> {return p + " World!!!";});

log.info("string : {}",string);
}

BiConsumerConsumer 多接收了一个参数

1
2
3
4
5
6
7
8
9
10
11
12
13
// 拼接一个名字
public void getName(String firstName,String secondName,BiConsumer<String,String> biConsumer){
biConsumer.accept(firstName,secondName);
}

//
@Test
public void testBiConsumer(){
FirstLambda firstLambda = new FirstLambda();

firstLambda.getName("Macro","Reus",
(a,b) -> log.info("{} {}",a,b));
}

BiPredicatePredicate 多接受一个参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 找出年龄较大的一位
public String getOlderUser(User first,User second,BiPredicate<User,User> biPredicate,Function<User,String> function){
if(biPredicate.test(first,second)){
return function.apply(first);
}else{
return function.apply(second);
}
}

@Test
public void testBiPredicate(){
FirstLambda firstLambda = new FirstLambda();
User first = new User();
first.setName("Ke");
first.setAge(22);
User second = new User();
second.setAge(21);
second.setName("Liang");
// 找出两个User中年龄较大的User的名字
String name = firstLambda.getOlderUser(first,second,
(a,b) -> {return a.getAge() >= b.getAge();},
p -> {return p.getName();});

log.info("user : {}",name);
}

BiFunction 相比于 Function 多接收一个参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 计算矩形面积
public Double getArea(Double length,Double width,BiFunction<Double,Double,Double> biFunction){
return biFunction.apply(length,width);
}

//测试实例
@Test
public void testBiFunction(){
FirstLambda firstLambda = new FirstLambda();

Double length = 2.2;

Double width = 5.1;

Double area = firstLambda.getArea(length,width,
(a,b) -> {return a * b;});

log.info("area : {}",area);
}

BinaryOperator 用法同上,只不过只能操作一种类型的参数


Optional 类

实际用处

函数式编程中,用于处理 空指针异常 (NullPointerException)

常用方法

方法 说明
public static Optional of(T value) 为非null的值创建一个Optional
public static Optional ofNullable(T value) 为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional
public boolean isPresent() 如果值存在返回true,否则返回false
public T get() 如果Optional有值则将其返回,否则抛出NoSuchElementException
public void ifPresent(Consumer<? super T> consumer) 如果Optional实例有值则为其调用consumer,否则不做处理
public T orElse(T other) 如果有值则将其返回,否则返回指定的其它值
public T orElseGet(Supplier<? extends T> other) orElseGet与orElse方法类似,区别在于得到的默认值
public T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X 如果有值则将其返回,否则抛出supplier接口创建的异常
public Optional map(Function<? super T, ? extends U> mapper) 如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。
public Optional flatMap(Function<? super T, Optional> mapper) 如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。
public Optional filter(Predicate<? super T> predicate) 如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional

具体实现

使用 of 创建一个 Optional ,传入的值不能为 NULL,否则抛出 NullPointerException

1
2
3
4
5
@Test
public void testOf(){
Optional<String> optional = Optional.of("Ke");
log.info("optional : {}",optional);
}

使用 ofNullable 创建一个 Optional ,如果传入一个 NULL ,则返回空的Optional

1
2
3
4
5
6
7
8
@Test
public void testOfNullable(){
Optional<String> optionalFirst = Optional.ofNullable("Liang");
Optional<String> optionalSecond = Optional.ofNullable(null);

log.info("first : {}",optionalFirst); // first : Optional[Liang]
log.info("second ; {}",optionalSecond); // second ; Optional.empty
}

使用 isPresent 判定 Optional 是否为空

1
2
3
4
5
6
7
8
@Test
public void testOfNullable(){
Optional<String> optionalFirst = Optional.ofNullable("Liang");
Optional<String> optionalSecond = Optional.ofNullable(null);

log.info("firstIsNull : {}",optionalFirst.isPresent()); // true
log.info("secondIsNull : {}",optionalSecond.isPresent()); // false
}

使用 get 获取值,如果值不存在,抛出 NoSuchElementException

1
2
3
4
5
6
7
8
9
@Test
public void testOfNullable(){
Optional<String> optionalFirst = Optional.ofNullable("Liang");
Optional<String> optionalSecond = Optional.ofNullable(null);

log.info("first : {}",optionalFirst.get()); // first : Liang
log.info("second ; {}",optionalSecond.get()); // java.util.NoSuchElementException: No value present

}

使用 ifPresent 实现函数式编程,如果值存在,则执行 Consumer

1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void testIfPresent(){
Optional<String> optionalFirst = Optional.ofNullable("Liang");
Optional<String> optionalSecond = Optional.ofNullable(null);

optionalFirst.ifPresent(
p -> log.info("firstValue : {}",p) // firstValue : Liang
);

optionalSecond.ifPresent(
p -> log.info("secondValue : {}",p)
);
}

使用 orElse 有值则返回,无值则指定其他值

1
2
3
4
5
@Test
public void testOrElse(){
Optional<String> optional = Optional.ofNullable(null);
log.info("optional : {}",optional.orElse("NULL")); // optional : NULL
}

使用 orElseGet 可以结合函数式编程使用,无值则使用 Supplier 工厂返回

1
2
3
4
5
6
7
8
9
@Test
public void testOrElseGet(){
Optional<User> optional = Optional.ofNullable(null);

log.info("optional : {}",optional.orElseGet(
() -> {return User.getSimpleUser();}
));
// optional : User(name=simple, age=21, weight=null, sexy=male, height=null)
}

使用 orElseThrow 结合函数式编程,无值则使用 Supplier 抛出异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Test
public void testOrElseThrow(){
Optional<User> optional = Optional.ofNullable(null);

try{
log.info("optional : {}",optional.orElseThrow(
() -> {return new ArithmeticException();}
));
}catch (ArithmeticException a){
log.info("error"); // error
}
}

@Test
public void testOrElseThrow(){
User user = new User();
user.setName("Kabin");
Optional<User> optional = Optional.ofNullable(user);
// optional : User(name=Kabin, age=null, weight=null, sexy=null, height=null)
try{
log.info("optional : {}",optional.orElseThrow(
() -> {return new ArithmeticException();}
));
}catch (ArithmeticException a){
log.info("error");
}
}

使用 map 来结合 Function 实现 对值的处理

1
2
3
4
5
6
7
8
  @Test
public void testMap(){
Optional<String> optional = Optional.ofNullable("Hello");
// optional : Optional[Hello World!!!]
log.info("optional : {}",optional.map(
p -> {return p + " World!!!";}
));
}

使用 flatMap 来结合 Function,不同的地方在于如果为 NULL,则返回空的 Optional

1
2
3
4
5
6
7
8
@Test
public void testFlatMap(){
Optional<String> optional = Optional.ofNullable(null);
// optional : Optional.empty
log.info("optional : {}",optional.map(
p -> {return p + " World!!!";}
));
}

使用 filter 来结合 Predicate 完成过滤处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    @Test
public void testFilter(){
List<Optional<Integer>> list = new ArrayList<>();

for(int i = 0 ;i < 10 ;i ++){
Optional<Integer> optional = Optional.ofNullable(i);
list.add(optional);
}

list.forEach(
p -> log.info("optional : {}",
p.filter(
q -> {return q >=5;}
)
)
);
}

2018-12-16 16:01:24.262 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional.empty
2018-12-16 16:01:24.262 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional.empty
2018-12-16 16:01:24.262 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional.empty
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional.empty
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional.empty
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional[5]
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional[6]
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional[7]
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional[8]
2018-12-16 16:01:24.263 INFO 11424 --- [ main] com.zyy.consumer.OptionalTest : optional : Optional[9]

最为有效的用途之一

连环夺命 NULL 判定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    @Test
public void testOptional(){
// 获取 User 类中的 name 并且转换为大写,进行 NULL 判定
Optional<User> optional = Optional.ofNullable(User.getSimpleUser());

// name : SIMPLE
log.info("name : {}",
optional.map(
p -> {return p.getName();}
).map(
q -> {return q.toUpperCase();}
).orElse(null)
);
}

@Test
public void testOptional(){
// 获取 User 类中的 name 并且转换为大写,进行 NULL 判定
Optional<User> optional = Optional.ofNullable(null);

// name : null
log.info("name : {}",
optional.map(
p -> {return p.getName();}
).map(
q -> {return q.toUpperCase();}
).orElse(null)
);
}

// 最直观的对比,如果使用 if 来判定,如果判定 null 过程过多时,会写出一堆不雅观的代码,一堆的 if 嵌套
@Test
public String getUser(){
User user = User.getSimpleUser();

if(user != null){
if(user.getName() != null){
return user.getName().toUpperCase();
}else{
return null;
}
}else{
return null;
}
}

Stream 类

详细参考

https://www.ibm.com/developerworks/cn/java/j-lo-java8streamapi/

关于 Stream

Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。Stream 就如同一个迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。

与 Iterator 的不同

Stream 可以并行化操作,迭代器只能命令式地、串行化操作。Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。

流管道的结构图

对 Stream 的使用就是实现一个 filter-map-reduce 过程,产生一个最终结果,或者导致一个副作用(side effect)

图 1.  流管道 (Stream Pipeline) 的构成


生成 Stream Source 的方法

  • Collection 和 数组:
    • Collection.stream()
    • Collection.parallelStream()
    • Arrays.stream(T array) or Stream.of()
  • BufferedReader:
    • java.io.BufferedReader.lines()
  • 静态工厂:
    • java.util.stream.IntStream.range()
    • java.nio.file.Files.walk()
  • 自己构建:
    • java.util.Spliterator
  • 其他:
    • Random.ints()
    • BitSet.stream()
    • Pattern.splitAsStream(java.lang.CharSequence)
    • JarFile.stream()

流的操作类型

  • Intermediate:一个流可以后面跟随零个或多个 intermediate 操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。
  • Terminal:一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个 side effect。
  • short-circuiting
    • 对于一个 intermediate 操作,如果它接受的是一个无限大(infinite/unbounded)的 Stream,但返回一个有限的新 Stream。
    • 对于一个 terminal 操作,如果它接受的是一个无限大的 Stream,但能在有限的时间计算出结果。

Stream 的常见构造

Stream 的 of 可以用于创建,默认是String 类型,如果要创建 Integer,Double,Long,请使用 IntStream, LongStream , DoubleStream ,避免使用泛型可以省去装箱操作,提高性能

1
2
3
4
5
6
7
8
9
10
11
12
13
  @Test
public void testStreamConstruction(){

Stream stream = Stream.of("Ke","Liang","Zeng");

// 不用泛型,使用具体Stream,可以省去 装箱操作,提高性能
IntStream intStream = IntStream.of(22,21,21);

DoubleStream doubleStream = DoubleStream.of(62,55,63);

LongStream longStream = LongStream.of(170,175,170);

}

通过数组构造

1
2
3
4
5
6
7
8
@Test
public void testStreamConstructionByArray(){
String[] strings = new String[]{"Ke","Liang","Zeng"};

Stream stream = Stream.of(strings);

stream = Arrays.stream(strings);
}

通过 Collection 来构造

1
2
3
4
5
6
7
8
9
10
  @Test
public void testStreamConstructionByList(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}
// 待探讨,这里无法用 IntStream 接收
Stream<Integer> stream = list.stream();

}

Stream 的操作

现在,我们之前学的 Lambda 就起作用了,因为 Stream 的操作 几乎都是基于 java.utils.function 包来完成的


Stream 的 Intermediate 操作

方法 说明
map 执行Function操作,修改数值
filter 执行 Predicate操作,完成过滤
distinct 去重
sorted 排序
peek 接收一个Consumer,做一些输出或外部处理
limit 限制Stream通过的个数
skip 跳过前几个
parallel 返回一个 parallel stream(转换为并行流)
sequential 返回一个 sequential stream(转换为串行流)
unordered 返回一个 unordered stream(转换为无序流)

Stream 的 Terminal 操作

方法 说明
forEach 接收一个Consumer
forEachOrdered 并行时按顺序处理,区别于forEach
toArray 返回一个数组
reduce 接收一个BinaryOperator
collect 返回一个集合
min 聚合求最小值
max 聚合求最大值
count 聚合计数
anyMatch 接收一个 Predicate,有一个符合就是True
allMatch 接收一个 Predicate,所有符合是Ture
noneMatch 接收一个 Predicate,所有不符合是Ture
findFirst 获取第一个,返回 Optional,并行流中才和findAny有区别
findAny 随机返回一个,返回 Optional
iterator 转换成迭代器

Stream 的 Short-circuiting 操作

方法 说明
anyMatch 同上
allMatch 同上
noneMatch 同上
findFirst 同上
findAny 同上
limit 同上

开始表演

map

Stream map(Function<? super T, ? extends R> mapper)

1
2
3
4
5
6
7
8
9
10
11
12
13
// 将 流的value 全部转为大写,其中的 collect 是返回集合
@Test
public void testStreamMap(){
String[] strings = new String[]{"Ke","Liang","Zeng"};

Stream<String> stream = Stream.of(strings);

List<String> list = stream.map(
p -> p.toUpperCase()
).collect(Collectors.toList());

log.info("list : {}",list); // list : [KE, LIANG, ZENG]
}

filter

Stream filter(Predicate<? super T> predicate) 执行过滤操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 将 流的value 小于等于5 的都过滤
@Test
public void testStreamFilter(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}

Stream<Integer> stream = list.stream();

list = stream.filter(
p -> p >5
).collect(Collectors.toList());

log.info("list : {}",list); // list : [6, 7, 8, 9]

}

distinct

Stream distinct() 去重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 去重
@Test
public void testStreamDistinct(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 3 ; i++){
list.add(i);
}

for(int i = 0 ; i < 3 ; i++){
list.add(i);
}

log.info("before : {}",list); // before : [0, 1, 2, 0, 1, 2]

Stream<Integer> stream = list.stream();

list = stream.distinct().collect(Collectors.toList());

log.info("after : {}",list); // after : [0, 1, 2]
}

sorted

Stream sorted()Stream sorted(Comparator<? super T> comparator)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Test
public void testStreamSorted(){

Stream<Integer> stream = Stream.of(22,21,21);

// 升序排列
List<Integer> integerList = stream.sorted().collect(Collectors.toList());

log.info("integerList : {}",integerList); // integerList : [21, 21, 22]

List<Integer> list = new ArrayList();
for(int i = 0 ; i < 5 ; i++){
list.add(i);
}

Stream<Integer> streamSecond = list.stream();

// 自定义 CompareTo 完成倒序
list = streamSecond.sorted( (a,b) -> a >= b ? -1 : 1 ).collect(Collectors.toList());

log.info("list : {}",list); // list : [4, 3, 2, 1, 0]
}

peek

Stream peek(Consumer<? super T> action)

1
2
3
4
5
6
7
8
9
10
11
12
13
   @Test
public void testStreamPeek(){
Stream<Integer> stream = Stream.of(22,21,21);
// 一个 Stream 必须执行 Terminal 操作,否则 Intermediate 不起作用
stream.peek(
p -> log.info("number : {}",p)
).count();
}
/*
2018-12-16 17:52:25.639 INFO 7988 --- [ main] com.zyy.consumer.StreamTest : number : 22
2018-12-16 17:52:25.640 INFO 7988 --- [ main] com.zyy.consumer.StreamTest : number : 21
2018-12-16 17:52:25.640 INFO 7988 --- [ main] com.zyy.consumer.StreamTest : number : 21
*/

limit

Stream limit(long maxSize)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   // 只需要 3 个元素就足够了
@Test
public void testStreamLimit(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}

Stream<Integer> stream = list.stream();

list = stream.limit(3).collect(Collectors.toList());

log.info("list : {}",list); // list : [0, 1, 2]


}

skip

Stream skip(long n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 跳过前三个

@Test
public void testStreamSkip(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}

Stream<Integer> stream = list.stream();

list = stream.skip(3).collect(Collectors.toList());

log.info("list : {}",list); // list : [3, 4, 5, 6, 7, 8, 9]
}

parallel

S parallel() 转换为并行流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    @Test
public void testStreamParallel(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 5 ; i++){
list.add(i);
}

Stream<Integer> stream = list.stream();

stream.parallel().forEach(
p -> log.info("number : {}",p)
);
}

2018-12-16 18:16:36.558 INFO 15640 --- [ main] com.zyy.consumer.StreamTest : number : 2
2018-12-16 18:16:36.558 INFO 15640 --- [ main] com.zyy.consumer.StreamTest : number : 4
2018-12-16 18:16:36.560 INFO 15640 --- [ main] com.zyy.consumer.StreamTest : number : 3
2018-12-16 18:16:36.561 INFO 15640 --- [ main] com.zyy.consumer.StreamTest : number : 0
2018-12-16 18:16:36.558 INFO 15640 --- [onPool-worker-1] com.zyy.consumer.StreamTest : number : 1

forEach

void forEach(Consumer<? super T> action)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    @Test
public void testStreamForEach(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}

Stream<Integer> stream = list.stream();

stream.limit(3).forEach(
p -> log.info("number : {}",p)
);
}

2018-12-16 18:11:22.170 INFO 14328 --- [ main] com.zyy.consumer.StreamTest : number : 0
2018-12-16 18:11:22.172 INFO 14328 --- [ main] com.zyy.consumer.StreamTest : number : 1
2018-12-16 18:11:22.172 INFO 14328 --- [ main] com.zyy.consumer.StreamTest : number : 2

forEachOrdered

void forEachOrdered(Consumer<? super T> action)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    // 并行流也会按顺序执行,不过会牺牲速度
@Test
public void testStreamForEachOrdered(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 5 ; i++){
list.add(i);
}

Stream<Integer> stream = list.stream();

stream.parallel().forEachOrdered(
p -> log.info("number : {}",p)
);
}

2018-12-16 18:20:00.344 INFO 17744 --- [ main] com.zyy.consumer.StreamTest : number : 0
2018-12-16 18:20:00.344 INFO 17744 --- [onPool-worker-1] com.zyy.consumer.StreamTest : number : 1
2018-12-16 18:20:00.345 INFO 17744 --- [onPool-worker-1] com.zyy.consumer.StreamTest : number : 2
2018-12-16 18:20:00.345 INFO 17744 --- [onPool-worker-1] com.zyy.consumer.StreamTest : number : 3
2018-12-16 18:20:00.345 INFO 17744 --- [onPool-worker-1] com.zyy.consumer.StreamTest : number : 4

toArray

Object[] toArray()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    @Test
public void testStreamToArray(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}

Stream<Integer> stream = list.stream();

Object[] objects = stream.limit(4).toArray();

for(Object o : objects){
log.info("number : {}",o);
}
}

2018-12-16 18:25:40.322 INFO 5544 --- [ main] com.zyy.consumer.StreamTest : number : 0
2018-12-16 18:25:40.322 INFO 5544 --- [ main] com.zyy.consumer.StreamTest : number : 1
2018-12-16 18:25:40.322 INFO 5544 --- [ main] com.zyy.consumer.StreamTest : number : 2
2018-12-16 18:25:40.322 INFO 5544 --- [ main] com.zyy.consumer.StreamTest : number : 3

reduce

Optional reduce(BinaryOperator accumulator)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 求和
@Test
public void testStreamReduce(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}

Stream<Integer> stream = list.stream();

Optional<Integer> optional = stream.reduce(
(a,b) -> a + b
);

log.info("sum : {}",optional.get()); // sum : 45
}

Match

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 测试三种 match
@Test
public void testStreamMatch(){
List<Integer> list = new ArrayList();
for(int i = 0 ; i < 10 ; i++){
list.add(i);
}

Stream<Integer> stream = list.stream();

log.info("AnyFirst : {}",stream.anyMatch(
p -> p >5
)); // true
stream = list.stream();
log.info("AnySecond : {}",stream.anyMatch(
p -> p >15
)); // false
stream = list.stream();
log.info("AllFirst : {}",stream.allMatch(
p -> p >=0
)); // true
stream = list.stream();
log.info("AllSecond : {}",stream.allMatch(
p -> p >5
)); // false
stream = list.stream();
log.info("NoneFirst : {}",stream.noneMatch(
p -> p > 10
)); // true
stream = list.stream();
log.info("NoneSecond : {}",stream.noneMatch(
p -> p > 5
)); // false
}

JDK8 中 :: 的使用

本质

就是将 Stream 的参数传入一个方法中执行

要求

  • 一个类的静态方法
  • 参数需要一致
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// LambdaTest 类

@Test
public void testLambdaPredicate(){
List<Integer> list = new ArrayList<>();
for(int i = 0 ; i < 10;i++){
list.add(i);
}
new FirstLambda().checkNumberBigger(list,
p -> p > 5,
LambdaTest::testDoubleQuote); // 将Stream 传入 LambdaTest.testDoubleQuote

new FirstLambda().checkNumberBigger(list,
p -> p > 5,
p -> log.info("number : {}",p));
}

public static void testDoubleQuote(Integer s){
log.info("element : {}",s);
}
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×