Java 8 Consumer、Supplier、Predicate、Function

这几个接口都在 java.util.function 包下的,分别是Consumer(消费型)、supplier(供给型)、predicate(谓词型)、function(功能性)
下面从具体的应用场景来讲讲这个接口的用法。

Consumer接口

源码:

Consumer.java

/**
 * 代表这样一种操作: 接收一个单值输入,没有返回值。与大部分函数式接口不同,
 *  Consumer一般通过"副作用"来操作。
 * Consumer 的函数式方法是accept
 * @since 1.8
 */
@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);

    /**
     * 这个默认方法与Function接口中的andThen方法类似,对于给定的入参after(类型也是Consumer),
     * 先执行上面的accept方法,再执行after中的accept方法。
     */
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

使用Consumer接口的示例

     @Test
    public void test_Consumer(){
        //1. 使用consumer接口实现方法
        System.out.println("使用consumer接口实现方法");
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        Stream<String> stream = Stream.of("aaa", "bbb");
        stream.forEach(consumer);

        System.out.println("*********************");

        //2. 使用lambda表达式, Stream的forEach方法需要的入参就是一个consumer接口
        System.out.println("使用lambda表达式");
        Consumer<String> consumer1 = (s) -> System.out.println(s);//lambda表达式返回的就是一个Consumer接口
        stream = Stream.of("aaa", "bbb");
        stream.forEach(consumer1);
        //更直接的方式
        //stream.forEach((s) -> System.out.println(s));
        System.out.println("********************");

        //3. 使用方法引用,方法引用也是一个consumer
        System.out.println("使用方法引用");
        Consumer consumer2 = System.out::println;
        stream = Stream.of("aaa", "bbb");
        stream.forEach(consumer2);
        //更直接的方式
        //stream.forEach(System.out::println);
        System.out.println("********************");

        //4. 演示Consumer的andThen方法
        Consumer<String> addHello = s -> System.out.println("hello");
        Consumer consumer3 = s -> System.out.println(s);
        //先执行consumer3定义的accept方法,再执行addHello定义的accept
        System.out.println("演示Consumer的andThen方法");
        stream = Stream.of("aaa", "bbb");
        stream.forEach(consumer3.andThen(addHello));
    }

输出:

使用consumer接口实现方法
aaa
bbb
*********************
使用lambda表达式
aaa
bbb
********************
使用方法引用
aaa
bbb
********************
演示Consumer的andThen方法
aaa
hello
bbb
hello

说明:

  1. Consumer是一个接口,并且只要实现一个 accept 方法,就可以作为一个“消费者”输出信息。
  2. lambda 表达式、方法引用的返回值都是 Consumer 类型,所以,他们能够作为StreamforEach 方法的参数,并且输出一个值。

其实除了StreamforEach方法, 我们常见的List列表的forEach方法也可以接收一个Consumer来遍历列表中的每个元素并对其进行Consumeraccept方法中定义的操作:
java.lang.IterableforEach方法源码:

default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

forEach的参数是一个Consumer,从forEach这个方法的定义来看,现在我们可以理解为“遍历我所包含的所有元素,对每个元素都执行一次action.accept()
所以客户端可以这样使用ListforEach:

List<String> list = new ArrayList<>();
list.add("Hello ");
list.add("World!");
list.forEach(s -> System.out.println(s)); // 这里当然也可以用更为简洁的方法引用来改写

## Supplier 接口 #### 源码 > Supplier.java ``` @FunctionalInterface public interface Supplier {
/**
 * Gets a result.
 *
 * @return a result
 */
T get();

}

`Supplier`接口是一个供给型的接口,其实,说白了就是一个容器,可以用来存储数据,然后可以供其他方法使用的这么一个接口。至于如何获取数据,交给用户去实现`Supplier`的`get`方法。
#### 使用Supplier接口的示例

