Java 8 lambda 无效参数
Java 8 lambda Void argument
假设我在 Java 8 中有以下功能接口:
interface Action<T, U> {
U execute(T t);
}
在某些情况下,我需要一个没有参数或 return 类型的动作。所以我写
像这样:
Action<Void, Void> a = () -> { System.out.println("Do nothing!"); };
但是,它给我编译错误,我需要把它写成
Action<Void, Void> a = (Void v) -> { System.out.println("Do nothing!"); return null;};
这很丑。有什么方法可以去掉 Void
类型参数吗?
拉姆达:
() -> { System.out.println("Do nothing!"); };
实际上表示接口的实现,例如:
public interface Something {
void action();
}
这与您定义的完全不同。这就是您收到错误的原因。
既然你不能扩展你的@FunctionalInterface
,也不能引入一个全新的,那么我认为你没有太多选择。不过,您可以使用 Optional<T>
接口来表示缺少某些值(return 类型或方法参数)。但是,这不会使 lambda 主体更简单。
我认为这是不可能的,因为函数定义与您的示例不匹配。
您的 lambda 表达式的计算结果与
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 语句或参数都会给您带来编译器错误。
因此,如果您声明一个接受参数的函数并且 return 有一个参数,我认为不可能将其转换为上述两者都没有的函数。
你所追求的语法可以通过一个小的辅助函数来实现,该函数将 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"));
那是不可能的。具有非空 return 类型(即使它是 Void
)的函数必须 return 一个值。但是,您可以向 Action
添加静态方法,这样您就可以 "create" a 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));
您可以为这种特殊情况创建一个子界面:
interface Command extends Action<Void, Void> {
default Void execute(Void v) {
execute();
return null;
}
void execute();
}
它使用 default method 覆盖继承的参数化方法 Void execute(Void)
,将调用委托给更简单的方法 void execute()
。
结果是使用起来简单多了:
Command c = () -> System.out.println("Do nothing!");
在你的功能接口中添加一个静态方法
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!
仅供参考在方法抛出and/orreturns一个值的情况下,哪些功能接口可以用于方法引用。
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
}
如果什么都不用,就用Supplier
,但是returns一些东西。
如果需要,请使用 Consumer
,但 returns 什么都不用。
在通用 CS 术语中使用 Callable
if it returns a result and might throw (most akin to Thunk
。
如果两者都不做且不能抛出,则使用 Runnable
。
我认为这个 table 简短而有用:
Supplier () -> x
Consumer x -> ()
BiConsumer x, y -> ()
Callable () -> x throws ex
Runnable () -> ()
Function x -> y
BiFunction x,y -> z
Predicate x -> boolean
UnaryOperator x1 -> x2
BinaryOperator x1,x2 -> x3
如其他答案所述,此问题的合适选项是Runnable
假设我在 Java 8 中有以下功能接口:
interface Action<T, U> {
U execute(T t);
}
在某些情况下,我需要一个没有参数或 return 类型的动作。所以我写 像这样:
Action<Void, Void> a = () -> { System.out.println("Do nothing!"); };
但是,它给我编译错误,我需要把它写成
Action<Void, Void> a = (Void v) -> { System.out.println("Do nothing!"); return null;};
这很丑。有什么方法可以去掉 Void
类型参数吗?
拉姆达:
() -> { System.out.println("Do nothing!"); };
实际上表示接口的实现,例如:
public interface Something {
void action();
}
这与您定义的完全不同。这就是您收到错误的原因。
既然你不能扩展你的@FunctionalInterface
,也不能引入一个全新的,那么我认为你没有太多选择。不过,您可以使用 Optional<T>
接口来表示缺少某些值(return 类型或方法参数)。但是,这不会使 lambda 主体更简单。
我认为这是不可能的,因为函数定义与您的示例不匹配。
您的 lambda 表达式的计算结果与
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 语句或参数都会给您带来编译器错误。
因此,如果您声明一个接受参数的函数并且 return 有一个参数,我认为不可能将其转换为上述两者都没有的函数。
你所追求的语法可以通过一个小的辅助函数来实现,该函数将 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"));
那是不可能的。具有非空 return 类型(即使它是 Void
)的函数必须 return 一个值。但是,您可以向 Action
添加静态方法,这样您就可以 "create" a 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));
您可以为这种特殊情况创建一个子界面:
interface Command extends Action<Void, Void> {
default Void execute(Void v) {
execute();
return null;
}
void execute();
}
它使用 default method 覆盖继承的参数化方法 Void execute(Void)
,将调用委托给更简单的方法 void execute()
。
结果是使用起来简单多了:
Command c = () -> System.out.println("Do nothing!");
在你的功能接口中添加一个静态方法
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!
仅供参考在方法抛出and/orreturns一个值的情况下,哪些功能接口可以用于方法引用。
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
}
如果什么都不用,就用Supplier
,但是returns一些东西。
如果需要,请使用 Consumer
,但 returns 什么都不用。
在通用 CS 术语中使用 Callable
if it returns a result and might throw (most akin to Thunk
。
如果两者都不做且不能抛出,则使用 Runnable
。
我认为这个 table 简短而有用:
Supplier () -> x
Consumer x -> ()
BiConsumer x, y -> ()
Callable () -> x throws ex
Runnable () -> ()
Function x -> y
BiFunction x,y -> z
Predicate x -> boolean
UnaryOperator x1 -> x2
BinaryOperator x1,x2 -> x3
如其他答案所述,此问题的合适选项是Runnable