您何时以及为何使用 Java 的供应商和消费者接口?

When and why would you use Java's Supplier and Consumer interfaces?

作为一名非 Java 程序员学习 Java,我目前正在阅读 SupplierConsumer 接口。而且我无法理解它们的用法和含义。

您何时以及为何使用这些界面?有人可以给我一个简单的外行示例吗?

我发现 Doc 示例不够简洁,不足以让我理解。

这是供应商:

public Integer getInteger() {
    return new Random().nextInt();
}

这是消费者:

public void sum(Integer a, Integer b) {
    System.out.println(a + b);
}

因此,通俗地说,供应商是一种 return 具有某种价值(如其 return 价值)的方法。然而,消费者是一种消耗某些值(如方法参数)并对它们执行某些操作的方法。

那些将变成这样的东西:

// new operator itself is a supplier, of the reference to the newly created object
Supplier<List<String>> listSupplier = ArrayList::new;
Consumer<String> printConsumer = a1 -> System.out.println(a1);
BiConsumer<Integer, Integer> sumConsumer = (a1, a2) -> System.out.println(a1 + a2);

至于用法,最基本的例子是:Stream#forEach(Consumer) 方法。它需要一个 Consumer,它从您正在迭代的流中消费元素,并对它们中的每一个执行一些操作。可能打印出来。

Consumer<String> stringConsumer = (s) -> System.out.println(s.length());
Arrays.asList("ab", "abc", "a", "abcd").stream().forEach(stringConsumer);

您之所以难以理解java.util.function中的函数式接口的含义,是因为此处定义的接口没有任何意义!它们的存在主要是为了表示结构,而不是语义

这对于大多数 Java API 来说是不典型的。典型的 Java API,例如 class 或接口,是有意义的,您可以为它所代表的内容开发一个心智模型,并使用它来理解对它的操作。以 java.util.List 为例。 List 是其他对象的容器。他们有一个序列和一个索引。列表中包含的对象数由 size() 编辑 return。每个对象都有一个在 0..size-1(含)范围内的索引。可以通过调用 list.get(i) 检索索引 i 处的对象。等等。

java.util.function中的功能接口没有任何这样的含义。相反,它们是仅表示函数的 结构 的接口,例如参数的数量、return 值的数量,以及(有时)参数或return 值是原始值。因此我们有类似 Function<T,R> 的东西,它表示一个函数,它接受一个类型为 T 的参数和 returns 一个类型为 R[= 的值44=]。而已。该功能有什么作用?好吧,它可以做任何事情……只要它接受一个参数并且 returns 是一个值。这就是为什么 Function<T,R> 的规格比 "Represents a function that accepts one argument and produces a result."

显然,当我们编写代码时,它是有意义的,而这种意义必须来自某个地方。在功能接口的情况下,含义来自使用它们的上下文。接口 Function<T,R> 孤立地没有意义。但是,在java.util.Map<K,V>API中,有如下内容:

V computeIfAbsent(K key, Function<K,V> mappingFunction)

(为简洁起见省略了通配符)

啊,这个 Function 的用法是 "mapping function"。那有什么作用?在这种情况下,如果 key 尚未出现在映射中,则调用映射函数并传递键并期望产生一个值,并将生成的键值对插入映射中。

因此您不能查看 Function 的规范(或任何其他功能接口,就此而言)并试图辨别它们的含义。您必须查看它们在其他 API 中的使用位置才能理解它们的含义,并且该含义仅适用于该上下文。

A Supplier 是任何不带参数且 return 有值的方法。它的工作实际上是提供预期 class 的实例。例如,每个对 'getter' 方法的引用都是 Supplier

public Integer getCount(){
    return this.count;
}

它的实例方法引用myClass::getCountSupplier<Integer>的一个实例。

A Consumer 是任何接受参数并且 return 什么都不带的方法。它因其副作用而被调用。在 Java 术语中,Consumervoid 方法的习语。 'setter' 方法就是一个很好的例子:

public void setCount(int count){
    this.count = count;
}

它的实例方法引用myClass::setCountConsumer<Integer>IntConsumer的实例。

A Function<A,B> 是接受一种类型参数和 return 另一种类型参数的任何方法。这可以称为'transformation'。 Function<A,B> 接受 A,return 接受 B。值得注意的是,对于给定的 A 值,函数应始终 return 特定的 B 值。 AB其实可以是同一个类型,比如下面这样:

public Integer addTwo(int i){
    return i+2;
}

它的实例方法引用myClass:addTwo是一个Function<Integer, Integer>和一个ToIntFunction<Integer>.

对 getter 的 Class 方法引用是函数的另一个示例。

public Integer getCount(){
    return this.count;
}

其class方法引用MyClass::getCountFunction<MyClass,Integer>ToIntFunction<MyClass>的一个实例。

