평신도를위한 Java 8 공급 업체 및 소비자 설명


101

Java를 배우는 비 Java 프로그래머로서 나는 현재 SupplierConsumer인터페이스에 대해 읽고 있습니다. 그리고 나는 그들의 사용법과 의미에 대해 머리를 감쌀 수 없습니다. 이 인터페이스를 언제, 왜 사용합니까? 누군가 나에게 이것에 대한 간단한 평신도 예제를 줄 수 있습니까? 나는 Doc 예제가 내 이해에 충분히 간결하지 않다는 것을 발견하고 있습니다.


4
은 API 문서의 각 페이지 링크가 당신이 클릭 할 수 있습니다 상단의 "사용"을 표시했다 ConsumerSupplier또한 검색 할 수 있습니다 자습서 를 들어 Consumer...
홀거

7
나는 Stuart Marks의 대답을 좋아합니다. 그리고 아래에 대답 한 대부분의 사람들이 요점을 놓친 것 같습니다. 문제는 공급자, 소비자 및 기능을 작성하는 "방법"이 아닙니다. 세계에서 "왜"를 원하십니까? 익숙하지 않은 사람에게는 코드가 훨씬 더 복잡해집니다. 그러나 그것들을 사용하는 이점은 명확하지 않습니다.
anton1980

내가 볼 수있는 한 (그리고 나는 접선 설명과 함께 당신의 좌절감을 공유한다) 그것은 코드 조각에 사용 된 객체로부터 객체 유형과 객체 처리를 모두 추상화하는 매끄러운 방법 일 뿐이다. 이를 통해 단순히 서로 다른 새 클래스를 정의하고이를 공급 업체 및 소비자 인터페이스에 주입함으로써이 동일한 코드를 다양한 유형의 객체에 적용 할 수 있습니다. 따라서 경찰 기록 시스템에서는 모든 용의자에게 동일한 피상적 코드가 사용되지만 각 용의자에 대한 최종 출력은 각 용의자의 분류에 따라 달라집니다. 예 : '시민', '소품', '라센', '중범', '경화', 기타
Trunk

답변:


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

3
그렇다면 공급자는 '무언가'를 반환하는 메서드의 인스턴스를 만드는 방법입니까?
james emanon

3
@jamesemanon 맞아요. 메서드 참조 또는 람다 일 수 있습니다.
Rohit Jain

14
메서드를 직접 호출하는 것보다 이것의 이점은 무엇입니까? 공급 업체가 중개자처럼 행동하여 "반품"가치를 전달할 수 있기 때문입니까?
james emanon

1
Consumer <Integer, Integer>가 유효하지 않습니다. 소비자에는 단일 유형 매개 변수가 있습니다.
nascar

2
하지만 왜 그런 구조를 만들까요? Java에서 문제를 해결하면 어떤 문제가 해결됩니까?
Trunk

177

에서와 같은 기능적 인터페이스의 의미를 이해하는 데 어려움을 겪는 이유 java.util.function는 여기에 정의 된 인터페이스가 의미가 없기 때문입니다! 그것들은 주로 의미론이 아니라 구조 를 나타 내기 위해 존재 합니다.

이는 대부분의 Java API에서 일반적이지 않습니다. 클래스 또는 인터페이스와 같은 일반적인 Java API에는 의미가 있으며, 그것이 나타내는 것에 대한 멘탈 모델을 개발하고이를 사용하여 작업을 이해할 수 있습니다. 고려 java.util.List예를 들어. A List는 다른 개체의 컨테이너입니다. 시퀀스와 인덱스가 있습니다. 목록에 포함 된 개체 수는에서 반환합니다 size(). 각 개체에는 0..size-1 (포함) 범위의 인덱스가 있습니다. 인덱스 i에 있는 객체 는를 호출하여 검색 할 수 있습니다 list.get(i). 기타 등등.

의 기능적 인터페이스에는 java.util.function그러한 의미가 없습니다. 대신 인수 수, 반환 값 수 및 (때로는) 인수 또는 반환 값이 원시인지 여부와 같은 함수 의 구조 를 단순히 나타내는 인터페이스입니다 . 따라서 우리는 TFunction<T,R> 유형의 단일 인수를 취하고 유형 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::setCountConsumer<Integer>및 의 인스턴스입니다 IntConsumer.

A Function<A,B>는 한 유형의 인수를 취하고 다른 유형을 리턴하는 모든 메소드입니다. 이를 '변환'이라고 할 수 있습니다. 는 Function<A,B>을 소요 A하고를 반환합니다 B. 주목할만한 점은 주어진 값에 A대해 함수가 항상 특정 값을 반환해야한다는 것입니다 B. A그리고 B실제로 같은 다음과 같은 유형이 될 수 있습니다 :

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

인스턴스 메서드 참조 myClass:addTwo는 a Function<Integer, Integer>ToIntFunction<Integer>.

getter에 대한 클래스 메서드 참조는 함수의 또 다른 예입니다.

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

클래스 메서드 참조 MyClass::getCountFunction<MyClass,Integer>및 의 인스턴스입니다 ToIntFunction<MyClass>.


15

java.util.function 패키지에 소비자 / 공급자 / 기타 기능 인터페이스가 정의 된 이유 : 소비자와 공급자는 Java 8에서 제공되는 내장 기능 인터페이스 중 두 가지입니다. 이러한 내장 기능 인터페이스의 목적은 다음과 같습니다. 공통 기능 설명자 (기능적 메서드 서명 / 정의)를 갖는 기능적 인터페이스를위한 준비된 "템플릿"을 제공합니다.

우리는 우리가 통과한다면 다른 종류의 R.에 T 형으로 변환 할 필요가 말할 수 있는 방법에 매개 변수로 다음과 같이 정의 함수를 다음 방법은 그 기능 기능적 인터페이스를 정의 할 필요가 있음을 / 추상 메소드는 매개 변수를 유형 T를 입력으로하고 R 유형의 매개 변수를 출력으로 제공합니다. 이제 이와 같은 많은 시나리오가있을 수 있으며 프로그래머는 필요에 따라 여러 기능 인터페이스를 정의하게됩니다. 이러한 종류의 시나리오를 방지하고 프로그래밍을 쉽게하고 기능 인터페이스 사용에 대한 공통 표준을 가져 오기 위해 Predicate, Function, Consumer & Supplier와 같은 내장 기능 인터페이스 세트가 정의되었습니다.

소비자가하는 일 : 소비자 기능 인터페이스는 입력을 받아들이고 해당 입력으로 무언가를 수행하며 출력을 제공하지 않습니다. 정의는 다음과 같습니다 (Java 소스에서)-

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

여기서 accept ()는 입력을 받고 출력을 반환하지 않는 function \ 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()(소비자의 역, 기본적으로 보편적 인 '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;
    }
}

0

Laymen 용어로,

공급자는 데이터를 제공하지만 데이터를 소비하지 않습니다. 프로그래밍 용어에서 인수를받지 않고 값을 반환하는 메서드입니다. 새 값을 생성하는 데 사용됩니다.

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

소비자는 데이터를 소비하지만 데이터를 반환하지는 않습니다. 프로그래밍 용어에서 여러 인수를 사용하고 값을 반환하지 않는 메서드입니다.

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


0

소비자와 공급자는 자바에서 제공하는 인터페이스입니다. 소비자는 목록 요소를 반복하는 데 사용되며 공급자는 공급 개체의

코드 데모로 쉽게 이해할 수 있습니다.

소비자

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

가장 간단한 대답은 다음과 같습니다.

소비자는 Function <T, Void>로 볼 수 있습니다. 공급 업체는 Function <Void, T>로 볼 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.