作为一名学习Java的非Java程序员,我现在正在阅读Supplier
和Consumer
接口。而且我无法围绕他们的用法和意义。您何时以及为何使用这些界面?有人可以给我一个简单的非专业人士的例子......我发现Doc的例子不够简洁,无法理解。
答案 0 :(得分:127)
您在掌握java.util.function
等功能接口的含义时遇到困难的原因是这里定义的接口没有任何意义!它们主要用于表示结构,而不是语义。
这对大多数Java API来说都是非典型的。典型的Java API(例如类或接口)具有意义,您可以为其所代表的内容开发心理模型,并使用它来理解其上的操作。例如,考虑java.util.List
。 List
是其他对象的容器。它们有序列和索引。 size()
返回列表中包含的对象数。每个对象的索引范围为0..size-1(包括)。可以通过调用list.get(i)
来检索索引 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
,则调用映射函数并将其传递给密钥,并期望生成一个值,并将生成的键值对插入到映射中。 / p>
因此,您无法查看Function
(或任何其他功能接口)的规范,并尝试辨别它们的含义。您必须查看它们在其他API中的用途,以了解它们的含义,并且该含义仅适用于该上下文。
答案 1 :(得分:67)
这是供应商:
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);
答案 2 :(得分:22)
Supplier
是任何不带参数并返回值的方法。它的工作实际上是提供一个预期类的实例。例如,对“getter”方法的每个引用都是Supplier
public Integer getCount(){
return this.count;
}
其实例方法引用myClass::getCount
是Supplier<Integer>
的实例。
Consumer
是接受参数并且不返回任何内容的任何方法。它的副作用被调用。在Java术语中,Consumer
是void
方法的惯用语。 'setter'方法就是一个很好的例子:
public void setCount(int count){
this.count = count;
}
其实例方法参考myClass::setCount
是Consumer<Integer>
和IntConsumer
的实例。
Function<A,B>
是接受一种类型的参数并返回另一种类型的任何方法。这可以称为“转换”。 Function<A,B>
需要A
并返回B
。值得注意的是,对于给定的A
值,函数应始终返回特定值B
。 A
和B
实际上可以是同一类型,例如:
public Integer addTwo(int i){
return i+2;
}
其实例方法参考myClass:addTwo
是Function<Integer, Integer>
和ToIntFunction<Integer>
。
对getter的Class方法引用是函数的另一个示例。
public Integer getCount(){
return this.count;
}
其类方法引用MyClass::getCount
是Function<MyClass,Integer>
和ToIntFunction<MyClass>
的实例。
答案 3 :(得分:10)
为什么在java.util.function包中定义了消费者/供应商/其他功能接口:消费者和供应商是Java 8中提供的内置功能接口中的两个。所有这些内置功能接口的目的是为具有通用功能描述符(功能方法签名/定义)的功能接口提供现成的“模板”。
假设我们需要将类型T转换为另一种类型R.如果我们将任何函数定义为这样的参数作为参数传递给方法,那么该方法需要定义功能接口,其功能/抽象方法将类型T的参数作为输入,并给出类型为R的参数作为输出。现在,可能有许多这样的场景,程序员最终会根据需要定义多个功能接口。为了避免这种情况,简化编程和为功能接口的使用带来了一个共同的标准,一组内置的功能接口,如Predicate,Function,Consumer&amp;已定义供应商。
消费者做什么:消费者功能接口接受输入,对该输入执行某些操作并且不提供任何输出。它的定义是这样的(来自Java Source) -
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
这里accept()是一个函数\ abstract方法,它接受输入并且不返回任何输出。因此,如果你想输入一个Integer,用它做一些没有输出的东西,那么使用Consumer的一个实例而不是定义你自己的接口。
供应商做什么:供应商功能界面不接受任何输入但返回输出。它的定义如下(来自Java Source) -
@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/
答案 4 :(得分:8)
查看我的问题here和另一个here的答案,但简而言之,这些新界面为每个人提供约定和描述性使用(+ {funky方法链接,如.forEach(someMethod().andThen(otherMethod()))
消费者:采取行动,做某事,不做任何回报:void accept(T t)
供应商:什么也不做,退货:T get()
(与消费者相反,基本上是一种普遍的&#39; getter&#39;方法)
// 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;
}
}
答案 5 :(得分:0)
在Laymen术语中,
供应商将提供数据但不消耗任何数据。在编程术语中,一种方法不会取任何参数但返回一个值。它用于生成新值。
http://codedestine.com/java-8-supplier-interface/
消费者将使用数据但不返回任何数据。在编程术语中,一个采用多个参数并且不返回任何值的方法。
答案 6 :(得分:0)
消费者和供应商是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());
}
}
答案 7 :(得分:0)
最简单的答案可以是:
使用者可以被视为功能