为什么 Consumer/Supplier/other 函数接口定义在 java.util.function 包中 : 消费者和供应商是提供的许多内置函数接口中的两个在 Java 8. 所有这些内置功能接口的目的是为具有通用功能描述符(功能方法 signatures/definitions)的功能接口提供现成的 "template"。

假设我们需要将类型 T 转换为另一种类型 R。如果我们将这样定义的 any 函数作为参数传递给方法,那么方法需要定义一个功能接口,其 functional/abstract 方法将 T 类型的参数作为输入并给出 R 类型的参数作为输出。现在,可能有很多这样的场景,程序员最终会根据他们的需要定义多个功能接口。为了避免这种情况,简化编程并在功能接口的使用中引入通用标准,定义了一组内置功能接口,如谓词、函数、消费者和供应商。

Consumer 做什么:Consumer 功能接口接受一个输入,对该输入做一些事情并且不给出任何输出。它的定义是这样的(来自Java来源)-

@FunctionalInterface
public interface Consumer<T> {
 void accept(T t);
}

这里的 accept() 是 functional\abstract 方法,它接受输入,returns 没有输出。所以,如果你想输入一个整数,用它做一些没有输出的事情,那么不要定义你自己的接口,而是使用消费者的实例。

Supplier 做什么:Supplier 功能接口不接受任何输入,但returns 输出。它的定义是这样的(来自 Java 来源)-

@FunctionalInterface
public interface Supplier<T> {
  T get();
}

只要你需要一个 returns 东西的函数,比如说一个整数,但不使用供应商实例的输出。

如果需要更清晰的消费者和供应商接口以及示例用法,那么您可以参考我的博客文章 - http://www.javabrahman.com/java-8/java-8-java-util-function-consumer-tutorial-with-examples/ and http://www.javabrahman.com/java-8/java-8-java-util-function-supplier-tutorial-with-examples/

通俗地说,

供应商将提供数据但不消耗任何数据。在编程术语中,一种不接受任何参数但 return 值的方法。它用于生成新值。

http://codedestine.com/java-8-supplier-interface/

consumer 会消费数据但不会return任何数据。在编程术语中,一种方法采用多个参数并且不 return 任何值。

http://codedestine.com/java-8-consumer-interface/

1。含义

查看我对问题 and also another 的回答,但简而言之,这些新界面为每个人提供了 约定 描述性 使用 (+ 时髦的方法链接,例如 .forEach(someMethod().andThen(otherMethod()))

2。差异

消费者:拿东西,做东西,returns什么都不做:void accept(T t)

供应商:什么都不拿,returns东西:T get()(与消费者相反,基本上是通用的'getter'方法)

3。用法

// Consumer: It takes something (a String) and does something (prints it) 
    List<Person> personList = getPersons();

     personList.stream()
                    .map(Person::getName)    
                    .forEach(System.out::println); 

供应商:包装重复代码,例如代码执行时间

public class SupplierExample {

    public static void main(String[] args) {

        // Imagine a class Calculate with some methods
        Double result1 = timeMe(Calculate::doHeavyComputation);
        Double result2 = timeMe(Calculate::doMoreComputation);
    }
    private static Double timeMe(Supplier<Double> code) {

        Instant start = Instant.now();
        // Supplier method .get() just invokes whatever it is passed
        Double result = code.get();
        Instant end = Instant.now();

        Duration elapsed = Duration.between(start,end);
        System.out.println("Computation took:" + elapsed.toMillis());

        return result;
    }
}

消费者和供应商是java提供的接口。消费者用于遍历列表元素,供应商用于供应对象的

通过代码演示,一目了然。

消费者

package com.java.java8;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * The Class ConsumerDemo.
 *
 * @author Ankit Sood Apr 20, 2017
 */
public class ConsumerDemo {

    /**
     * The main method.
     *
     * @param args
     *            the arguments
     */
    public static void main(String[] args) {

    List<String> str = new ArrayList<>();
    str.add("DEMO");
    str.add("DEMO2");
    str.add("DEMO3");

    /* Consumer is use for iterate over the List */
    Consumer<String> consumer = new Consumer<String>() {
        @Override
        public void accept(String t) {

        /* Print list element on consile */
        System.out.println(t);
        }
    };

    str.forEach(consumer);

    }

}

供应商

package com.java.java8;

import java.util.function.Supplier;

/**
 * The Class SupplierDemo.
 *
 * @author Ankit Sood Apr 20, 2017
 */
public class SupplierDemo {

    /**
     * The main method.
     *
     * @param args
     *            the arguments
     */
    public static void main(String[] args) {
    getValue(() -> "Output1");
    getValue(() -> "OutPut2");
    }

    /**
     * Gets the value.
     *
     * @param supplier
     *            the supplier
     * @return the value
     */
    public static void getValue(Supplier<?> supplier) {
    System.out.println(supplier.get());
    }

}