@Test
public void test_Supplier() {
//① 使用Supplier接口实现方法,只有一个get方法,无参数,返回一个值
Supplier supplier = new Supplier() {
@Override
public Integer get() {
//返回一个随机值
return new Random().nextInt();
}
};
System.out.println("获取随机int");
System.out.println(supplier.get());

    System.out.println("********************");

    //② 使用lambda表达式,
    supplier = () -> new Random().nextInt();
    System.out.println("使用lambda表达式定义supplier");
    System.out.println(supplier.get());
    System.out.println("********************");

    //③ 使用方法引用
    System.out.println("使用方法引用");
    Supplier<Double> supplier2 = Math::random;
    System.out.println(supplier2.get());

    Integer[] integers = {1, 2, 3, 4, 5};
    List<Integer> list = Arrays.asList(integers);
    Stream<Integer> stream = list.stream();
    //返回一个optional对象, optional对象可以持有元素或者null
    Optional<Integer> first = stream.filter(i -> i > 4)
            .findFirst();
    //optional对象有需要Supplier接口的方法
    //orElse,如果first中存在数,就返回这个数,如果不存在,就返回传入orElse中的数字
    System.out.println("使用optional对象找到大于4的第一个元素并返回,找不到返回-100");
    System.out.println(first.orElse(-100));
    System.out.println("********************");

    //这次找大于100的数字
    stream = list.stream();
    Optional<Integer> above100 = stream.filter(integer -> integer > 100).findFirst();
    Supplier<Integer> supplier3 = () -> new Random().nextInt();

    //orElseGet,如果first中存在数,就返回这个数,如果不存在,就返回supplier3返回的值
    System.out.println("orElseGet,如果first中存在数,就返回这个数,如果不存在,就返回supplier3返回的值");
    System.out.println(above100.orElseGet(supplier3));
}
输出:

获取随机int
-1992653641


使用lambda表达式定义supplier
-1661833099


使用方法引用
0.4916754644996516
使用optional对象找到大于4的第一个元素并返回,找不到返回-100
5


orElseGet,如果first中存在数,就返回这个数,如果不存在,就返回supplier3返回的值
-454437243

说明:
1. `Supplier` 接口可以理解为一个容器,用于装数据的。
2. `Supplier` 接口有一个 `get` 方法,用户重写这个方法以提供返回。
<br/>

#### Supplier接口示例补充:
> CallableLock.java

public class CallableLock {
public V lock(Supplier supplier){
try {
doLock();
return supplier.get();
}finally {
unLock();
}
}

private boolean doLock(){
    System.out.println("Lock!");
    return true;
}

private void unLock(){
    System.out.println("Unlock!");
}

}

> Processor.java

public class Processor {
public boolean process() {
System.out.println("Processing");
try {
Thread.sleep(10 * 1000);
}catch (Exception e){
e.printStackTrace();
}
return true;
}
}

> LockTest.java

public class LockTest {

@Test
public void lockTest(){
   CallableLock<Boolean> callableLock = new CallableLock<>();
   Processor processor = new Processor();
   callableLock.lock(processor::process);
    System.out.println("====================");
   callableLock.lock(()->processor.process());
    System.out.println("====================");
   callableLock.lock(new Supplier<Boolean>() {
       @Override
       public Boolean get() {
           return processor.process();
       }
   });
    System.out.println("====================");
}

}

<br/>

## Predicate 接口
#### 源码
> Predicate.java

@FunctionalInterface
public interface Predicate {

/**
 * 计算给定的boolean表达式的真假
 *
 * @param t 入参
 * @return {@code true} 根据输入t是否符合test函数中定义的判断逻辑返回true或false,
 */
boolean test(T t);
 
//下面在接口中默认实现的and方法、negate方法、or方法、isEqual方法, 可以实现嵌套判断
//and方法提供逻辑与功能,具有短路效应
/**
 * Returns a composed predicate that represents a short-circuiting logical
 * AND of this predicate and another.  When evaluating the composed
 * predicate, if this predicate is {@code false}, then the {@code other}
 * predicate is not evaluated.
 */
default Predicate<T> and(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) && other.test(t);
}

//negate方法提供逻辑非功能
/**
 * Returns a predicate that represents the logical negation of this
 * predicate.
 */
default Predicate<T> negate() {
    return (t) -> !test(t);
}

// or方法提供逻辑或功能,具有短路效应
/**
 * Returns a composed predicate that represents a short-circuiting logical
 * OR of this predicate and another.  When evaluating the composed
 * predicate, if this predicate is {@code true}, then the {@code other}
 * predicate is not evaluated.
 */
default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
}

/** isEqual方法提供逻辑相等判断
 * Returns a predicate that tests if two arguments are equal according
 * to {@link Objects#equals(Object, Object)}.
 */
