Java 8 лямбда-аргумент Void
допустим, у меня есть следующий функциональный интерфейс в 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;};
что это некрасиво. Есть ли способ избавиться от Void тип параметра?
8 ответов:
синтаксис, который вы ищете, возможен с помощью небольшой вспомогательной функции, которая преобразует
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"));
лямбда:
() -> { 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!");
это невозможно. Функция, которая имеет тип возврата non-void (даже если это
Void) должен возвращать значение. Однако вы можете добавить статические методы вActionчто позволяет "создать" aAction: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; } }и отсутствие возврата заявление или аргумент даст вы ошибка компилятора.
поэтому, если вы объявите функцию, которая принимает аргумент и возвращает его, я думаю, что невозможно преобразовать его в функцию, которая не делает ни одного из упомянутых выше.
просто для справки, какой функциональный интерфейс может использоваться для ссылки на метод в случаях, когда метод бросает и / или возвращает значение.
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 }
Comments