穹顶灯打不出阴暗面_Java 8星期五:Java 8的阴暗面
穹頂燈打不出陰暗面
在Data Geekery ,我們喜歡Java。 而且,由于我們真的很喜歡jOOQ的流暢的API和查詢DSL ,我們對(duì)Java 8將為我們的生態(tài)系統(tǒng)帶來(lái)什么感到非常興奮。
Java 8星期五
每個(gè)星期五,我們都會(huì)向您展示一些不錯(cuò)的教程風(fēng)格的Java 8新功能,這些功能利用了lambda表達(dá)式,擴(kuò)展方法和其他出色的功能。 您可以在GitHub上找到源代碼 。
Java 8的陰暗面
到目前為止,我們已經(jīng)展示了這個(gè)主要新版本中令人激動(dòng)的部分 。 但是也有一些警告。 其中很多。 那件事
- ……令人困惑
- … 錯(cuò)了
- …被省略(目前)
- …被省略(很長(zhǎng)時(shí)間)
Java主要版本始終有兩個(gè)方面。 從好的方面來(lái)說(shuō),我們獲得了許多新功能,大多數(shù)人會(huì)認(rèn)為這已經(jīng)過(guò)期了 。 其他語(yǔ)言,平臺(tái)早在Java 5之前就有泛型。其他語(yǔ)言,平臺(tái)早在Java 8之前就有l(wèi)ambda。但是現(xiàn)在,我們終于有了這些功能。 在通常的古怪Java方式中。
Lambda表達(dá)式的引入非常優(yōu)美。 從向后兼容的角度來(lái)看,能夠?qū)⒚總€(gè)匿名SAM實(shí)例編寫(xiě)為lambda表達(dá)式的想法非常引人注目。 那么,什么是黑暗面到Java 8?
超載變得更糟
重載,泛型和vararg不是朋友。 我們已經(jīng)在上一篇文章以及這個(gè)Stack Overflow問(wèn)題中 對(duì)此進(jìn)行了解釋 。 在您的奇怪應(yīng)用程序中,這些可能并非每天都有問(wèn)題,但對(duì)于API設(shè)計(jì)人員和維護(hù)人員而言,這是非常重要的問(wèn)題。
使用lambda表達(dá)式,事情變得“更糟”。 因此,您認(rèn)為您可以提供一些便利的API,以重載現(xiàn)有的run()方法(該方法接受Callable并接受新的Supplier類型:
static <T> T run(Callable<T> c) throws Exception {return c.call(); }static <T> T run(Supplier<T> s) throws Exception {return s.get(); }看起來(lái)非常有用的Java 7代碼現(xiàn)在是Java 8的一大難題。 因?yàn)槟荒苤皇褂胠ambda參數(shù)簡(jiǎn)單地調(diào)用這些方法:
public static void main(String[] args) throws Exception {run(() -> null);// ^^^^^^^^^^ ambiguous method call }倒霉。 您將不得不采用以下任一“經(jīng)典”解決方案:
run((Callable<Object>) (() -> null));run(new Callable<Object>() {@Overridepublic Object call() throws Exception {return null;}});因此,盡管總有變通辦法,但這些變通辦法總是“糟透了”。 即使從向后兼容的角度來(lái)看事情不會(huì)中斷,這也真是令人沮喪。
并非所有關(guān)鍵字都支持默認(rèn)方法
默認(rèn)方法是一個(gè)不錯(cuò)的補(bǔ)充。 有人可能聲稱Java最終具有特質(zhì) 。 其他人顯然與該術(shù)語(yǔ)脫離了關(guān)系,例如Br??ian Goetz:
向Java添加默認(rèn)方法的主要目標(biāo)是“接口演變”,而不是“窮人的特征”。
如lambda-dev郵件列表中所示。
事實(shí)是,默認(rèn)方法與Java中的其他任何東西相比,都有很多正交和不規(guī)則的特征。 這里有一些批評(píng):
他們不能成為最終的
鑒于默認(rèn)方法也可以用作API中的便捷方法:
public interface NoTrait {// Run the Runnable exactly oncedefault final void run(Runnable r) {// ^^^^^ modifier final not allowedrun(r, 1);}// Run the Runnable "times" timesdefault void run(Runnable r, int times) {for (int i = 0; i < times; i++)r.run();} }不幸的是,以上操作是不可能的,因此第一個(gè)重載的便捷方法可能會(huì)在子類型中被覆蓋,即使這對(duì)API設(shè)計(jì)人員而言毫無(wú)意義。
無(wú)法使其同步
mm! 用語(yǔ)言難以實(shí)現(xiàn)嗎?
public interface NoTrait {default synchronized void noSynchronized() {// ^^^^^^^^^^^^ modifier synchronized// not allowedSystem.out.println("noSynchronized");} }是的, synchronized很少使用,就像決賽。 但是,當(dāng)您擁有該用例時(shí),為什么不僅僅允許它呢? 是什么使接口方法主體如此特別?
默認(rèn)關(guān)鍵字
這可能是所有功能中最怪異和最不規(guī)則的。 default關(guān)鍵字本身。 讓我們比較一下接口和抽象類:
// Interfaces are always abstract public /* abstract */ interface NoTrait {// Abstract methods have no bodies// The abstract keyword is optional/* abstract */ void run1();// Concrete methods have bodies// The default keyword is mandatorydefault void run2() {} }// Classes can optionally be abstract public abstract class NoInterface {// Abstract methods have no bodies// The abstract keyword is mandatoryabstract void run1();// Concrete methods have bodies// The default keyword mustn't be usedvoid run2() {} }如果從頭開(kāi)始重新設(shè)計(jì)該語(yǔ)言,則可能不需要任何abstract或default關(guān)鍵字。 兩者都是不必要的。 存在或不存在主體的事實(shí)足以使編譯器評(píng)估方法是否抽象。 即,情況應(yīng)該如何:
public interface NoTrait {void run1();void run2() {} }public abstract class NoInterface {void run1();void run2() {} }上面的內(nèi)容將更加精簡(jiǎn)和規(guī)范。 遺憾的是,EG從未真正討論過(guò)default的用途。 好吧,這是經(jīng)過(guò)辯論的,但是EG從來(lái)不想接受這種選擇。 我已經(jīng)嘗試過(guò)運(yùn)氣,下面的響應(yīng) :
我不認(rèn)為#3是一種選擇,因?yàn)榕c方法主體的接口一開(kāi)始是不自然的。 至少指定“默認(rèn)”關(guān)鍵字為讀者提供了某種語(yǔ)言來(lái)說(shuō)明該語(yǔ)言允許使用方法主體的原因。 就個(gè)人而言,我希望接口將保持純合同形式(不執(zhí)行),但是我不知道有更好的選擇來(lái)發(fā)展接口。
同樣,這是EG的明確承諾,即不承諾Java中的“特征”。 默認(rèn)方法是實(shí)現(xiàn)1-2個(gè)其他功能的純粹必要手段。 他們從一開(kāi)始就沒(méi)有精心設(shè)計(jì)。
其他修飾符
幸運(yùn)的是,在項(xiàng)目后期,使用了static修飾符使其成為規(guī)格。 因此現(xiàn)在可以在接口中指定靜態(tài)方法。 但是由于某種原因,這些方法不需要(也不允許!) default關(guān)鍵字,它必須是EG完全隨機(jī)決定的,就像您顯然無(wú)法在接口中定義static final方法一樣。
雖然可見(jiàn)性修飾符已在lambda-dev郵件列表中進(jìn)行了討論 ,但超出了此發(fā)行版的范圍。 也許,我們可以在將來(lái)的版本中獲得它們。
實(shí)際上很少執(zhí)行默認(rèn)方法
有些方法可能在接口上使用了明智的默認(rèn)實(shí)現(xiàn),有人可能會(huì)猜測(cè)。 直觀地,集合接口(例如List或Set會(huì)將它們放在其equals()和hashCode()方法上,因?yàn)檫@些方法的協(xié)定在接口上定義良好。 它還使用listIterator()在AbstractList實(shí)現(xiàn),對(duì)于大多數(shù)定制列表而言,這是合理的默認(rèn)實(shí)現(xiàn)。
如果對(duì)這些API進(jìn)行改造,以使使用Java 8輕松實(shí)現(xiàn)自定義集合,那將是非常不錯(cuò)的。例如,我可以使我的所有業(yè)務(wù)對(duì)象都實(shí)現(xiàn)List ,而不會(huì)浪費(fèi)AbstractList上的單個(gè)基類繼承。
但是,可能有一個(gè)與向后兼容性相關(guān)的令人信服的原因阻止了Oracle的Java 8團(tuán)隊(duì)實(shí)現(xiàn)這些默認(rèn)方法。 凡是向我們發(fā)送此原因的人都將獲得免費(fèi)的jOOQ標(biāo)簽 !
不是在這里發(fā)明的-心態(tài)
在lambda-dev EG郵件列表中也多次批評(píng)了這一點(diǎn)。 而且在撰寫(xiě)本博客系列文章時(shí) ,我只能確認(rèn)新的功能接口讓人很難記住。 由于這些原因,他們感到困惑:
一些原始類型比其他更平等
與所有其他類型相比, int , long , double基本類型是首選的,因?yàn)樗鼈冊(cè)趈ava.util.function包以及整個(gè)Streams API中都具有功能接口。 boolean是二等公民,因?yàn)樗匀话阉龀砂谝粋€(gè)形式BooleanSupplier或Predicate ,或者更糟: IntPredicate 。
所有其他原始類型在該區(qū)域中實(shí)際上并不存在。 即,沒(méi)有針對(duì)byte , short , float和char特殊類型。 盡管滿足最后期限的爭(zhēng)論無(wú)疑是有效的,但這種古怪的現(xiàn)狀將使新手學(xué)習(xí)這種語(yǔ)言更加困難。
這些類型不只是稱為函數(shù)
坦白地說(shuō)。 所有這些類型都只是“功能”。 沒(méi)有人真正關(guān)心Consumer , Predicate , UnaryOperator等之間的隱式差異。
實(shí)際上,當(dāng)您尋找具有非void返回值和兩個(gè)參數(shù)的類型時(shí),您可能會(huì)調(diào)用什么呢? Function2 ? 好吧,你錯(cuò)了。 它稱為BiFunction 。
這是一個(gè)決策樹(shù),用于了解您要查找的類型如何被調(diào)用:
- 您的函數(shù)返回void嗎? 叫做Consumer
- 您的函數(shù)返回boolean嗎? 這叫做Predicate
- 您的函數(shù)返回int , long , double嗎? 叫做XXToIntYY , XXToLongYY , XXToDoubleYY東西
- 您的函數(shù)沒(méi)有參數(shù)嗎? 叫做Supplier
- 您的函數(shù)是否接受單個(gè)int , long , double參數(shù)? 它被稱為IntXX , LongXX , DoubleXX東西
- 您的函數(shù)是否接受兩個(gè)參數(shù)? 叫做BiXX
- 您的函數(shù)是否接受兩個(gè)相同類型的參數(shù)? 叫做BinaryOperator
- 您的函數(shù)返回的類型是否與作為單個(gè)參數(shù)的類型相同? 叫做UnaryOperator
- 您的函數(shù)是否帶有兩個(gè)參數(shù),第一個(gè)是引用類型,第二個(gè)是原始類型? 它稱為ObjXXConsumer (只有使用該配置的使用者存在)
- 否則:稱為Function
好主啊! 最近,我們當(dāng)然應(yīng)該去Oracle Education檢查Oracle Certified Java Programmer課程的價(jià)格是否急劇上漲了……幸運(yùn)的是,有了Lambda表達(dá)式,我們幾乎不必記住所有這些類型!
有關(guān)Java 8的更多信息
Java 5泛型為Java語(yǔ)言帶來(lái)了許多很棒的新功能。 但是也有很多與類型擦除有關(guān)的警告。 Java 8的默認(rèn)方法,Streams API和lambda表達(dá)式將再次為Java語(yǔ)言和平臺(tái)帶來(lái)很多很棒的新功能。 但是我們確信, Stack Overflow很快就會(huì)因在Java 8叢林中迷路的困惑程序員而引發(fā)問(wèn)題。
學(xué)習(xí)所有新功能并非易事,但是新功能(和注意事項(xiàng))仍然存在。 如果您是Java開(kāi)發(fā)人員,則最好在有機(jī)會(huì)時(shí)立即開(kāi)始練習(xí)。 因?yàn)槲覀冞€有很長(zhǎng)的路要走。
翻譯自: https://www.javacodegeeks.com/2014/04/java-8-friday-the-dark-side-of-java-8.html
穹頂燈打不出陰暗面
總結(jié)
以上是生活随笔為你收集整理的穹顶灯打不出阴暗面_Java 8星期五:Java 8的阴暗面的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 学会这些电脑键盘技巧如何快速学习电脑键盘
- 下一篇: 现在性价比比较高的电脑现在性价比比较高的