关于java:Java-常用函数式接口-Consumer接口

2次阅读

共计 3125 个字符,预计需要花费 8 分钟才能阅读完成。

JDK 提供了大量的函数式接口,不便咱们开发的时候无需本人编写接口,这些接口都比拟通用,学会他们并且在工作中应用,不仅不便的解决问题,而且非常优雅。

1、接口概述

Consumer 接口也比较简单,只有两个办法,一个是形象办法,一个是默认办法:

@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); };
    }
}

2、accept 办法

该办法接管一个接口泛型类型的对象,没有返回值。

看看汇合的 forEach 办法的应用:

public class ConsumerTest {public static void main(String[] args) {List<String> names = new ArrayList<String>() {
            {add("Tom");
                add("Jerry");
            }
        };
        names.forEach(e -> System.out.println(e));
        names.forEach(System.out::println);
    }
}

咱们应用 forEach 办法的时候,该办法就是应用了 Consumer 接口作为参数。这是咱们最常见的应用 Consumer 的形式。

除了打印信息,个别咱们对于汇合中的对象的某些数据须要更改,也常常应用 forEach 遍历,而后对于每个对象做一些业务操作。

尽管 forEach 罕用,然而个别咱们都很少关注 forEach 的实现,也很少本人写个办法用到 Consumer 接口:

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

3、Consumer 接口应用场景 - 回调

public class ConsumerTest {private static final Map<Integer, String> map = new HashMap<Integer, String>() {
        {put(10, "Tom");
            put(3, "Jerry");
        }
    };

    public static void main(String[] args) {
        // 调用办法,同时编写对后果的回调:此处仅仅打印而已
        test(3, System.out::println);
    }

    public static void test(Integer age, Consumer<String> consumer) {
        // 业务解决
        System.out.println(age);

        // 对处理结果的回调: 上面的 ifPresent 参数也是 Consumer 接口,所有上面三种写法都能够
        //Optional.ofNullable(map.get(age)).ifPresent(e -> consumer.accept(e));
        //Optional.ofNullable(map.get(age)).ifPresent(consumer::accept);
        Optional.ofNullable(map.get(age)).ifPresent(consumer);
    }
}

Consumer 接口个别作为办法参数来实现回调的性能,例如下面的例子,test 函数传递待处理的对象 age , 通过业务解决失去其它后果对象,之后调用 accept 对后果对象进行解决。

理论中回调解决的对象是依据入参失去其它后果。比方传入姓名从数据库查问数据,回调函数将数据保留在其它中央,那么这个其它中央就须要调用者本人解决,比方存文件。

4、默认办法 andThen

办法源码:

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

应用场景:

    public static void main(String[] args) {Consumer<String> first = (x) -> System.out.println(x.toLowerCase());
        Consumer<String> next = (x) -> System.out.println(x.toUpperCase());
        first.andThen(next).accept("Hello World");
    }

andThen 接管一个 Consumer 接口,返回的也是一个 Consumer 接口,同样的,调用该办法的也是 Consumer 接口。这个中央比拟绕,须要对照下面两处代码仔细分析。

first 是一个 Consumer 接口,当调用 andThen 办法的时候,并不是执行 (T t) -> {accept(t); after.accept(t); } 这段代码,而是返回了一个 Consumer 接口,留神它的构造是 给一个对象 t,而后大括号中生产 t。解决逻辑是以后 Consumer 执行 accept 办法,而后再让 after 这个 Consumer 执行 accept 办法。了解 andThen 办法返回的构造特地重要。

first.andThen(next) 执行实现,失去一个 Consumer 接口接口后,再次调用 accept("Hello World") 时,实际上对 Hello World 字符串执行的内容就是大括号外面的内容了:accept(t); after.accept(t); 也就是下面的先输入小写字符串、再输入大写的字符串了。

5、andThen 办法应用场景

public class ConsumerTest {private static final Map<Integer, Consumer<String>> QUEUE = new ConcurrentHashMap<>();

    public static void main(String[] args) {resolve(1, s -> System.out.println(s.toUpperCase()));
        resolve(1, s -> System.out.println(s.toLowerCase()));
        resolve(1, s -> System.out.println(s.substring(0, 2)));
        QUEUE.get(1).accept("Hello World");
    }

    public static void resolve(Integer id, Consumer<String> callback) {final Consumer<String> existing = QUEUE.get(id);
        if (callback == null) callback = i -> {};
        if (existing != null && callback != existing) {callback = existing.andThen(callback);
        }
        QUEUE.put(id, callback);
    }
}

后果如下:

HELLO WORLD
hello world
He

下面代码中的 resolve 办法依据 id , 向 map 类型的 QUEUE 中减少多个回调函数,最初执行的时候,多个回调函数都被执行,很相似责任链的设计模式。能够联合下面的解说认真了解

callback = existing.andThen(callback);

以及在执行的中央:

QUEUE.get(1).accept("Hello World");
正文完
 0