java scala_经过几天的Scala回归Java的10个最烦人的事情
java scala
因此,我正在嘗試使用Scala,因?yàn)槲蚁刖帉?xiě)一個(gè)解析器,而Scala Parsers API似乎非常合適。 畢竟,我可以在Scala中實(shí)現(xiàn)解析器并將其包裝在Java接口后面,因此除了附加的運(yùn)行時(shí)依賴(lài)關(guān)系之外,應(yīng)該不存在任何互操作性問(wèn)題。
在幾天后真正真正地習(xí)慣了Scala語(yǔ)法的強(qiáng)大功能之后,以下是我回到編寫(xiě)Java時(shí)最想錯(cuò)過(guò)的十件事:
1.多行字符串
這是我個(gè)人的最?lèi)?ài),也是一種非常棒的功能,應(yīng)該使用任何語(yǔ)言。 甚至PHP都有:多行字符串。 像編寫(xiě)一樣簡(jiǎn)單:
println ("""Dear reader,If we had this feature in Java, wouldn't that be great?Yours Sincerely, Lukas""")這在哪里有用? 使用SQL,當(dāng)然! 這是使用jOOQ和Scala運(yùn)行純SQL語(yǔ)句的方法:
println(DSL.using(configuration).fetch("""SELECT a.first_name, a.last_name, b.titleFROM author aJOIN book b ON a.id = b.author_idORDER BY a.id, b.id""") )這不僅對(duì)靜態(tài)字符串有用。 使用字符串插值,您可以輕松地將變量注入到這樣的字符串中:
val predicate =if (someCondition)"AND a.id = 1"else""println(DSL.using(configuration)// Observe this little "s".fetch(s"""SELECT a.first_name, a.last_name, b.titleFROM author aJOIN book b ON a.id = b.author_id-- This predicate is the referencing the-- above Scala local variable. Neat!WHERE 1 = 1 $predicateORDER BY a.id, b.id""") )太棒了,不是嗎? 對(duì)于SQL,Scala具有很大的潛力。
2.分號(hào)
我真心沒(méi)有錯(cuò)過(guò)他們一點(diǎn)。 我構(gòu)造代碼的方式(可能也是大多數(shù)人構(gòu)造代碼的方式),Scala似乎根本不需要分號(hào)。 在JavaScript中,我不會(huì)說(shuō)同樣的話(huà)。 JavaScript的解釋性和非類(lèi)型安全性質(zhì)似乎表明,放棄可選的語(yǔ)法元素可以保證您一臂之力。 但是Scala不支持。
val a = thisIs.soMuchBetter() val b = no.semiColons() val c = at.theEndOfALine()這可能是由于Scala的類(lèi)型安全性導(dǎo)致的,這將使編譯器在那些罕見(jiàn)的模棱兩可的情況下抱怨,但這只是有根據(jù)的猜測(cè)。
3.括號(hào)
這是一個(gè)雷區(qū),在許多情況下,省略括號(hào)似乎很危險(xiǎn)。 實(shí)際上,在調(diào)用方法時(shí),您也可以忽略這些點(diǎn):
myObject method myArgument由于可能會(huì)產(chǎn)生大量歧義,尤其是在鏈接更多方法調(diào)用時(shí),我認(rèn)為最好避免使用此技術(shù)。 但是在某些情況下,“忘記”父母是很方便的。 例如
val s = myObject.toString4.類(lèi)型推斷
這在Java中確實(shí)很煩人,與此同時(shí),似乎許多其他語(yǔ)言也都做到了這一點(diǎn)。 Java僅具有有限的類(lèi)型推斷功能,并且事情并不盡如人意 。
在Scala中,我可以簡(jiǎn)單地寫(xiě):
val s = myObject.toString……而不在乎s是String類(lèi)型的事實(shí)。 有時(shí)但僅在某些時(shí)候,我想明確指定引用的類(lèi)型。 在那種情況下,我仍然可以做到:
val s : String = myObject.toString5.案例分類(lèi)
我想我想寫(xiě)另一個(gè)POJO,它具有40個(gè)屬性,構(gòu)造函數(shù),getter,setter,equals,hashCode和toString
-沒(méi)人說(shuō)。 曾經(jīng)
Scala具有案例類(lèi)。 用單線編寫(xiě)的簡(jiǎn)單不可變的pojos。 以Person案例類(lèi)為例:
case class Person(firstName: String, lastName: String)我同意,必須確實(shí)寫(xiě)下一次屬性。 但是其他一切應(yīng)該是自動(dòng)的。
以及如何創(chuàng)建此類(lèi)案例類(lèi)的實(shí)例? 輕松,你甚至都不需要new運(yùn)營(yíng)商(事實(shí)上,它完全逃脫了我的想象,為什么new真正需要擺在首位):
Person("George", "Orwell")而已。 您還想寫(xiě)些什么以符合企業(yè)標(biāo)準(zhǔn)?
邊注
好的,現(xiàn)在有些人會(huì)爭(zhēng)辯說(shuō)要使用lombok項(xiàng)目 。 基于注釋的代碼生成是胡說(shuō)八道,應(yīng)最好避免。 實(shí)際上,Java生態(tài)系統(tǒng)中的許多注釋簡(jiǎn)單地證明了Java語(yǔ)言的(而且將永遠(yuǎn)是)其進(jìn)化能力非常有限這一事實(shí)。 以@Override為例。 這應(yīng)該是關(guān)鍵字,而不是注釋。 您可能會(huì)認(rèn)為這是表面上的區(qū)別,但是我說(shuō)Scala已經(jīng)證明注釋幾乎總是錯(cuò)誤的工具。 還是您最近看過(guò)帶有大量注釋的 Scala代碼?
6.到處都有方法(功能!)
我認(rèn)為,這實(shí)際上是任何語(yǔ)言中最有用的功能之一。 為什么我們總是必須將方法鏈接到特定的類(lèi)? 為什么我們不能簡(jiǎn)單地?fù)碛腥魏巫饔糜蚣?jí)別的方法? 因?yàn)槲覀兛梢?#xff0c;所以使用Scala:
// "Top-level", i.e. associated with the package def m1(i : Int) = i + 1object Test {// "Static" method in the Test instancedef m2(i : Int) = i + 2def main(args: Array[String]): Unit = {// Local method in the main methoddef m3(i : Int) = i + 3println(m1(1))println(m2(1))println(m3(1))} }對(duì)? 為什么我不能在另一個(gè)方法中定義本地方法? 我可以使用Java中的類(lèi)來(lái)做到這一點(diǎn):
public void method() {class LocalClass {}System.out.println(new LocalClass()); }局部類(lèi)是方法局部的內(nèi)部類(lèi)。 這幾乎沒(méi)有用,但是真正有用的是局部方法。
JavaScript或REPL也支持這些功能。 這對(duì)于在應(yīng)用程序范圍之外測(cè)試小型算法或概念非常有用。
在Java中,我們通常傾向于這樣做:
public class SomeRandomClass {// [...]public static void main(String[] args) {System.out.println(SomeOtherClass.testMethod());}// [...] }在Scala中,我將在REPL中編寫(xiě)以下代碼:
println(SomeOtherClass.testMethod)還請(qǐng)注意始終可用的println方法。 純金方面高效的調(diào)試。
8.數(shù)組不是(很多)特例
在Java中,除了基本類(lèi)型之外,還有一些我們稱(chēng)為數(shù)組的怪異事物。 數(shù)組起源于一個(gè)完全獨(dú)立的宇宙,在這里我們必須記住起源于柯克上尉(大約)時(shí)代的古怪規(guī)則:
是的,規(guī)則如下:
// Compiles but fails at runtime Object[] arrrrr = new String[1]; arrrrr[0] = new Object();// This works Object[] arrrr2 = new Integer[1]; arrrr2[0] = 1; // Autoboxing// This doesn't work Object[] arrrr3 = new int[];// This works Object[] arr4[] = new Object[1][];// So does this (initialisation): Object[][] arr5 = { { } };// Or this (puzzle: Why does it work?): Object[][] arr6 = { { new int[1] } };// But this doesn't work (assignment) arr5 = { { } };是的,清單可以繼續(xù)。 從語(yǔ)法上講,使用Scala,數(shù)組不再是一種特殊情況:
val a = new Array[String](3); a(0) = "A" a(1) = "B" a(2) = "C" a.map(v => v + ":")// output Array(A:, B:, C:)如您所見(jiàn),數(shù)組的行為與其他集合非常相似,包括可以在其上使用的所有有用方法。
9.符號(hào)方法名稱(chēng)
現(xiàn)在,這個(gè)話(huà)題更具爭(zhēng)議性,因?yàn)樗刮覀兿肫鹆诉\(yùn)算符重載的危險(xiǎn) 。 但是,每隔一段時(shí)間,我們希望有類(lèi)似的東西。 可以讓我們寫(xiě)的東西:
val x = BigDecimal(3); val y = BigDecimal(4); val z = x * y非常直觀地,z的值應(yīng)為BigDecimal(12) 。 那不能太難,對(duì)嗎? 我不在乎*的實(shí)現(xiàn)是否真的是一個(gè)稱(chēng)為multiply()的方法。 寫(xiě)下該方法時(shí),我想使用看起來(lái)很普通的運(yùn)算符進(jìn)行乘法。
順便說(shuō)一句,我也想用SQL做到這一點(diǎn)。 這是一個(gè)例子:
select ( AUTHOR.FIRST_NAME || " " || AUTHOR.LAST_NAME,AUTHOR.AGE - 10 ) from AUTHOR where AUTHOR.ID > 10 fetch那沒(méi)有道理嗎? 我們知道|| 表示concat(在某些數(shù)據(jù)庫(kù)中)。 我們知道- (減號(hào))和> (大于)的含義。 為什么不就寫(xiě)呢?
上面是在Scala中的jOOQ的編譯示例。
注意:警告
允許操作符重載或符號(hào)方法名之類(lèi)的東西總是存在弊端。 它可能(并將被)濫用。 圖書(shū)館與Scala語(yǔ)言本身一樣多 。
10.元組
作為一個(gè)SQL人員,這再次是我在其他語(yǔ)言中最想念的功能之一。 在SQL中,所有內(nèi)容都是TABLE或ROW。 實(shí)際上,很少有人知道這一點(diǎn) ,并且很少有數(shù)據(jù)庫(kù)實(shí)際上支持這種思維方式。
Scala沒(méi)有ROW類(lèi)型(實(shí)際上是記錄),但是至少有匿名元組類(lèi)型。 將行視為具有命名屬性的元組,而案例類(lèi)將命名為行:
- 元組:具有類(lèi)型化和索引元素的匿名類(lèi)型
- 行:具有類(lèi)型化,命名和索引元素的匿名類(lèi)型
- 案例類(lèi):具有類(lèi)型化元素和命名元素的命名類(lèi)型
在Scala中,我可以這樣寫(xiě):
// A tuple with two values val t1 = (1, "A")// A nested tuple val t2 = (1, "A", (2, "B"))在Java中,可以完成類(lèi)似的操作,但是您必須自己編寫(xiě)該庫(kù),并且不提供語(yǔ)言支持:
class Tuple2<T1, T2> {// Lots of bloat, see missing case classes }class Tuple3<T1, T2, T3> {// Bloat bloat bloat }然后:
// Yikes, no type inference... Tuple2<Integer, String> t1 = new Tuple2<>(1, "A");// OK, this will certainly not look nice Tuple3<Integer, String, Tuple2<Integer, String>> t2 =new Tuple3<>(1, "A", new Tuple2<>(2, "B"));jOOQ充分利用了上述技術(shù),將SQL的行值表達(dá)式帶到Java,并且令人驚訝的是,在大多數(shù)情況下,您可以在不丟失類(lèi)型推斷的情況下做到這一點(diǎn),因?yàn)閖OOQ是一種流利的API,在其中您從未真正將值分配給局部變量。例:
DSL.using(configuration).select(T1.SOME_VALUE).from(T1).where(// This ROW constructor is completely type saferow(T1.COL1, T1.COL2).in(select(T2.A, T2.B).from(T2))).fetch();結(jié)論
當(dāng)然,這是一篇有關(guān)scala的文章,與Java稍有抵觸。 不要誤會(huì)我的意思。 我絕不希望完全遷移到Scala。 我認(rèn)為Scala語(yǔ)言遠(yuǎn)遠(yuǎn)超出了任何有用軟件中的合理范圍。 有很多看起來(lái)不錯(cuò)的小功能和頭,但不可避免地會(huì)炸掉您的臉,例如:
- implicit轉(zhuǎn)換。 這不僅很難管理,而且還嚴(yán)重降低了編譯速度。 此外,使用implicit合理地實(shí)現(xiàn)語(yǔ)義版本控制可能完全是不可能的,因?yàn)椴豢赡芡ㄟ^(guò)偶然的向后不兼容預(yù)見(jiàn)所有可能的客戶(hù)端代碼損壞。
- 乍一看,本地導(dǎo)入看起來(lái)很棒,但是當(dāng)人們開(kāi)始部分導(dǎo)入或重命名本地范圍的類(lèi)型時(shí),它們的功能很快使代碼難以理解。
- 符號(hào)方法名稱(chēng)最常被濫用。 以解析器API為例,它具有諸如^^ , ^^^ , ^?類(lèi)的方法名稱(chēng)^? 或~!
盡管如此,我認(rèn)為本文中列出的Scala與Java相比的優(yōu)點(diǎn)也可以全部用Java實(shí)現(xiàn):
- 幾乎沒(méi)有破壞向后兼容的風(fēng)險(xiǎn)
- 用(可能)不太大的努力,在JLS方面
- 對(duì)開(kāi)發(fā)人員的生產(chǎn)力產(chǎn)生巨大影響
- 對(duì)Java的競(jìng)爭(zhēng)力產(chǎn)生巨大影響
無(wú)論如何,Java 9將是另一個(gè)很有前途的版本,其熱門(mén)話(huà)題包括值類(lèi)型, 聲明站點(diǎn)差異 , 特殊化(非常有趣!)或ClassDynamic。
有了這些巨大的變化,我們希望上面的一些小改進(jìn)還有一定的余地,這將為日常工作增加更多的直接價(jià)值。
翻譯自: https://www.javacodegeeks.com/2014/08/the-10-most-annoying-things-coming-back-to-java-after-some-days-of-scala.html
java scala
總結(jié)
以上是生活随笔為你收集整理的java scala_经过几天的Scala回归Java的10个最烦人的事情的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 美国作家协会和17位知名作家对OpenA
- 下一篇: [MEGA DEAL] Ultimate