// JDK 1.1 doesn't support readResolve necessary for the assertion
if (!System.getProperty("java.version").startsWith("1.1.")) {
assertTrue(obj == Level.INFO);
}
// No need to change the old Java 6 style implementation
public void forEach(Consumer<T> c);
default void forEach(java.util.function.Consumer<T> c){
// Your Consumer needs a constructor for j.u.f.C
Consumer<T> myC = new Consumer<T>(c);
forEach(myC);
}
型
Defender方法 * 示例:
// Consumer extends j.u.f.C so this is more specific and will override
default void forEach(Consumer<T> c){
// All we need to call the other method is an explicit cast
forEach((java.util.function.Consumer<T>) c);
}
//All new Java 8 style implementation here
public void forEach(java.util.function.Consumer<T> c);
public interface MyIterable<T> extends Iterable<T> {
default void each(MyConsumer<? super T> action){
//Iterable.super.forEach((Consumer<? super T>) action);
//
// Or whatever else we need to do for our special
// class processing
}
default void each(Consumer<? super T> action){
if (action instanceof MyConsumer){
each((MyConsumer<? super T>) action);
} else {
Iterable.super.forEach(action);
}
}
@Override
default void forEach(Consumer<? super T> action){
each(action);
}
}
8条答案
按热度按时间agxfikkp1#
您可以从一个pom.xml文件为每个Java版本(6、7、8)生成一个jar。
所有相关的工作都发生在maven-compiler-plugin:compile mojo中。
诀窍是执行mojo 3次,每次将结果文件写入不同的outputFileName。这将导致编译器多次运行,每次使用不同的版本并吐出适当命名的文件。
字符串
希望能帮上忙。
编辑
RE:每个运行都针对不同源代码编译的附加要求。
参见上面对pom片段的编辑。
每个 * 执行 * 都可以定义自己的 * 依赖项 * 库列表。
因此,JDK 6构建依赖于ABC.jar,而JDK 7依赖于XYZ.jar。
8oomwypt2#
你可以通过为每个java版本创建单独的配置文件来有条件地包含一些源目录。然后你可以用配置文件名运行maven,它将定义你想要使用的版本的源。在这种情况下,所有公共源都保留在
src/main/java
中,而java版本依赖文件放在/src/main/java-X.X directories
中。字符串
您可以通过将硬编码的java-X.X替换为属性(您将与profile一起传递给maven)来更动态地执行此操作。这将类似于:
型
当你运行它的时候,你只需要传递
mvn -Pconditional-java -Dmy.java.version=1.6
。这需要你把java版本相关的文件放在不同的目录中。在IDE中,当你针对特定的java版本进行开发时,只需将与你的java版本相关的目录标记为源文件夹(因为默认情况下IDE只会将src/main/java识别为源目录)。
同样的方式,你可以把编译器级别传递给maven编译器插件:
型
t40tm48m3#
为什么不收集每个java版本中应该不同的方法,将它们 Package 在一个“实用程序”项目中,制作您自己的主代码可以调用的API,并在发布时添加您想要的任何实用程序jar?
例如:
util-api.jar(主项目调用的方法)
util-1.6.jar(无论哪个实现都适用,如果需要,即使是“无操作”,也不需要做任何事情)
我已经成功地做了很多次类似的问题,你现在有一个。
n6lpvg4x4#
在决定迁移到基于Gradle的构建之前,从事Hibernate工作的人已经与这个问题斗争了一段时间。
查看Gradle: why?了解更多信息。
iibxawm45#
一种方法是嵌入到代码中:来自log4j 2源代码:
字符串
你也可以使用https://github.com/raydac/java-comment-preprocessor并根据java版本设置变量来改变代码。虽然这样做的地方很少,因为这将很难调试。或者至少在动态代码运行之前打印一个日志,这样你就知道哪个版本/真实的行有问题。
xxe27gdn6#
为了这种事,我会
u2nhd7ah7#
您需要做的是定义一个基本的API,然后将新版本的Java可用的功能作为额外的方法(可以从您原来的API方法中调用)添加进去。这使得您的API的基本完整性从旧的实现到新的实现保持不变。
举例来说:
字符串
是原始的API方法,其中Consumer是org. mylib. Consumer。在Java 8中,您可以使用它做两件事。您可以保留旧的实作,并新增一个新方法作为该方法的 * 便利方法 *,或者您可以新增新的实作,并新增一个 *defender方法 * 来呼叫新的实作。不论是哪种方式,实作API的旧版程式码都将保持有效。
型
型
显然,对于Java 7版本,您不能在Interface上定义默认方法,因此您必须在抽象基类中实现这些方法,但概念是基本相同的。从理论上讲,在Java 8中,您不需要defender,因为调用可以完全相同,因为Consumer的任何有效示例都是j.u.f.C的有效示例。
Java8第一次意味着它完全可以在现有接口中添加新方法,但是Java 6和Java7之间的API签名不应该有什么不同。
对于Java 6和7,只需在源代码中避免以下内容,就可以编译为这两种代码:
我并不知道是否有为J6编写的代码在为J8编译时不能在J8 JVM上运行,但我知道您可能希望库的较新版本利用J8的改进,如流和lambda。
您可能还想从Java7开始研究Java服务提供者api。它允许您在基本模块中定义API,并将实现安装为Java服务插件jar文件,只要它们位于应用程序的类路径中,JVM就可以检测到这些文件。然后,您可以在新特性可用时简单地定义新的服务插件jar。当然,这对您的Java 6没有帮助实现,但是您可以使用J6 API作为基础,为J7 API添加服务附加功能,并在JVM更新时不断添加和替换服务。
igetnqfo8#
我在这里添加了另一个答案,以回应Leventov关于需要显式转换的最后评论,并提供此建议。这可能是也可能不是坏的实践,但我发现它在某些情况下非常有用,因为我想注入一些预处理或后处理,或者在别人的抽象层之上提供自己的抽象层(例如,我们为Hibernate的Work类定义了一个这样的类,这样如果Hibernate的API在将来发生变化,我们的实现就不必改变--只需要在我们的Interface中使用默认方法),这可能会使同一个接口的两个版本的使用变得更容易。
想想这个:函数式接口的美妙之处在于它只有一个抽象方法,所以你可以传递一个lambda作为该方法的实现。
但是,当你扩展一个接口时,你仍然希望它具有相同的功能(传递一个lambda,并在所有情况下工作),Java 8的另一个优点发挥作用:Defender方法。任何地方都没有说你必须像父类那样保留Defender方法抽象。你可以将接口扩展为一种拦截器接口。所以你可以这样定义你的MyConsumer:
字符串
我们的接口,而不是将accept(T)定义为一个抽象方法,实现了accept(T),并定义了一个抽象方法getConsumer()。这使得示例化MyConsumer的lambda与示例化j.u.f.Consumer所需的lambda不同,并消除了编译器的类冲突。然后您可以定义实现Iterable的类来实现您自己的自定义接口扩展Iterable。
型
它仍然有一个forEach方法,允许它遵循可迭代的iterface,但是你的所有代码都可以在你的API的所有版本中调用each()而不是forEach()。这样你的代码也部分地面向未来-如果底层的Java API在几年后被弃用,你可以修改默认的each()方法来以新的方式做事情,但在其他任何地方 * 所有现有的实现代码在功能上仍然是正确的 *。
因此,当你调用API.each时,不需要显式的强制转换,你只需将lambda传递给另一个方法.在MyConsumer中,该方法返回一个消费者,所以你的lambda真的很简单,你只需将lambda零参数构造函数添加到你前面的语句中。消费者中的accept()方法接受一个参数并返回一个void,所以如果你定义它没有参数,Java知道它需要一个接口,它有一个不带参数的抽象方法,这个lambda示例化了MyConsumer。
型
而这个示例化了j.u.f.消费者
型
因为原始的抽象方法(accept)在那里,并且已经实现,所以它仍然是Consumer的有效示例,并且在所有情况下都可以工作,但是因为我们调用了0-arg构造函数,所以我们已经显式地使它成为我们自定义接口的示例。这样,我们仍然满足Consumer的接口契约,但是我们可以区分我们接口的签名和Consumer的签名。