Wetts's blog

Stay Hungry, Stay Foolish.

0%

Java-API-函数式编程.md

转自:https://blog.csdn.net/qq_33591903/article/details/102948344

快速理解 Consumer、Supplier、Predicate 与 Function

前言

这几个接口都处在java.util.function包下,Consumer(消费型),Supplier(供给型)、Predicate(判断型)与Function(转换型),暂时不理解他们的类型没关系。

Consumer

Consumer 是一个消费型的接口

先看 Consumer 接口的源码,有一个未实现的抽象方法,和一个默认方法(jdk1.8 之后,接口里面可以有默认方法和静态方法)。

1
2
3
4
5
6
7
8
9
10
11
@FunctionalInterface
public interface Consumer<T> {

void accept(T t);

default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}

}

我们只在意这个accept方法,接收一个泛型参数,不返回任何值。ok,我们来简单实现它

1
2
3
4
5
6
7
8
Consumer<Integer> consumer=new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
};

consumer.accept(1);

接下来我们使用 lambda 表达式来对此匿名内部类进行改写。此时该 lambda 的类型就是 Consumer 类型。

1
consumer = i-> System.out.println(i);

当然我们也可以使用方法引用

1
consumer=System.out::println;

在 Stream 类中,我们发现常用的 forEach 接口接收一个 Consumer 类型的参数,源码如下

1
void forEach(Consumer<? super T> action);

我们将 consumer 传入 forEach 中,来实现遍历集合的操作。

1
2
3
List<Integer> list= Arrays.asList(1,2,3,4,5);
Consumer<Integer> consumer= System.out::println;
list.stream().forEach(consumer);

Consumer 总结:

  • Consumer 接口是一个消费型的接口,只要实现它的 accept 方法,就能作为消费者来输出信息。
  • lambda、方法引用都可以是一个 Consumer 类型,因此他们可以作为 forEach 的参数,用来协助 Stream 输出信息。
  • Consumer 还有很多变种,例如 IntConsumer、DoubleConsumer 与 LongConsumer 等,归根结底,这些变种其实只是指定了 Consumer 中的泛型而已,方法上并无变化。

Supplier

Supplier 是一个供给型的接口,我们可以无条件的从它这里获取东西。

1
2
3
4
5
@FunctionalInterface
public interface Supplier<T> {

T get();
}

我们不需要为 get 方法传入任何参数,就能获得一个结果

1
2
3
4
Supplier<Double> supplier=()->new Random().nextDouble();
//当然也可以使用方法引用
Supplier<Double> supplier1= Math::random;
System.out.println(supplier.get());

我们看看 Supplier 在 Optional 中的应用。

1
2
3
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}

该方法接收 Supplier 类型的参数,当 Optional 内部的 value 不为空时,才会返回 Supplier 中的值。例如

1
2
3
Optional<Double> optional=Optional.empty();
Supplier<Double> supplier=()->new Random().nextDouble();
optional.orElseGet(supplier);

这必定返回 Supplier 中的随机值,因为 Optional.empty() 包含的值就是 null。

Supplier 总结:

  • Supplier 是一个供给型的接口,其中的 get 方法用于返回一个值。
  • Supplier 也有很多的变种,例如 IntSupplier、LongSupplier 与 BooleanSupplier 等

Predicate

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
@FunctionalInterface
public interface Predicate<T> {

boolean test(T t);

default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}

default Predicate<T> negate() {
return (t) -> !test(t);
}

default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}

static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
1
2
Predicate<Integer> predicate=i->i>5;
System.out.println(predicate.test(1));

很明显,输出是 false。等等,既然可以进行判断,那和 Stream.filter() 有没有关系呢?

1
Stream<T> filter(Predicate<? super T> predicate);
1
2
List<Integer> list= Arrays.asList(1,2,3,4,5,6,7,8);
list.stream().filter(i->i>5).forEach(System.out::print);

很简单,输出是678。

Predicate 总结:

  • Predicate 是一个判断型的接口,用一个 test 方法去测试传入的参数。
  • 当然,Predicate 也有对应的变种。

Function

Function 是一个功能型的接口,用于将一种类型的数据转化为另外一种类型的数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@FunctionalInterface
public interface Function<T, R> {

R apply(T t);

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}

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

static <T> Function<T, T> identity() {
return t -> t;
}
}

重点关注它的 apply 方法,现在就去实现它,并将之传入进 Stream.map() 方法中试试。

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 class TestFunction {
static class Student{
String name;
Integer id;

public Student(String name, Integer id) {
this.name = name;
this.id = id;
}

public String getName() {
return name;
}

public Integer getId() {
return id;
}
}
public static void main(String[] args) {
List<Student> list= Arrays.asList(new Student("jack",1),new Student("tom",2));
Function<Student,Integer> function= Student::getId;
list.stream().map(function).forEach(System.out::print);
}

}

输出 12,可以看得出,Function 中的 apply 方法将 Student 类型的数据转化为对应 id 的 Integer 类型的数据。

Function 总结:

  • Function 是一个转换型的接口,其中的 apply 可以将一种类型的数据转化成另外一种类型的数据。
  • Function 的变种就更多了。

总结

首先只要记住这四个接口的类型,Consumer(消费型)、Supplier(供给型)、Predicate(判断型)与Function(转换型),再记住他们对应的抽象方法 Consumer(accpet)、Supplier(get)、Predicate(test) 与 Function(apply)。