好的,所以方法重载是一个糟糕的事情.既然已经解决了这个问题,我们假设我实际上想要重载这样的方法:
static void run(Consumer<Integer> consumer) {
System.out.println("consumer");
}
static void run(Function<Integer, Integer> function) {
System.out.println("function");
}
Run Code Online (Sandbox Code Playgroud)
在Java 7中,我可以使用非模糊的匿名类作为参数轻松地调用它们:
run(new Consumer<Integer>() {
public void accept(Integer integer) {}
});
run(new Function<Integer, Integer>() {
public Integer apply(Integer o) { return 1; }
});
Run Code Online (Sandbox Code Playgroud)
现在在Java 8中,我当然想用lambda表达式调用这些方法,我可以!
// Consumer
run((Integer i) -> {});
// Function
run((Integer i) -> 1);
Run Code Online (Sandbox Code Playgroud)
既然编译器应该能够推断出来Integer,为什么我不离开Integer呢?
// Consumer
run(i -> {});
// Function
run(i -> 1);
Run Code Online (Sandbox Code Playgroud)
但这不编译.编译器(javac,jdk1.8.0_05)不喜欢这样:
Test.java:63: error: reference to run is …Run Code Online (Sandbox Code Playgroud) 我正在玩java8 lambdas,我遇到了编译器错误,我没想到.
假设我有一个函数interface A,一个abstract class B和一个class C重载方法,它们可以采用A或B作为参数:
public interface A {
void invoke(String arg);
}
public abstract class B {
public abstract void invoke(String arg);
}
public class C {
public void apply(A x) { }
public B apply(B x) { return x; }
}
Run Code Online (Sandbox Code Playgroud)
然后我可以传入一个lambda c.apply,它正确地解决了c.apply(A).
C c = new C();
c.apply(x -> System.out.println(x));
Run Code Online (Sandbox Code Playgroud)
但是当我更改B作为泛型版本的参数的重载时,编译器报告两个重载是不明确的.
public class C {
public void apply(A x) { …Run Code Online (Sandbox Code Playgroud) 我有以下代码:
public class LambdaTest1 {
public static void method1(Predicate<Integer> predicate){
System.out.println("Inside Predicate");
}
public static void method1(Function<Integer,String> function){
System.out.println("Inside Function");
}
public static void main(String[] args) {
method1((i) -> "Test");
}
}
Run Code Online (Sandbox Code Playgroud)
这给我一个错误信息
"方法method1(谓词)对于LambdaTest1类型是不明确的".
我可以看到,对于Function和Consumer功能接口,输入参数是Integer.但对于Function,返回类型是String.
因为我的lambda调用具有返回值"Text" - 这应该调用我的Function函数接口而不是抛出此错误.
任何人都可以解释这种行为背后的原因吗?
另一个例子:
public class LambdaTest1 {
public static void method1(Consumer<Integer> consumer){
System.out.println("Inside Consumer");
}
public static void method1(Predicate<Integer> predicate){
System.out.println("Inside Predicate");
}
public static void main(String[] args) {
List<Integer> lst …Run Code Online (Sandbox Code Playgroud) 当使用双冒号运算符来引用重载方法时,Java似乎无法确定要使用的正确方法.考虑这个例子:
public class A {
private void setter(final Number value) { }
private void setter(final Optional<Number> value) { }
private void setter2(final Optional<Number> value) { }
private <T> void useSetter(final Consumer<Optional<T>> a) { }
private void callMethod() {
useSetter(this::setter); // Error here
useSetter(this::setter2);
}
}
Run Code Online (Sandbox Code Playgroud)
第一次调用useSetter不编译并给出以下错误:
Cannot infer type argument(s) for <T> useSetter(Consumer<Optional<T>>)
The type A does not define setter(Optional<Object>) that is applicable here
Run Code Online (Sandbox Code Playgroud)
但是,第二个调用编译得很好,这意味着问题在于重载setter.只有一个setter重载是适用的,所以我不明白为什么这不起作用.
可以通过使用指定参数类型的lambda解决这个问题,但这更详细.
useSetter((final Optional<Number> v) -> setter(v));
Run Code Online (Sandbox Code Playgroud)
有没有更好的方法来处理这种情况,或者我是否陷入了这个奇怪的怪癖?
我有以下类与重载方法:
import java.util.ArrayList;
import java.util.concurrent.Callable;
public abstract class Test {
public void test1 () {
doStuff (ArrayList::new); // compilation error
}
public void test2 () {
doStuff ( () -> new ArrayList<> ());
}
public abstract void doStuff (Runnable runable);
public abstract void doStuff (Callable<ArrayList<String>> callable);
}
Run Code Online (Sandbox Code Playgroud)
该方法test1导致错误消息的编译错误
The method doStuff(Runnable) is ambiguous for the type Test.
我添加了第三种方法test3,如下所示:
public void test3 () {
doStuff ( () -> {
new ArrayList<> ();
});
}
Run Code Online (Sandbox Code Playgroud)
这里doStuff(Runnable) …
我有一个重载方法,它将两个不同的功能接口作为参数(Runnble和Supplier).System.out.println显然只是兼容Runnable,因为它是一种void方法.然而,编译器仍然声称呼叫是模糊的.怎么可能?
import java.util.function.Supplier;
public class GenericLambdas {
public static void main(String[] args) {
wrap(System.out::println); // Compiler error here
wrap(() -> {}); // No error
wrap(System.out::flush); // No error
}
static <R> void wrap(Supplier<R> function) {}
static void wrap(Runnable function) {}
}
Run Code Online (Sandbox Code Playgroud)
编译器输出:
Error:Error:line (5)java: reference to wrap is ambiguous
both method <R>wrap(java.util.function.Supplier<R>) in GenericLambdas and method wrap(java.lang.Runnable) in GenericLambdas match
Error:Error:line (5)java: incompatible types: cannot infer type-variable(s) R
(argument mismatch; …Run Code Online (Sandbox Code Playgroud)