static <T> Predicate<T> isEqual(Object targetRef) {
    return (null == targetRef)
            ? Objects::isNull
            : object -> targetRef.equals(object);
}
说明: 默认实现的`and`、 `negate`、 `or`、`isEqual`方法都返回`Predicate`对象。 用于嵌套的逻辑判断。
#### Predicate接口示例
@Test
public void test_Predicate() {
    Integer[] integers = {1, 2, 3, 4, 5};
    List<Integer> list = Arrays.asList(integers);
    Stream<Integer> stream = list.stream();
    // 基本测试, 使用predicate打印所有大于3的数字
    Predicate<Integer> predicate = integer -> integer > 3;
    System.out.println("使用predicate打印所有大于3的数字");
    stream.filter(predicate).forEach((integer)-> System.out.println(integer));
    System.out.println("********************");

    //默认方法测试,这里只测试and方法, 其他的方法类似
    System.out.println("测试and方法, 使用两个predicate之间的and逻辑,打印所有大于3且为偶数的数字");
    Predicate<Integer> even = integer -> integer%2 == 0;
    stream = list.stream();
    stream.filter(predicate.and(even)).forEach(System.out::println);
}
测试结果:

使用predicate打印所有大于3的数字
4
5


测试and方法, 使用两个predicate之间的and逻辑,打印所有大于3且为偶数的数字

说明:
1. `Predicate` 是一个谓词型接口,其实只是起到一个判断作用。
2. `Predicate` 通过实现一个 `test` 方法做判断。
3. `Predicate`有默认实现的逻辑判断方法
<br/>

## Function接口
#### 基本使用
见 [Java8 Function接口(apply compose andThen)](https://www.cnblogs.com/greatLong/articles/11975684.html)
<br/>
#### 链式调用进阶使用
首先定义接口`ProcessUnit`继承`Function`接口并提供`apply`方法的默认实现:
> ProcessUnit.java

public interface ProcessUnit<T, R> extends Function<T, R> {
@Override
default R apply(T t){
return process(t);
}

R process(T t);

}

这里对`apply`方法的默认实现是调用`ProcessUnit`定义的`process`方法,这个方法交给实现`ProcessUnit`的类去实现,从而可以在这里写自己的处理逻辑。在使用的时候可以使用`ProcessUnit`从`Function`接口中继承来的`compose`和`andThen`方法对逻辑处理进行组合。
下面的`AndThen1`、`AndThen2`和`AndThen3`都分别实现了`ProcessUnit`接口,并重写了`process`方法来提供自己的处理逻辑。
> AndThen1.java

public class AndThen1 implements ProcessUnit<Integer, String>{
@Override
public String process(Integer integer) {
integer += 1;
System.out.println("I am in andThen1, the number is " + integer);
String s = String.valueOf(integer);
return s;
}
}

> AndThen2.java

public class AndThen2 implements ProcessUnit<String, String>{
@Override
public String process(String string) {
Integer integer = Integer.parseInt(string) + 1;
System.out.println("I am in andThen2, the number is " + integer);
return String.valueOf(integer);
}
}

> AndThen3.java

public class AndThen3 implements ProcessUnit<String, String>{
@Override
public String process(String string) {
Integer integer = Integer.parseInt(string) + 1;
System.out.println("I am in andThen3, the number is " + integer);
return String.valueOf(integer);
}
}

测试方法:
> test.java

public class test {

Function<Integer, String> function;

@Before
public void prepare(){
    System.out.println("Prepare the test ... ");
    System.out.println("++++++++++++++++++++++++++++++");
    function = new AndThen1().andThen(new AndThen2()).andThen(new AndThen3());
}

@Test
public void testAndThen(){
    System.out.println(function.apply(100));
}

@After
public void finish(){
    System.out.println("==============================");
    System.out.println("finish test");
}

}

在测试类中定义了一个`Function`对象来接收方法调用链实例。
测试结果:

Prepare the test ...
++++++++++++++++++++++++++++++
I am in andThen1, the number is 101
I am in andThen2, the number is 102
I am in andThen3, the number is 103
103

finish test

Process finished with exit code 0


> 参考文章
>> [Java8之Consumer、Supplier、Predicate和Function攻略](https://www.cnblogs.com/SIHAIloveYAN/p/11288064.html)
posted @ 2019-12-03 15:03  lllunaticer  阅读(1498)  评论(0编辑  收藏  举报