IT

자바 8 람다 무효 인수

lottoking 2020. 6. 3. 08:09
반응형

자바 8 람다 무효 인수


Java 8에서 다음과 같은 기능 인터페이스가 있다고 가정 해 봅시다.

interface Action<T, U> {
   U execute(T t);
}

그리고 어떤 경우에는 인수 또는 반환 유형이없는 작업이 필요합니다. 그래서 다음과 같이 씁니다.

Action<Void, Void> a = () -> { System.out.println("Do nothing!"); };

그러나 컴파일 오류가 발생하므로 다음과 같이 작성해야합니다.

Action<Void, Void> a = (Void v) -> { System.out.println("Do nothing!"); return null;};

못생긴 것입니다. Voidtype 매개 변수를 제거하는 방법이 있습니까?


다음 구문은 a Runnable변환하는 작은 도우미 함수로 가능합니다 Action<Void, Void>( Action예 : 배치 할 수 있음 ).

public static Action<Void, Void> action(Runnable runnable) {
    return (v) -> {
        runnable.run();
        return null;
    };
}

// Somewhere else in your code
 Action<Void, Void> action = action(() -> System.out.println("foo"));

Supplier아무것도 걸리지 않지만 무언가를 반환하면 사용하십시오 .

Consumer무언가가 필요하지만 아무것도 반환하지 않으면 사용하십시오 .

Callable결과를 반환하고 던질 수있는 경우에 사용하십시오 ( Thunk일반적인 CS 용어 와 유사 ).

Runnable던지지 않고 던질 수없는 경우 사용하십시오 .


람다 :

() -> { System.out.println("Do nothing!"); };

실제로 다음과 같은 인터페이스에 대한 구현을 나타냅니다.

public interface Something {
    void action();
}

정의한 것과는 완전히 다릅니다. 그래서 오류가 발생합니다.

를 확장하거나 @FunctionalInterface새로운 것을 소개 할 수 없으므로 많은 옵션이 없다고 생각합니다. Optional<T>인터페이스를 사용하여 일부 값 (반환 유형 또는 메소드 매개 변수)이 누락되었음을 표시 할 수 있습니다 . 그러나 이것은 람다 본문을 더 단순하게 만들지는 않습니다.


해당 특수한 경우에 대한 하위 인터페이스를 만들 수 있습니다.

interface Command extends Action<Void, Void> {
  default Void execute(Void v) {
    execute();
    return null;
  }
  void execute();
}

기본 메서드사용 하여 상속 된 매개 변수화 된 메서드 를 재정 Void execute(Void)의하여 더 간단한 메서드에 대한 호출을 위임합니다 void execute().

결과적으로 사용이 훨씬 간단 해집니다.

Command c = () -> System.out.println("Do nothing!");

불가능합니다. 무효가 아닌 반환 유형을 가진 함수 Void는 값을 반환해야합니다. 그러나 정적 메소드를 추가하여 Action다음과 같이 "생성"할 수 있습니다 Action.

interface Action<T, U> {
   U execute(T t);

   public static Action<Void, Void> create(Runnable r) {
       return (t) -> {r.run(); return null;};
   }

   public static <T, U> Action<T, U> create(Action<T, U> action) {
       return action;
   } 
}

그러면 다음을 쓸 수 있습니다.

// create action from Runnable
Action.create(()-> System.out.println("Hello World")).execute(null);
// create normal action
System.out.println(Action.create((Integer i) -> "number: " + i).execute(100));

기능적 인터페이스 내에 정적 메소드 추가

package example;

interface Action<T, U> {
       U execute(T t);
       static  Action<Void,Void> invoke(Runnable runnable){
           return (v) -> {
               runnable.run();
                return null;
            };         
       }
    }

public class Lambda {


    public static void main(String[] args) {

        Action<Void, Void> a = Action.invoke(() -> System.out.println("Do nothing!"));
        Void t = null;
        a.execute(t);
    }

}

산출

Do nothing!

함수 정의가 예제에서 일치하지 않기 때문에 가능하지 않다고 생각합니다.

람다 식은 다음과 같이 정확하게 평가됩니다

void action() { }

당신의 선언은 다음과 같습니다

Void action(Void v) {
    //must return Void type.
}

예를 들어 다음과 같은 인터페이스가있는 경우

public interface VoidInterface {
    public Void action(Void v);
}

호환되는 유일한 기능 (인스턴스화 중)은 다음과 같습니다.

new VoidInterface() {
    public Void action(Void v) {
        //do something
        return v;
    }
}

return 문이나 인수가 없으면 컴파일러 오류가 발생합니다.

Therefore, if you declare a function which takes an argument and returns one, I think it is impossible to convert it to function which does neither of mentioned above.


Just for reference which functional interface can be used for method reference in cases method throws and/or returns a value.

void notReturnsNotThrows() {};
void notReturnsThrows() throws Exception {}
String returnsNotThrows() { return ""; }
String returnsThrows() throws Exception { return ""; }

{
    Runnable r1 = this::notReturnsNotThrows; //ok
    Runnable r2 = this::notReturnsThrows; //error
    Runnable r3 = this::returnsNotThrows; //ok
    Runnable r4 = this::returnsThrows; //error

    Callable c1 = this::notReturnsNotThrows; //error
    Callable c2 = this::notReturnsThrows; //error
    Callable c3 = this::returnsNotThrows; //ok
    Callable c4 = this::returnsThrows; //ok

}


interface VoidCallableExtendsCallable extends Callable<Void> {
    @Override
    Void call() throws Exception;
}

interface VoidCallable {
    void call() throws Exception;
}

{
    VoidCallableExtendsCallable vcec1 = this::notReturnsNotThrows; //error
    VoidCallableExtendsCallable vcec2 = this::notReturnsThrows; //error
    VoidCallableExtendsCallable vcec3 = this::returnsNotThrows; //error
    VoidCallableExtendsCallable vcec4 = this::returnsThrows; //error

    VoidCallable vc1 = this::notReturnsNotThrows; //ok
    VoidCallable vc2 = this::notReturnsThrows; //ok
    VoidCallable vc3 = this::returnsNotThrows; //ok
    VoidCallable vc4 = this::returnsThrows; //ok
}

참고URL : https://stackoverflow.com/questions/29945627/java-8-lambda-void-argument

반응형