我正在开发一个Java开源库,并希望确保它对Java 8用户很方便,并且尽可能利用Java 8中的新概念(lambdas等)为Java 8增强库,同时保持向后兼容性
同时我绝对需要保持向后兼容性(对于使用Java 6或7的人来说,该库仍然必须可用)。
我可以采用哪些有用的Java 8特性,这对于库用户是有利的,而不会破坏老版本Java用户的库兼容性?
我正在开发一个Java开源库,并希望确保它对Java 8用户很方便,并且尽可能利用Java 8中的新概念(lambdas等)为Java 8增强库,同时保持向后兼容性
同时我绝对需要保持向后兼容性(对于使用Java 6或7的人来说,该库仍然必须可用)。
我可以采用哪些有用的Java 8特性,这对于库用户是有利的,而不会破坏老版本Java用户的库兼容性?
我不知道你的图书馆,这个建议可能会稍微偏离。
Lambdas:别担心。任何功能接口都可以使用Lambda表达式来实现。
方法参考:与lambda相同,它们应该是可用的。
流:如果这适合你的库,你应该使用它们,但保持兼容性在这里更难。向后兼容性可以通过使用第二个库部件来实现,它围绕基本库并挂接到它的公共API。因此,它可以在不放弃Java 6/7的情况下提供额外的糖/功能。
默认方法:通过一切手段,使用这些!它们是一种快速/便宜/好方法,可以在不破坏现有实现的情况下加强现有实现。您添加的所有默认方法将自动用于实现类。但是,这些将需要第二个库部分,因此您应该在基本库中提供基本接口,并从协同库扩展接口。
不要分叉库,放弃旧的,因为仍然有许多开发人员不能使用Java 8甚至Java 7。 Android,请保持兼容性。
如果您希望您的代码能够被Java 6消耗的虚拟机使用,那么您的必须使用Java 6语言兼容性来编写。唉。字节码格式严格地从6变为7,所以7和8的代码不会加载到6.(我发现这与我自己的代码迁移到7;即使当我所有使用的是多catch
- 应该可写在6字节码 - 我不能建立它的6个目标。编译器拒绝。)
我还没有试验8,但你必须小心,因为如果你依赖任何新的Java包或课程,你会仍然无法使用旧版本;老的虚拟机根本无法访问相关的类,也无法加载代码。特别是,lambdas definitely won't work。
那么,我们可以针对不同的类文件版本吗?没有任何源码和目标的组合可以让javac对此感到满意。
kevin$ $JAVA8/bin/javac -source 1.8 -target 1.7 *.java javac: source release 1.8 requires target release 1.8
因此,根本没有办法将Java源代码与lambda编译为Java 8之前的类文件版本。
我的一般看法是,如果您要支持旧版本的Java,则必须使用旧版本的Java来执行此操作。你可以使用Java 8工具链,但你需要Java 7或Java 6源码。你可以可以通过分支代码来实现它,维护你想支持的所有Java版本的版本,但是这远比你可以作为一个独立的开发者合理得多。选择最低版本,并与那(并亲吻那些多汁的新功能,现在再见,唉)。
为了记录,我目前使用Java 7作为我的主要目标平台。我得到的代码严格要求Java 7的特性(改进的文件系统处理),我根本不针对智能手机。 –
+1表示支持旧Java版本需要使用该版本进行构建。可以试试'$ JAVA8/bin/javac -source 1.7 -target 1.7',但即使这样也会让Java 8库的依赖性无意中蠕动。这样做会导致一个消息,如'warning:[options] bootstrap class path没有与-source 1.7'一起设置,它基本上说你必须将引导类路径设置为指向Java 7.在这一点上,你可能只是以及使用Java 7工具链。 –
如果您在Java 8使用任何新的语言功能,它也需要使用Java字节码8。
$ javac -source 1.8 -target 1.7
javac: source release 1.8 requires target release 1.8
这意味着您的选择非常有限。您不能使用lambdas,方法引用,默认方法,Streams等,并保持向后兼容性。
还有两两件事你可以做到这一点的Java 8的用户将受益。首先是在公共API中使用Functional Interfaces。如果您的方法将Runnables,Callables,Comparators等作为参数,那么Java 8的用户将能够传递lambda表达式。您也可以创建自己的单抽象方法接口。如果你发现你需要函数和谓词,我建议重复使用GS Collections或番石榴而不是自己写的函数。
你可以做的第二件事是使用丰富的馆藏的API,使用功能接口的好处。同样,这意味着使用GS Collections或Guava。例如,如果您有一个将返回List的方法,则返回MutableList或ImmutableList。这样,该方法的调用者将能够链接由这些接口公开的丰富API的用法。
如所述由他人,提供和使用接口与单个方法,使得它们可以使用Java 8时的支持Java 8而不会断裂的Java 7的兼容性的好方法使用的lambda或方法的引用来实现。
这可以通过提供方法你的库,融入标准函数类型的Java 8中的一种补充(如Supplier
,(Bi)Consumer
,(Bi)Function
),这样的Java 8开发人员可以创建他们的方法引用用于Java 8 API方法。这意味着它们的签名与这些功能接口中的一个匹配,并且它们不会抛出检查的异常。这通常是自然的,例如getFoo()
可能充当Function
和isBar()
作为Predicate
,但有时可以通过考虑可能的Java 8使用场景来改进方法。
例如,如果您提供了一个采用两个参数的方法,那么选择第一个参数更有可能是Map
中的一个键的顺序非常有用。所以它更可能用于带有方法参考的Map.forEach
。
避免含有模糊签名的方法。例如。如果你有一个类Foo
与实例方法ReturnType bar()
和static
方法ReturnType bar(Foo)
他们都不可以再使用的方法引用作为Foo::bar
将是不明确的。消除或重命名这些方法之一。
,这种方法不具有多线程使用时会导致令人惊讶的行为无证内部状态是很重要的。否则,它们不能被并行流使用。
不应被低估的另一个机会是使用名为类,接口,符合由Java API 8引入了模式的成员。例如。如果您必须为您的库引入某种过滤器接口并使用适用于您的库的测试方法,则应该将接口Predicate
和方法test
命名为将它与Java 8的类似命名函数接口相关联。
也许你可能会创建一个Java8 fork,并让旧版本可用于需要它的人。 – MightyPork
我想说你可以做的就是在整个API中使用函数接口,这样JDK 8中的用户就可以使用lambda表达式和方法引用来实现它们,这就是它。 –