一如既往,我正在查看JDK 8源代码并发现非常有趣的代码:
@Override
default void forEachRemaining(Consumer<? super Integer> action) {
if (action instanceof IntConsumer) {
forEachRemaining((IntConsumer) action);
}
}
Run Code Online (Sandbox Code Playgroud)
问题是:怎么Consumer<? super Integer>可能是一个实例 IntConsumer?因为他们处于不同的等级.
我已经制作了类似的代码片段来测试:
public class InterfaceExample {
public static void main(String[] args) {
IntConsumer intConsumer = i -> { };
Consumer<Integer> a = (Consumer<Integer>) intConsumer;
a.accept(123);
}
}
Run Code Online (Sandbox Code Playgroud)
但它抛出ClassCastException:
Exception in thread "main"
java.lang.ClassCastException:
com.example.InterfaceExample$$Lambda$1/764977973
cannot be cast to
java.util.function.Consumer
Run Code Online (Sandbox Code Playgroud)
你可以在java.util.Spliterator.OfInt#forEachRemaining(java.util.function.Consumer)找到这段代码.
所以我试图重构以下代码:
/**
* Returns the duration from the config file.
*
* @return The duration.
*/
private Duration durationFromConfig() {
try {
return durationFromConfigInner();
} catch (IOException ex) {
throw new IllegalStateException("The config file (\"" + configFile + "\") has not been found.");
}
}
/**
* Returns the duration from the config file.
*
* Searches the log file for the first line indicating the config entry for this instance.
*
* @return The duration.
* @throws FileNotFoundException If …Run Code Online (Sandbox Code Playgroud) 功能接口的定义是"功能接口是一个只有一个抽象方法的接口(除了Object的方法),因此代表一个单一的功能契约."
根据这个定义,Comparable<T>它绝对是一个功能界面.
lambda表达式的定义是"lambda表达式就像一个方法:它提供了一个形式参数列表和一个正文 - 一个表达式或块 - 用这些参数表示."
lambda表达式的评估产生功能接口的实例.
因此,lambda表达式的目的是通过实现功能接口的单个功能来创建功能接口的实例.即.允许使用单个函数创建实例.
让我们来看看Comparable<T>,这个界面是否设计用作单一功能?即.它是否仅用于创建具有此单一功能的实例?
Comparable<T>以"This接口开头的文档对每个实现它的类的对象施加了一个总排序.这个排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法."
上面的句子清楚地表明,Comparable<T>它不是设计用作单个函数,而是总是由一个类实现,它通过添加这个单个函数对其实例具有自然顺序.
这意味着它不是设计为使用lambda表达式创建的?
关键是我们不会有任何仅仅是可比较的对象,它意味着要实现,因此用作类的附加功能.
那么,Java语言中是否有一种方法Comparable<T>可以防止创建lambda表达式?接口的设计者是否可以决定该接口是否由类实现,而不是通过使用lambda表达式使用此单一方法创建为实例?
仅仅因为接口恰好有一个抽象方法,它不应该被视为一个功能接口.
也许,如果Java提供像NotFunctional这样的注释,编译器可以检查该接口是否不用于创建lambda表达式,例如.
@NotFunctional
public interface Comparable<T> { public int compareTo(T t); }
Run Code Online (Sandbox Code Playgroud) 在Java 8中,@FunctionalInterface引入了注释以表示任何具有一个抽象方法作为功能接口的接口.引入它的原因之一是指示用户(程序员),lambda表达式可以在功能接口的上下文中使用.
该Comparator接口都被注解@FunctionalInterface.但是,两种方法都是抽象的.
int compare(T o1, T o2);
Run Code Online (Sandbox Code Playgroud)
和
boolean equals(Object obj);
Run Code Online (Sandbox Code Playgroud)
在文档中FunctionalInterface,它被明确提及为
从概念上讲,功能界面只有一种抽象方法.
这个equals方法不是被认为是抽象的吗?
我可以使用retrolambda来启用Android API级别<24的lambdas.这样可行
myButton.setOnClickListener(view -> Timber.d("Lambdas work!"));
Run Code Online (Sandbox Code Playgroud)
这也有效
Runnable runLater = () -> Timber.d("Lambdas work!");
runLater.run();
Run Code Online (Sandbox Code Playgroud)
但是这个没有
Consumer<Integer> runLaterWithInt = (Integer i) -> Timber.d("i = " + i);
runLaterWithInt.accept(3);
Run Code Online (Sandbox Code Playgroud)
最后一个适用于Android API Level 24,但在其他设备上,此代码会导致崩溃
java.lang.NoClassDefFoundError: com.retrolambdatry.MainActivity$$Lambda$1
Run Code Online (Sandbox Code Playgroud)
我试图启用Java 8.而不是使用retrolambda.前两个代码示例仍然有效,尽管butterknife停止工作.https://developer.android.com/preview/j8-jack.html#configuration这里ava.util.function被认为是支持的,但在运行第三个时,我仍然得到一个崩溃,这一次却是有一点不同
java.lang.NoClassDefFoundError: com.retrolambdatry.MainActivity$-void_onCreate_android_os_Bundle_savedInstanceState_LambdaImpl1
Run Code Online (Sandbox Code Playgroud) 我有一个我已经使用了一段时间的自定义界面,看起来像这样:
public interface Function<T, R> {
R call(T input);
}
Run Code Online (Sandbox Code Playgroud)
我想用Java Function和Guava 来改进这个接口Function,同时保持它FunctionalInterface.我以为我有完美的安排:
@FunctionalInterface
public interface Function<T, R> extends
java.util.function.Function<T, R>,
com.google.common.base.Function<T, R> {
R call(T input);
@Override
default R apply(T input) {
return call(input);
}
}
Run Code Online (Sandbox Code Playgroud)
两个超级apply()接口都声明了相同的方法,该方法已在我的界面中实现,只留下抽象call()方法.奇怪的是,它不会编译,告诉我
"@FunctionalInterface"注释无效; 函数<T,R>不是功能接口
更奇怪的是,以下变化编译得很好:
@FunctionalInterface
public interface Function<T, R> extends
java.util.function.Function<T, R> {
R call(T input);
@Override
default R apply(T input) {
return call(input);
}
}
Run Code Online (Sandbox Code Playgroud)
@FunctionalInterface
public interface Function<T, R> extends
com.google.common.base.Function<T, R> …Run Code Online (Sandbox Code Playgroud) 正如我们在Java 8中所知,引入了功能接口的概念.功能接口有一种abstract方法,可以使用多种默认或静态方法.
但为什么Functional接口只有一个抽象方法呢?如果Interface有多个抽象方法,为什么这不是一个功能接口?
在Java(目前使用Java 8)中,我可以编写这个并且所有编译都很好:
Supplier<Long> asd = () -> {
throw new RuntimeException();
};
Run Code Online (Sandbox Code Playgroud)
但是,我不能这样写:
Supplier<Long> asd = () -> throw new RuntimeException(); // This won't compile :(
Run Code Online (Sandbox Code Playgroud)
有谁知道为什么Java的实现不允许这样的样式(表达式lambda)和只有语句/代码块样式lambda?
我的意思是,由于lambda 只抛出RuntimeException,为什么JDK不能将lambda表达式推断为:
new Supplier<Long>() {
@Override
public Long get() {
throw new RuntimeException();
}
};
Run Code Online (Sandbox Code Playgroud)
这是在specs/docs中的某处记录的吗?这是仅在JDK> 8中添加的吗?
Java 8为我们提供了许多有趣的方法来使用功能接口,并为它们添加了一个新的注释:@FunctionalInterface.如果我们不遵守功能接口的规则(只需要一个需要覆盖的抽象方法),它的工作就是告诉编译器对我们大喊大叫.
java.util.function包中有43个接口,带有此批注.搜索jdk.1.8.0/src @FunctionalInterface只能获得57次点击.为什么其他可能添加的接口(如AutoCloseable)@FunctionalInterface仍然缺少它?
注释文档中有一些模糊的提示:
"用于指示接口类型声明旨在成为功能接口的信息性注释类型"
有没有什么好的理由不打算我设计的接口(可能只是一个功能接口)不能用作一个接口?除了没有意识到它可能被添加之外,是否有任何迹象?
是不是将抽象方法添加到任何已发布的接口来阻止实现它的任何人,功能与否?我觉得玩世不恭,假设他们只是懒得去追捕他们,但其他解释是什么?
更新:看过"应该'可比'是一个'功能界面'?" 我发现我仍然有唠叨的问题.当单一方法接口和功能接口在结构上相同时,它们会有什么不同?简单的名称是不同的?Comparable和Comparator在语义上足够接近.事实证明它们在结构上是不同的,但仍然不是最好的例子......
是否有一种情况,SMI在结构上很好用作功能接口,但仍然不鼓励接口名称和方法的语义含义?或者也许是Javadocs隐含的合同?
这段代码有什么区别?
Supplier<LocalDate> s1 = LocalDate::now;
LocalDate s2 = LocalDate.now();
System.out.println(s1.get()); //2016-10-25
System.out.println(s2); //2016-10-25
Run Code Online (Sandbox Code Playgroud)
我开始学习Java 8中的功能接口,而不了解供应商的好处.究竟何时以及如何使用它们.供应商是否提高了绩效或者提取抽象水平的好处?
谢谢你的回答!这不是重复的问题,因为我使用搜索并没有找到我需要的东西.
更新1: 你的意思是这个?
Supplier<Long> s1 = System::currentTimeMillis;
Long s2 = System.currentTimeMillis();
System.out.println(s1.get()); //1477411877817
System.out.println(s2); //1477411877817
try {
Thread.sleep(3000l);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(s1.get()); //1477411880817 - different
System.out.println(s2); //1477411877817
Run Code Online (Sandbox Code Playgroud)