外行的Java 8供应商和消费者说明


99

作为学习Java的非Java程序员,我现在正在阅读SupplierConsumer接口。而且我无法理解它们的用法和含义。什么时候以及为什么要使用这些接口?有人可以给我一个简单的外行例子吗?我发现Doc例子不够简洁,无法理解。


4
该API文档的每一页都有一个链接标记在上面的“使用”,您可以点击ConsumerSupplier你也可以搜索教程中Consumer...
霍尔格

7
我喜欢Stuart Marks的回答。而且我认为大多数在下面回答的人都忽略了这一点。问题不是“如何”编写供应商,消费者和职能部门。您想在世界上“为什么”?对于不习惯它们的人,它们会使代码复杂得多。但是使用它们的好处尚不清楚。
anton1980 '19

据我所知(我对切向描述也感到沮丧),这只是从一段代码中使用的对象中抽象对象类型和对象处理的一种巧妙方法。只需定义不同的新类并将它们注入Supplier和Consumer接口,就可以将相同的代码应用于许多不同类型的对象。因此,在警察记录系统中,所有犯罪嫌疑人都使用相同的表面代码,但是每个人的最终打印结果取决于每个犯罪嫌疑人的分类,例如“公民”,“小资”,“盗窃”,“重罪”,“坚强”,等
树干

Answers:


95

这是供应商:

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

3
那么,供应商是一种创建返回“某物”的方法实例的方法吗?
james emanon 2015年

3
@jamesemanon确实如此。那可能是方法参考或lambda。
罗希特·贾因

14
与直接调用方法相比,这样做有什么好处?是因为供应商可以像中介一样行事并交出“回报”价值吗?
james emanon 2015年

1
Consumer <Integer,Integer>无效。使用者具有单个类型参数。
纳斯卡'15

2
但是为什么要创建这样的构造?通过使用Java解决了什么问题?
干线

175

您难以理解诸如之类的功能接口的含义的原因java.util.function是,此处定义的接口没有任何意义!它们的存在主要是为了表示结构,而不是语义

对于大多数Java API而言,这是非典型的。典型的Java API(例如类或接口)具有含义,您可以为它表示的内容开发一个思维模型,并使用它来理解其操作。考虑java.util.List例如。A List是其他对象的容器。它们具有序列和索引。列表中包含的对象数由返回size()。每个对象的索引范围为0..size-1(含)。可以通过调用检索索引为i的对象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中的使用位置,以了解它们的含义,并且该含义仅适用于该上下文。


3
所以基本上,它只是作为类型的功能
JGuo

另一个有用的信息可能是功能接口可以具有多种实现的方法,这些方法可以向您的代码添加行为
Jhon Mario Lotero

28

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

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

其实例方法参考myClass::getCount是的实例Supplier<Integer>

A Consumer是接受参数且不返回任何值的任何方法。调用它是出于副作用。用Java术语来说,a Consumervoid方法的惯用法。“设置”方法就是一个很好的例子:

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

它的实例方法的参考myClass::setCount是的一个实例Consumer<Integer>IntConsumer

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

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

其实例方法参考myClass:addTwo是a Function<Integer, Integer>和a ToIntFunction<Integer>

引用吸气剂的Class方法是函数的另一个示例。

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

其类方法参考MyClass::getCount是的一个实例Function<MyClass,Integer>ToIntFunction<MyClass>


15

为什么在java.util.function包中定义了使用者/供应商/其他功能接口:使用者和供应商是Java 8中提供的许多内置功能接口中的两个。所有这些内置功能接口的目的是为具有通用功能描述符(功能方法签名/定义)的功能接口提供现成的“模板”。

可以说,我们需要将类型T转换为另一种类型R。如果要将这样定义的任何函数作为参数传递给方法,则该方法将需要定义一个功能接口,其功能/抽象方法采用参数输入类型T作为输入,并给出类型R作为输出参数。现在,可能有许多这样的场景,程序员最终将为他们的需求定义多个功能接口。为了避免这种情况,简化编程并在功能接口的使用方面引入通用标准,已定义了一组内置的功能接口,例如谓词,功能,消费者和供应商。

消费者做什么:消费者功能接口接受输入,使用该输入执行某项操作,但不提供任何输出。它的定义是这样的(来自Java Source)-

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

这里accept()是functional \ abstract方法,它确实接受输入,但不返回任何输出。因此,如果要输入一个Integer,则对其进行一些操作而没有输出,然后使用Consumer的实例代替定义自己的接口。

供应商做什么:供应商功能接口不接受任何输入,但返回一个输出。其定义如下(来自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/


12

1.意义

在这里查看我对问题的回答,在这里查看其他问题,总之,这些新接口为每个人提供了约定描述性(+时髦的方法链接,例如.forEach(someMethod().andThen(otherMethod()))

2.差异

消费者:采取某件事,做某件事,什么都不返回:void accept(T t)

供应商:不 采取任何行动,返回任何东西:( T get()与消费者相反,基本上是一种通用的“获取”方法)

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


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

}


0

简而言之,

  1. 供应商

表示一个不接受任何参数并产生结果的匿名函数。

  1. 消费者

表示一个接受参数且不产生结果的匿名函数。

另外,还有一个谓词。谓词表示一个匿名函数,该函数接受一个参数并产生一个结果。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.