可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
Let's say I have the following functional interface in Java 8:
interface Action<T, U> {
U execute(T t);
}
And for some cases I need an action without arguments or return type. So I write
something like this:
Action<Void, Void> a = () -> { System.out.println("Do nothing!"); };
However, it gives me compile error, I need to write it as
Action<Void, Void> a = (Void v) -> { System.out.println("Do nothing!"); return null;};
Which is ugly. Is there any way to get rid of the Void
type parameter?
回答1:
The syntax you're after is possible with a little helper function that converts a Runnable
into Action<Void, Void>
(you can place it in Action
for example):
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"));
回答2:
Use Supplier
if it takes nothing, but returns something.
Use Consumer
if it takes something, but returns nothing.
Use Callable
if it returns a result and might throw (most akin to Thunk
in general CS terms).
Use Runnable
if it does neither and cannot throw.
回答3:
The lambda:
() -> { System.out.println("Do nothing!"); };
actually represents an implementation for an interface like:
public interface Something {
void action();
}
which is completely different than the one you've defined. That's why you get an error.
Since you can't extend your @FunctionalInterface
, nor introduce a brand new one, then I think you don't have much options. You can use the Optional<T>
interfaces to denote that some of the values (return type or method parameter) is missing, though. However, this won't make the lambda body simpler.
回答4:
You can create a sub-interface for that special case:
interface Command extends Action<Void, Void> {
default Void execute(Void v) {
execute();
return null;
}
void execute();
}
It uses a default method to override the inherited parameterized method Void execute(Void)
, delegating the call to the simpler method void execute()
.
The result is that it's much simpler to use:
Command c = () -> System.out.println("Do nothing!");
回答5:
That is not possible. A function that has a non-void return type (even if it's Void
) has to return a value. However you could add static methods to Action
that allows you to "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;
}
}
That would allow you to write the following:
// 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));
回答6:
Add a static method inside your functional interface
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);
}
}
Output
Do nothing!
回答7:
I don't think it is possible, because function definitions do not match in your example.
Your lambda expression is evaluated exactly as
void action() { }
whereas your declaration looks like
Void action(Void v) {
//must return Void type.
}
as an example, if you have following interface
public interface VoidInterface {
public Void action(Void v);
}
the only kind of function (while instantiating) that will be compatibile looks like
new VoidInterface() {
public Void action(Void v) {
//do something
return v;
}
}
and either lack of return statement or argument will give you a compiler error.
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.
回答8:
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
}