什么时候以及为什么要使用 Java 的供应商和消费者接口?

作为一个学习 Java 的非 Java 程序员,我现在正在阅读关于 SupplierConsumer接口的文章。我无法理解它们的用法和含义。

什么时候以及为什么你会使用这些接口? 有人能给我一个简单的外行例子吗?

我发现文件中的例子不够简洁。

82915 次浏览

这是供应商:

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

这是消费者:

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

因此,在通俗的术语中,供应商是一个返回一些值的方法(比如它的返回值)。然而,使用者是一个使用某些值(如在方法参数中)并对它们执行某些操作的方法。

它们将转变成这样的东西:

// 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中的函数式接口的含义,是因为这里定义的接口没有任何含义!它们主要表示 结构,而不是 语义学

这对于大多数 JavaAPI 来说是非典型的。典型的 JavaAPI,比如类或接口,是有意义的,您可以为它所表示的内容开发一个心理模型,并使用该模型来理解它上面的操作。以 java.util.List为例。List是其他对象的容器。它们有序列和索引。列表中包含的对象数由 size()返回。每个对象都有一个范围为0.size-1(包括)的索引。可以通过调用 list.get(i)检索索引 处的对象。等等。

java.util.function中的函数接口没有这样的含义。相反,它们是仅仅表示函数的 结构的接口,例如参数的数量、返回值的数量,以及(有时)参数或返回值是否是原语。因此,我们有一个类似于 Function<T,R>的函数,它接受类型为 T的单个参数并返回类型为 R的值。就是这样。这个函数是做什么的?它可以做任何事情... 只要它接受一个参数并返回一个值。这就是为什么 Function<T,R>的规范只不过是“表示一个接受一个参数并产生结果的函数”

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

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

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

啊,这个使用 Function就是一个“映射函数”。那有什么用?在这种情况下,如果映射中还没有出现 key,那么就会调用映射函数,并传递给键,期望它生成一个值,然后将生成的键-值对插入到映射中。

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

Supplier是任何不接受参数并返回值的方法。它的工作实际上是提供一个期望类的实例。例如,对“ getter”方法的每个引用都是 Supplier

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

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

Consumer是任何接受参数但不返回任何值的方法。它是由于其副作用而被调用的。在 Java 术语中,Consumervoid方法的习惯用法。Setter 方法就是一个很好的例子:

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

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

Function<A,B>是接受一种类型的参数并返回另一种类型的任何方法。这可以被称为“转换”。Function<A,B>接受一个 A并返回一个 B。值得注意的是,对于给定的 A值,函数应该始终返回特定的 B值。AB实际上可以是相同的类型,例如:

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

它的实例方法引用 myClass:addTwoFunction<Integer, Integer>ToIntFunction<Integer>

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

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

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

为什么在 Java.util.function 包 中定义 Consumer/Supplier/其他函数接口: Consumer 和 Supplier 是 Java 8中提供的许多内置函数接口中的两个。所有这些内置函数接口的目的是为具有公共函数描述符(函数方法签名/定义)的函数接口提供一个现成的“模板”。

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

Consumer 做什么 : Consumer 函数接口接受一个输入,对该输入执行某些操作,但不提供任何输出。它的定义是这样的(来自 Java 源)-

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

在这里接受()是一个函数抽象方法,它接受一个输入,但不返回任何输出。因此,如果您想要输入一个 Integer,那么使用它做一些没有输出的事情,而不是使用 Consumer 的实例来定义您自己的接口。

Supplier 做什么 : Supplier 函数接口不接受任何输入,但返回输出。它的定义如下所示(来自 Java 源代码)-

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

无论你在什么地方需要一个返回一些东西的函数,比如说一个 Integer,但是没有输出,使用 Supplier 的一个实例。

如果更清晰的情况下,连同示例使用,消费者和供应商接口是需要的,然后你可以参考我的博客文章在同一-http://www.javabrahman.com/java-8/java-8-java-util-function-consumer-tutorial-with-examples/ 还有 http://www.javabrahman.com/java-8/java-8-java-util-function-supplier-tutorial-with-examples/

用外行人的话说,

供应商会提供资料,但不会使用任何资料。在编程术语中,不接受任何参数但返回一个值的方法。它用于生成新值。

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

使用者会使用数据,但不会返回任何数据。在编程术语中,采用多个参数且不返回任何值的方法。

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

1. 意义

看看我对我的问题 给你和另一个 给你的回答,但是简而言之,这些新的接口提供 大会描述性供每个人使用(+ 时髦的方法链接,如 .forEach(someMethod().andThen(otherMethod()))

2. 差异

消费者 : 取某物,做某事,不返回任何东西: void accept(T t)

供应商: 不取任何东西,返回某些东西: T get()(与 Consumer 相反,基本上是一个通用的‘ 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());
}


}