jdk内置线程实例_EA问题的JDK14实例
jdk內(nèi)置線程實(shí)例
Tagir Valeev最近發(fā)布了一條有關(guān)即將發(fā)布的Java JDK14版本的預(yù)覽功能的推文:
#Java14模式匹配將名稱(chēng)隱藏帶入了更高的瘋狂程度。 在這里,我為FLAG字段添加或刪除了final修飾符,該修飾符僅在不可達(dá)的if分支中訪問(wèn)。 這實(shí)際上改變了程序的語(yǔ)義! #ProgrammingIsFun 。 pic.twitter.com/UToRY3mpW9
#Java14模式匹配將名稱(chēng)隱藏帶入了更高的瘋狂程度。 在這里,我為FLAG字段添加或刪除了final修飾符,該修飾符僅在不可達(dá)的if分支中訪問(wèn)。 這實(shí)際上改變了程序的語(yǔ)義! #ProgrammingIsFun 。 pic.twitter.com/UToRY3mpW9
-Tagir Valeev(@tagir_valeev) 2019年12月27日問(wèn)題在于,有一個(gè)計(jì)劃中的并且在EA版本中已經(jīng)可用的Java新功能引入了模式變量,而所提議的新標(biāo)準(zhǔn)的當(dāng)前版本為某些真正令人毛骨悚然的編碼問(wèn)題留出了空間。
在推文之后,詳細(xì)討論了足夠的細(xì)節(jié)以了解實(shí)際問(wèn)題。 但是,在本文中,我將總結(jié)所有這些內(nèi)容,以使您無(wú)需深入了解推文和標(biāo)準(zhǔn)。
什么是模式變量
在上面的推文中深入探討問(wèn)題概述之前,讓我們先討論一下模式變量是什么。 (也許有點(diǎn)草率,比精確和完整更多的解釋,但這是來(lái)的。)
進(jìn)行多次編程后,我們需要檢查某些對(duì)象的類(lèi)型。 運(yùn)算符instanceof為我們做到了。 典型的示例代碼可以是這樣的:
// HOW THIS IS TODAY, JAVA < 14 Object z = "alma" ; if (!(z instanceof String)){ throw new IllegalArgumentException(); } System.out.println(((String)z).length());在現(xiàn)實(shí)生活中,變量z可能來(lái)自其他地方,在這種情況下,它是不那么明顯,這是一個(gè)字符串。 當(dāng)我們想使用println打印出字符串的長(zhǎng)度時(shí),我們已經(jīng)知道z引用的對(duì)象是一個(gè)字符串。 另一方面,編譯器則沒(méi)有,我們必須將變量強(qiáng)制轉(zhuǎn)換為String ,然后才能使用length()方法。 其他語(yǔ)言做得更好。 理想情況下,我可以寫(xiě):
// HOW IT WOULD BE THE SIMPLEST Object z = "alma" ; if (!(z instanceof String)){ throw new IllegalArgumentException(); } System.out.println(z.length());這不是Java方式,也不是JDK14簡(jiǎn)化此編程模式的方式。 相反,建議的功能為instanceof運(yùn)算符引入了一種新語(yǔ)法,該語(yǔ)法引入了一個(gè)新變量: 模式變量 。
長(zhǎng)話(huà)短說(shuō),上面的示例如下所示:
// HOW IT IS IN JDK14-EA / OpenJDK (build 14-ea+28-1366) Object z = "alma" ; if (!(z instanceof String s)){ throw new IllegalArgumentException(); } System.out.println(s.length());它引入了一個(gè)新變量s ,僅當(dāng)引用的對(duì)象是String時(shí)才在范圍內(nèi)。 沒(méi)有異常拋出部分的簡(jiǎn)單代碼版本是
Object z = "alma" ; if (z instanceof String s){ // we have here 's' and it is a String System.out.println(s.length()); } // we do not have 's' here當(dāng)條件為真時(shí),對(duì)象是字符串,因此我們有“ s”。 如果條件為假,那么我們將跳過(guò)then_statement,并且由于沒(méi)有字符串,因此這里沒(méi)有's'。 代碼中只有在對(duì)象為字符串時(shí)才運(yùn)行“ s”。 這樣,模式變量的變量范圍不僅由變量的句法范圍決定,而且受可能的控制流程確定和限制。 僅考慮可以確定分析的控制流。
在Java編譯器中,這種控制流分析并非無(wú)與倫比。 例如,如果存在編譯器可以檢測(cè)到的無(wú)法訪問(wèn)的代碼,則Java程序?qū)⒉粫?huì)編譯。
到目前為止,這似乎很簡(jiǎn)單,我們都很高興獲得Java 14的新功能。
JSL14標(biāo)準(zhǔn)
精確范圍計(jì)算在JLS14(Java語(yǔ)言規(guī)范14)標(biāo)準(zhǔn)中定義。 在撰寫(xiě)本文時(shí),該規(guī)范僅作為預(yù)覽提供。
http://cr.openjdk.java.net/~gbierman/jep305/jep305-20191021/specs/patterns-instanceof-jls.html#jls-6.3.2.2
由于Java程序的執(zhí)行流程可以由許多不同的語(yǔ)言構(gòu)造控制,因此為每種結(jié)構(gòu)定義了模式變量的范圍。 對(duì)于不同的邏輯運(yùn)算符,有單獨(dú)的部分來(lái)評(píng)估短路,“ if”語(yǔ)句,“ while”語(yǔ)句等。 我不想廣泛討論不同的情況。 在這里,我將僅關(guān)注“ if”語(yǔ)句的情況,而沒(méi)有“ else”部分。 上面引用的標(biāo)準(zhǔn)說(shuō):
以下規(guī)則適用于“ if(e)S”(14.9.1)語(yǔ)句:
*當(dāng)e為true時(shí),由e引入的模式變量肯定與`S`相匹配。
如果`e`引入的任何模式變量true都已經(jīng)在`S`的作用域中,則是編譯時(shí)錯(cuò)誤。
*當(dāng)且僅當(dāng)`false`和`S'無(wú)法正常完成時(shí),`if(e)S`引入`V`。
如果`if`語(yǔ)句引入的任何模式變量已經(jīng)在范圍內(nèi),則是編譯時(shí)錯(cuò)誤。
有趣的部分是“無(wú)法正常完成”。 上面的示例就是一個(gè)很好的例子:我們創(chuàng)建了一個(gè)所謂的guard if語(yǔ)句。 當(dāng)變量z不是String我們將拋出異常,返回或執(zhí)行其他操作,這將始終阻止在變量不是String的if語(yǔ)句之后執(zhí)行代碼。
對(duì)于throw或return語(yǔ)句,通常很容易直接看出代碼“無(wú)法正常完成”。 在無(wú)限循環(huán)的情況下,這并不總是那么明顯。
問(wèn)題
讓我們看一下以下代碼片段:
private static boolean FLAG = true ; static String variable = "Hello from field" ; public static void main() { Object z = "Hello from pattern matching" ; if (!(z instanceof String variable)){ while (FLAG) { System.out.println( "We are in an endless loop" ); } } System.out.println(variable); }在這種情況下,我們有一個(gè)循環(huán),它是無(wú)限的或不是無(wú)限的。 這取決于代碼的另一部分,它可能會(huì)將類(lèi)字段FLAG的值從true更改為false 。 這部分代碼“可以正常完成”。
如果我們修改上面的代碼,只需稍微使字段FLAG為final ,如
private static final boolean FLAG = true ; static String variable = "Hello from field" ; public static void main() { Object z = "Hello from pattern matching" ; if (!(z instanceof String variable)){ while (FLAG) { System.out.println( "We are in an endless loop" ); } } System.out.println(variable); }那么編譯器將看到循環(huán)是無(wú)限的并且無(wú)法正常完成。 在第一種情況下,該程序Hello from field中打印出Hello from field Hello from pattern matching打印Hello from pattern matching 。 第二種情況下的模式variable隱藏了字段variable因?yàn)槟J阶兞康姆秶鷶U(kuò)展到了if語(yǔ)句之后的命令,因?yàn)槟敲床糠植荒苷M瓿伞?
確實(shí),此預(yù)覽功能確實(shí)存在問(wèn)題。 在這種情況下,代碼的可讀性非常可疑。 模式變量的范圍以及是否隱藏字段取決于該字段的final修飾符,該修飾符不存在。 當(dāng)我們查看某些代碼時(shí),實(shí)際的執(zhí)行和代碼結(jié)果應(yīng)該很簡(jiǎn)單,并且不應(yīng)該真正依賴(lài)于距離很遠(yuǎn)的某些代碼,并且可能會(huì)跳過(guò)我們?cè)诒镜亻喿x代碼的注意力。
這不是Java中唯一出現(xiàn)此異常的情況。 例如,您的代碼庫(kù)中可以有一個(gè)名為String的類(lèi)。 當(dāng)它們引用String類(lèi)型時(shí),位于同一包中的類(lèi)的代碼將使用該類(lèi)。 如果我們從用戶(hù)代碼中刪除String類(lèi),則String類(lèi)型的含義變?yōu)閖ava.lang.String 。 代碼的實(shí)際含義取決于“遠(yuǎn)”的其他代碼。
然而,第二個(gè)例子是一個(gè)黑客,沒(méi)有大意的Java程序員不可能將String類(lèi)命名為(嚴(yán)重https://github.com/verhas/jScriptBasic/blob/master/src/main/ java / com / scriptbasic / classification / String.java ?)或JDK中java.lang包中也存在的其他名稱(chēng)。 也許這是純粹的運(yùn)氣,也許在決策過(guò)程中考慮了這一點(diǎn),以避免從java.lang包中強(qiáng)制導(dǎo)入類(lèi)。 這是歷史。
另一方面,變量名隱藏和上述情況似乎并不那么怪異,某些Java代碼中肯定不會(huì)偶然發(fā)生某些事情。
幸運(yùn)的是,這只是預(yù)覽功能。 它將按原樣出現(xiàn)在JDK14中,但作為預(yù)覽功能,僅當(dāng)javac編譯器和Java執(zhí)行使用--enable-preview標(biāo)志并且預(yù)覽功能將來(lái)可能以不兼容的方式更改時(shí),它才可用。
解
我不知道它將如何改變。 我什至不能說(shuō)它會(huì)改變。 僅憑我個(gè)人的看法,如果仍然那樣下去將是非常可悲的。 有了此功能,只要我們計(jì)算經(jīng)驗(yàn)豐富的Java程序員可以編寫(xiě)的程序的精妙程度和可讀性,Java就會(huì)是更好的語(yǔ)言。 但是,如果我們看看沒(méi)有經(jīng)驗(yàn)的,新鮮的初級(jí)人員如何弄糟代碼,情況將會(huì)更糟。 以我的拙見(jiàn),第二點(diǎn)更為重要,而Java在這方面有很強(qiáng)的優(yōu)勢(shì)。 Java不是一種黑客語(yǔ)言,您應(yīng)該非常拼命編寫(xiě)一個(gè)非常不可讀的代碼。 我不希望它改變。
說(shuō)完之后,我們可以看看技術(shù)上的可能性。 一種是放棄該功能,這實(shí)際上不是一個(gè)好的解決方案。 這實(shí)際上不是解決方案。
另一種可能性是將模式變量的范圍限制為then語(yǔ)句或else語(yǔ)句。
就個(gè)人而言,我希望綁定變量范圍僅適用于顯式聲明的else塊,而不適用于這種情況下的隱式塊。
-Michael Rasmussen(@jmichaelras) 2019年12月27日這樣,我們就不會(huì)依賴(lài)代碼的“無(wú)法正常完成”功能。 else保證只有在if語(yǔ)句的條件為false時(shí)才執(zhí)行else分支。 這將使解決方案不太優(yōu)雅。
同樣,另一種可能性是禁止模式變量遮蓋任何字段變量。 它可以解決上面概述的問(wèn)題,但是會(huì)引入一個(gè)不同的問(wèn)題。 受此限制,當(dāng)我們引入一個(gè)名為V的新字段變量時(shí),可能會(huì)發(fā)生帶有方法和模式變量V的現(xiàn)有類(lèi)停止編譯的情況。 至少這個(gè)問(wèn)題是編譯時(shí)的問(wèn)題,而不是運(yùn)行時(shí)有錯(cuò)誤的某些代碼。
我寧愿有100個(gè)編譯時(shí)錯(cuò)誤,也不愿有一個(gè)運(yùn)行時(shí)錯(cuò)誤。
還有一種可能是放棄模式變量,而僅使用原始變量和擴(kuò)展的類(lèi)型信息,而當(dāng)前的預(yù)覽解決方案使用模式變量。 Kotlin粉絲會(huì)喜歡這種解決方案。 由于局部變量已經(jīng)遮蔽(或不遮蓋)字段變量,因此這也可以很好地消除陰影問(wèn)題。 該解決方案的缺點(diǎn)是,重新作用域限定的變量類(lèi)型在代碼的不同位置將具有不同的類(lèi)型。 讓我們看下面的代碼:
package javax0.jdk14.instanceof0; public class Sample2 { public static class A { public static void m(){ System.out.println( "A" ); } } public static class B extends A { public static void m(){ System.out.println( "B" ); } } public static void main(String[] args) { A a = new B(); if ( a B b){ ( a instanceof B b){ bm(); } am(); } }此代碼將先打印出B然后打印出A因?yàn)楦鶕?jù)變量b的聲明類(lèi)型,對(duì)bm()的調(diào)用與Bm()相同,并且根據(jù)聲明的類(lèi)型,對(duì)am()與Am()的相同方法的變量a 。 省略模式變量并使用原始變量可能會(huì)造成混淆:
// NOT ACTUAL CODE public static void main(String[] args) { A a = new B(); if ( a B){ ( a instanceof B){ am(); } am(); }am()會(huì)在不同的行上調(diào)用不同的方法嗎?
如您所見(jiàn),除此問(wèn)題外,沒(méi)有已知的最佳或最佳解決方案。 在JDK中稱(chēng)您的代表為“國(guó)會(huì)”,并告訴他們那樣不好。 (Psst:他們已經(jīng)從原始推文中知道了。)
帶走
這是一篇特別的文章,因?yàn)檫@與某些完善的Java功能或某些良好的編程工具或樣式,模式,方法無(wú)關(guān)。 我們討論了預(yù)覽功能。 預(yù)覽功能也許證明了為什么我們需要Java中的預(yù)覽功能。
對(duì)于需要長(zhǎng)期支持的長(zhǎng)期商業(yè)項(xiàng)目,請(qǐng)使用最新的LTS版本。
將最新發(fā)布的Java版本用于您的實(shí)驗(yàn)和開(kāi)源項(xiàng)目,并在用戶(hù)需要時(shí)準(zhǔn)備支持較舊的Java版本。
不要在項(xiàng)目中使用預(yù)覽功能,也不要準(zhǔn)備從代碼中獲得新版本,以防它們?cè)谧優(yōu)榉穷A(yù)覽但正常功能時(shí)在下一個(gè)Java版本中發(fā)生更改。
嘗試使用預(yù)覽功能以將其包含在內(nèi),并在它們成為真實(shí)功能時(shí)具有某種肌肉記憶。 并且還可以向Java社區(qū)提供反饋,以防您覺(jué)得它們不是很完美。
翻譯自: https://www.javacodegeeks.com/2020/01/jdk14-instance-of-ea-issue.html
jdk內(nèi)置線程實(shí)例
總結(jié)
以上是生活随笔為你收集整理的jdk内置线程实例_EA问题的JDK14实例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 百度推广怎么否词(百度推广否词技巧)
- 下一篇: ps怎么绘制草稿(ps怎么绘制草稿图片)