溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Ruby和Java的基礎(chǔ)語法有哪些區(qū)別

發(fā)布時(shí)間:2021-10-28 18:01:15 來源:億速云 閱讀:135 作者:iii 欄目:編程語言

本篇內(nèi)容主要講解“Ruby和Java的基礎(chǔ)語法有哪些區(qū)別”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Ruby和Java的基礎(chǔ)語法有哪些區(qū)別”吧!

前言

這篇文章示例代碼比較多, Java 程序員可以看到一些 Ruby 相關(guān)語法和使用,Ruby 程序員可以看看 Java  的基本語法和使用方法,本文比較長,將近萬字左右,預(yù)計(jì)需要十幾分鐘,如果有耐心讀完文章的話,你將獲得和了解:

  • Ruby 語言的基本語法和使用方式

  • Java 語言的基本語法和使用方式

  • 從老司機(jī)的角度分析和講解 Ruby 和 Java 語言語法的特點(diǎn)和區(qū)別

  • 它們的各自適合并且擅長的應(yīng)用場景

網(wǎng)上單獨(dú)介紹 Ruby ,Java 的文章應(yīng)該很多,但是對比兩種編程語言的基本語法使用的文章應(yīng)該不多見,寫這篇文章的目的主要是對自己近期幾個(gè)月學(xué)習(xí)  Ruby 做總結(jié)和回顧,我之前最熟悉的編程語言是  Java,我個(gè)人認(rèn)為合格的程序員應(yīng)該掌握多門語言,多學(xué)一門語言沒有壞處,在解決問題的時(shí)候可以多些思路,在經(jīng)歷最近幾個(gè)月的橫向?qū)Ρ群褪褂酶惺?,先拋我個(gè)人結(jié)論,在個(gè)人項(xiàng)目或者小型團(tuán)隊(duì),技術(shù)能力較強(qiáng)的團(tuán)隊(duì)我推薦使用  Ruby, 在團(tuán)隊(duì)需要快速擴(kuò)展和大型項(xiàng)目規(guī)劃的情況下我推薦 Java,因?yàn)榈靡嬗?Java 語法的嚴(yán)謹(jǐn)性和安全性,很大程度上可以保證團(tuán)隊(duì)水平的下限,Java  較強(qiáng)的工程化規(guī)約和代碼類型檢查,可以保證新手不至于寫出破壞性很強(qiáng)的代碼,如果把兩種語言作為一個(gè)簡單的比如,最直觀的感受就是可以把 Ruby 和 Java  比做金庸小說里的兩把武器:

  • Ruby 設(shè)計(jì)精妙,體積小巧靈活迅捷如風(fēng),就像紫薇軟劍那般鋒芒畢露,使用者可以隨心所欲,不必被太多語法和規(guī)則限制

  • Java 老成持重,雖然語法和年代較為古板啰嗦,但是卻長年占據(jù) TIOBE 編程語言排行榜第一名,真可謂是重劍無鋒,大巧不工

在很多人的印象中 Ruby 主要是在初創(chuàng)公司會比較流行,例如早期的 Airbnb,GitLab 都是使用 Ruby 作為開發(fā)語言,Ruby  是一門很靈活也很優(yōu)雅的動(dòng)態(tài)語言,解釋運(yùn)行,有興趣了解的同學(xué)可以點(diǎn)開 鏈接 查看維基百科的詞條,Ruby 語法精煉,做相同的事情代碼行數(shù)通常會比 Java  要短的多,使用 Ruby  寫程序的的過程是非常舒服的,因?yàn)椴槐鼐心嘤谀切┛贪鍙?qiáng)制的語法規(guī)范,可以讓開發(fā)者隨心所欲的表達(dá)自己的想法,不必強(qiáng)制分號結(jié)尾,不強(qiáng)制中括號,不強(qiáng)制方法參數(shù)長度等語法規(guī)范所限制,這種靈活的表達(dá)方式設(shè)計(jì)體現(xiàn)在語言使用的方方面面,并且如果你是用  Mac OS 則系統(tǒng)天生支持 Ruby 開發(fā)環(huán)境,在 Mac 終端 輸入以下命令就可以看到 Ruby 版本號:

ruby -v # ruby 2.6.5p114 (2019-10-01 revision 67812) [x86_64-darwin19]

然后只要在終端里面鍵入 irb 就可以進(jìn)入調(diào)式模式,不像要運(yùn)行 Java 程序首先安裝 JDK 然后再配置環(huán)境變量 JAVA_HOME 和  CLASS_PATH 經(jīng)過繁瑣的配置才勉強(qiáng)可以執(zhí)行 java 命令執(zhí)行 class 程序,在 irb  模式下,對于簡單的邏輯程序可以先在調(diào)式模式將代碼寫出來驗(yàn)證想法的可行后再加入到代碼庫中去,使用起來非常的方便,示例如下:

>irb >2.6.5 :001 > p "hello world" # => "hello world"

下面簡單的寫一個(gè) Hello World 程序進(jìn)行對比,兩種編程語言在打印 HelloWorld 程序上的寫法,示例代碼如下:

// java print public class Main {     public static void main(String[] args) {         System.out.println("hello world!");   // 注意分號結(jié)尾     } }
# ruby print p "hello world!"

通過一個(gè)簡單的 Hello World 程序你就可以發(fā)現(xiàn)兩者的明顯區(qū)別:

  • Ruby 的執(zhí)行是從上到下順序執(zhí)行,main 方法則是 Java 程序的唯一入口

  • Ruby 不必用 ; 號結(jié)束符,不必使用 {} 聲明代碼塊,函數(shù)式方法傳參甚至不用使用 () (挺有意思)

經(jīng)過以上講解,大家可能會對開始產(chǎn)生一些興趣,不過這僅僅只是開始,后面主要簡單介紹一下 Ruby  常用的對象,條件,循環(huán),方法,運(yùn)算符,數(shù)值,數(shù)組,字符串,散列等使用方法,本文不算嚴(yán)格意義的文章,因?yàn)槭纠a量占了文章的 50%  ,而且本文的特點(diǎn)就是會在語法將 Ruby 和 Java 進(jìn)行對比,不過還是會講解 Ruby  基本語法為主,本文偏入門級水平,介紹的內(nèi)容都是平時(shí)使用比較的多的場景,暫時(shí)不會涉及到例如 Ruby 的 metaprogramming 和 Java 的  反射等較為深入的知識點(diǎn),可能后續(xù)會有單獨(dú)的文章進(jìn)行分析,看完文章應(yīng)該可以用寫一些簡單的程序用于跑一些簡單的腳本應(yīng)該是夠用了,實(shí)際上腳本處理程序也正是 Ruby  很擅長的領(lǐng)域

補(bǔ)充:文章對比 Java,Ruby  兩種語言在語法上的區(qū)別,并不是爭論哪種編程語言的好壞優(yōu)劣,我個(gè)人觀點(diǎn)是:編程語言本身沒有好壞之分,只有在不同場景下做出合適的選擇,而且熟悉 Java  的同學(xué)也應(yīng)該明白 Java 的優(yōu)勢從來都不在語言和語法層面,而是在生態(tài),并發(fā)編程,虛擬機(jī)和穩(wěn)定這些特性才是 Java 的核心競爭力,在生態(tài)上 Spring  Framework為代表的高質(zhì)量輪子覆蓋 Java 應(yīng)用的方方面面,可以說在輪子的多樣性上面,暫時(shí)沒有哪種語言可以跟 Java  抗衡,所以如果簡單的用語法概括語言的好壞就非常以偏概全的看法,話不多說,我們進(jìn)入正題,先列一下文章大綱,入門篇只會簡單說一些基本語法:

  • 多重賦值

  • 條件判斷

  • 循環(huán)

  • 方法

  • 類和模塊

  • 運(yùn)算符

  • 異常處理

多重賦值

每個(gè)變量單獨(dú)賦值的場景大多相同,就不做介紹,在程序開發(fā)中,我們經(jīng)常會把多個(gè)變量同時(shí)賦值,這樣效率會高很多,每種語言對多重賦值的支持都不同,我們先通過一段代碼對比  Java,Ruby 語言對于多重賦值的不同寫法:

// Java 多重賦值 int a, b, c = 1, 2, 3;      // compile error int a, long b, short c = 1, 2L, 3;  // complier error int a = 1, b = 2, c =3;     // compile pass
# Ruby 中多重賦值非常輕松 a, b, c = 1, 2, 3 # => [1, 2, 3]  # 兼容不同類型 a, s, c = 1, "2", 3 # => [1, "2", 3]      # 兼容不同長度 a, b, c = 1, 2 # => [1, 2, nil] a, b, c, = 1, 2, 3, 4 # => [1, 2, 3]  自動(dòng)裁掉超出的長度

結(jié)合以上案例感覺 Java 對多重賦值不是很友好,很多不合規(guī)范的語法在編譯期就會被攔截并且報(bào)錯(cuò),簡單對比后總結(jié):

  • Java 因?yàn)閺?qiáng)類型,所以對賦值的比較限制多,例如只能對同類型的變量進(jìn)行簡單的賦值

  • Ruby 中多重賦值比較輕松,不用考慮類型,長度等問題,過長和過短都不會在編譯時(shí)拋出問題

  • Ruby 在聲明類型的時(shí)候不需要像 Java 那樣聲明類型,這也是動(dòng)態(tài)語言的特性,我個(gè)人是比較喜歡的

條件判斷

Ruby 的條件判斷主要有以下三種:

  • if 語句

  • unless 語句

  • case 語句

先看實(shí)例和對比代碼:

a, b = 10, 20 p "a 比 b 大" if a > b p "a 比 b 小" if a < b # => a 比 b 小  # unless 條件就不多做介紹,用法剛好與 if 語句相反,類似java中的 != 運(yùn)算符,實(shí)例代碼: a, b = 10, 20 p "a 和 b 不相等" unless a == b # => a 和 b 不相等
int a = 10, b = 20; if (a > b) System.out.println("a 比 b 大"); // 在合作項(xiàng)目中還是推薦使用中括號 {} if (a < b) System.out.println("a 比 b 小"); //=> a 比 b 小  int a = 10, b = 20; if (a != b) System.out.println("a 和 b 不相等"); //=> a 比 b 小

還有 case 語句主要用于多條件進(jìn)行判斷,語句用法是 case~when~end 進(jìn)行組合條件判斷,功能跟 Java 中的 switch  相同,還有邏輯運(yùn)算符 ==, !=, ||, && 都是通用的基本知識,所以就不寫詳細(xì)說明和寫示例代碼了,不然會顯得很啰嗦

總結(jié):條件判斷語句用法非常簡單,兩種編程語言基本類似語言類似,不過還是有以下區(qū)別:

  • Ruby 在關(guān)鍵字選擇上多一些,例如 unless 實(shí)際上是替代了運(yùn)算符 !=,也增加了一些可讀性

  • if 語法基本相似,但 Java 強(qiáng)制表達(dá)式必須使用括號 () ,Ruby則不需要

  • Ruby 使用 if~then~end 語法標(biāo)記代碼塊,不同于 Java 使用中括號 {} 標(biāo)記代碼塊

  • Ruby 條件判斷 if/unless 放在代碼后面,程序看上去可以更加緊湊和簡潔

循環(huán)

Ruby 的循環(huán)結(jié)構(gòu)語句比較豐富,相比 Java 只有 for,while 兩種循環(huán)方式來說,Ruby  中的可用的循環(huán)方法有:time,while,each,for,until,loop,不過大多都異曲同工,就不一一介紹了,本章節(jié)主要圍繞平時(shí)常用的幾個(gè)需求來做一個(gè)簡單的講解,對比兩種語言的使用區(qū)別,具體如下:

  • 如何執(zhí)行一個(gè)固定次數(shù)的循環(huán) ?

  • 如何遍歷一個(gè)數(shù)組 ?

  • 如何遍歷一個(gè) Hash ?

執(zhí)行固定次數(shù)的循環(huán)是 time循環(huán) 方法的拿手好戲,用于和語句也很簡單,如果不需要下標(biāo)值,|i| 參數(shù)也是可以移除的,示例代碼如下

3.time do |i|  # i 也可以省略    p "第#{i}次打印" end # => 第0次打印 # => 第1次打印 # => 第2次打印

在 Java 中想要執(zhí)行固定長度的循環(huán),不能通過 forEach只能通過古老的 for..i 來實(shí)現(xiàn),具體代碼如下:

for (int i = 0; i < 3; i++) {     System.out.println("第" + i + "次打印"); } // 第0次打印 // 第1次打印 // 第2次打印

如何遍歷一個(gè)數(shù)組?

在 Ruby 中通常會推薦使用 **each ** 不僅語法簡單,而且可以輕松拿到元素值,示例代碼如下:

["abc","efg","hmn"].each do |e|   p "#{e}!"  end #=> abc! dfg! hmn!

Java 在 JDK 8 經(jīng)過 Stream 和 Lambda 語法增強(qiáng)后,遍歷數(shù)組也沒有想象中那么古板,示例代碼:

Arrays.asList("abc", "dfg","hmn").forEach(e ->    System.out.println(e + "!") ); // abc! dfg! hmn!

不過在平時(shí)遍歷數(shù)組的時(shí)候經(jīng)常會遇到一種需求,不僅想要拿到數(shù)組的元素,還需要拿到當(dāng)前循環(huán)的索引值,Ruby 中提供一個(gè)特別的 each 方式實(shí)現(xiàn),就是  each_with_index 方法,它會把 [元素, 索引] 傳入到 do 代碼塊的后,具體示例代碼:

["abc","def","ghi"].each_with_index do |e, i|   p "當(dāng)前元素 #{e} , 以及第 #{i} 次循環(huán)" end #=> "當(dāng)前元素 abc , 以及第 0 次循環(huán)" #=> ...

Java 想要實(shí)現(xiàn)相同循環(huán)效果就不能用基于迭代器的 ForEach 實(shí)現(xiàn)了,只能用 for..i 實(shí)現(xiàn),示例代碼如下:

List<String> list = Arrays.asList("abc", "deg", "ghi"); for (int i = 0; i < list.size(); i++) {     String e = list.get(i);     System.out.println("當(dāng)前元素" + e + ",以及第 " + i + "次循環(huán)"); } // 當(dāng)前元素abc,以及第 0次循環(huán) // ..

如何遍歷一個(gè) Hash ?

Hash 是 Ruby 的常用的對象,因此循環(huán)遍歷獲取 K,V 也是相當(dāng)方便的,示例代碼:

hash = {name: "apple", age: 15, phone: "15815801580"} hash.each do |k, v|  p "key: #{k}, value: #{v}" end #=> key: name, value: apple #=> ...

Java 中最常用的 K-V 結(jié)構(gòu)的 Hash 實(shí)現(xiàn)是基于 Map 接口的  HashMap,它是一種非線程安全的哈希表實(shí)現(xiàn),之所以常用是因?yàn)樗骖櫟男屎蜁r(shí)間的平衡,內(nèi)部是通過數(shù)組實(shí)現(xiàn),采用使用鏈表法處理哈希沖突,JDK 8 后又引入  紅黑樹 解決哈希沖突過多導(dǎo)致鏈表過長的問題,這塊就先不展開講了,不然可以講很久,示例代碼展示 Java 如何遍歷 Hash:

Map<String, String> hashMap = new HashMap<>(); hashMap.put("name", "apple"); hashMap.put("age", "15"); hashMap.put("phone", "15815801580");  for (Map.Entry<String, String> entry : hashMap.entrySet()) {   System.out.println("key :" + entry.getKey() + ", value : " + entry.getValue()); } // key :name, value : apple // ....

Java 遍歷 Hash 的方式還有很多種,我們這里只展示最常用的用法,通過 ForEach 遍歷 entrySet() 返回的集合即可。

最后再說一個(gè)有意思的循環(huán)方法,不過使用場景應(yīng)該很少,一個(gè)沒有終止的循環(huán) loop方法,因?yàn)闆]有終止條件,所以必須依賴 break 關(guān)鍵字跳出循環(huán),Java  也可以很輕松實(shí)現(xiàn)這種循環(huán)效果,只是語法上不同而已,我們可以看看以下實(shí)例對比:

// java 使用 while(true) 或者 for(;;) 實(shí)現(xiàn)無限循環(huán) while (true) System.out.println("i use java");
# ruby 無限循環(huán) loop do   p "i use ruby" end

如果程序進(jìn)入無限循環(huán)就只能通過 CTRL + C 來終止程序運(yùn)行了 總結(jié):循環(huán)上兩種語言區(qū)別不大,Ruby 雖然循環(huán)方式多,但是平時(shí)常用的也就 each,  for 會比較多,在循環(huán)上的區(qū)別,大多只是兩種語言在語法上的區(qū)別

方法

分類

Ruby 中的方法大致可分為 3 類:

  • 實(shí)例方法

  • 類方法

  • 函數(shù)式方法

實(shí)例方法:Ruby 中的實(shí)例方法 Instance method 和 Java  中的普通方法類似,顧名思義就是調(diào)用方必須是一個(gè)類的實(shí)例(對象),需要調(diào)用實(shí)例方法就必須先通過類構(gòu)造一個(gè)實(shí)例對象才能進(jìn)行調(diào)用,具體請看示例代碼:

# ruby 中的實(shí)例方法  [1, 2, 3] .clear # 清理數(shù)組 =>  [] 100.to_s   # int 轉(zhuǎn) string  => "100" "100".to_i  # string 轉(zhuǎn) int => 100 ["a", "b", "c"].index("b")  # 查找下標(biāo) => result: 1
// java 中的實(shí)例方法 StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("abc");  // 實(shí)例方法 append stringBuilder.append("efg");  List<String> strList = new ArrayList<>(); strList.add("abc");  // 實(shí)例方法 add strList.add("efg");

類方法:Ruby 的類方法 class method 可以理解為 Java  的靜態(tài)方法,就是需要類對象作為接收方的方法,指無需構(gòu)建類的對象即可以直接通過類調(diào)用其自身的方法,大多常見于工具類當(dāng)中,請看示例代碼:

// java 中的靜態(tài)方法 Arrays.asList(T...a)    // 數(shù)組轉(zhuǎn)集合 Executors.newCachedThreadPool()  // 創(chuàng)建線程池
# ruby 中的類方法 Hash.new  # 創(chuàng)建散列對象 Time.new  # 創(chuàng)建時(shí)間對象

函數(shù)方法是指沒有接收者的方法,這種類型方法在Java中倒是不存在,參考示例代碼,例如上文中函數(shù)方法 p

p "hello" puts "print words"

定義實(shí)例方法

Ruby 定義方法非常簡單,沒有 Java 那么多的格式規(guī)范:修飾符:靜態(tài)聲明:返回值:方法名:(參數(shù)...),在方法聲明的形式上要簡單許多,主要通過  def 關(guān)鍵字定義,具體參考示例代碼:

// java define method public static int add(int x, int y) {    return x * y } add(2, 5) // 10
# ruby define method  def add(x, y)     x * y end   add(2, 5) #=> 10  # 帶默認(rèn)值的方法 def add(x=2, y=6)     x * y end  # 省略參數(shù)使用默認(rèn)值調(diào)用方法 add #=> 12  # 指定參數(shù)的方法 add(2, 5) #=> 10

在方法的命名規(guī)則,兩種語言還有如下區(qū)別:

  • Ruby 方法名可由英文字母,數(shù)字,下劃線組成,但不能以數(shù)字開頭,例如 hello_with_name

  • Java 方法名首字母必須由英文小寫開頭,英文格式遵循駝峰原則,不允許出現(xiàn)連接符,例如 addPerson

返回值return:上面的 ruby 方法并沒有聲明 return 語句也可以拿到返回值,并不代表 ruby 沒有 return 關(guān)鍵字,ruby  有一個(gè)特點(diǎn)就是如果沒有聲明 return 語句那么方法最后一個(gè)表達(dá)式會成為方法的返回值遵循這個(gè)約定所以上述的方法就可以省略 return  關(guān)鍵字,所以在日常開發(fā)中會較少的使用 return 關(guān)鍵字

定義類方法

前面講過 Ruby 的類方法實(shí)際上就等于 Java 的靜態(tài)方法,Ruby 中定義類方法的示例代碼:

# ruby 定義類方法 class Hello   # class << self 定義類方法的一種方式  class << self   def say_morning    p "hello good morning"   end   #... class << self 塊后面還可以定義多個(gè)類方法  end end  Hello.say_morning  # 類方法 #=> "hello good morning"    h = Hello.new h.say_morning  # 如果用實(shí)例對象類方法就會報(bào)錯(cuò)!undefined method 'say_morning'

在 Java 中定義靜態(tài)方法的示例:

public class Hello {      public static void sayMorning() {         System.out.println("hello good morning");     }      public static void main(String[] args) {         Hello.sayMorning();     } }  #=> "hello good morning"

定義方法也都是很簡單的知識點(diǎn),通過以上程序,我們可以得出:

  • Ruby 使用 class << self 或者 class << 類名 可以將代碼塊內(nèi)的方法全部聲明為類方法

  • Java 使用 static 修飾符定義靜態(tài)方法,不能定義塊,我想可能因?yàn)橐?guī)范和可讀性的原因

Ruby 的特點(diǎn)是特定的功能都可以有N種不同的方式實(shí)現(xiàn),所以定義類方法不但只有 class << self ~ end 還可以使用 def  class_name.method_name ~ end 這種形式定義 class_name 是類名,method_name 為方法名,如果是在當(dāng)前 class  上下文中可以像示例代碼用同樣的形式 def self.method_name ~ end 定義類方法

方法參數(shù)

默認(rèn)參數(shù) Rudy 的方法默認(rèn)參數(shù)是我個(gè)人比較喜歡的特性,Java 程序里方法參數(shù)是強(qiáng)類型檢查的,就是必須按照參數(shù)定義的類型進(jìn)行傳參,JDK 1.5 后  Java 也出了可變參的特性,不過因?yàn)閷?shí)現(xiàn)效果不是很理性,目前在主流 Java 開發(fā)規(guī)范中還是不被推薦使用的,我們先看一段 Java  定義參數(shù)和使用參數(shù)的示例代碼:

// 方法要求類型,順序,并且必傳 public void show(String name, int age, String address) {     System.out.println(name + ", " + age + ", " + address); }  //  new Person().show("胖大海");          // 編譯出錯(cuò),參數(shù)不符合要求 // new Person().show("胖大海", 19);          // 編譯出錯(cuò),參數(shù)不符合要求   new Person().show("胖大海", 19, "北京朝陽區(qū)");     // 編譯通過輸出:胖大海, 19, 北京朝陽區(qū)

Ruby 則會靈活一些,具體請看示例代碼:

# 無需聲明類型,帶默認(rèn)值的參數(shù)可不傳  def show(name, age=18, address="北京市")   p "#{name}, #{age}, #{address}"  end  Person.new.show("胖胖")  #=> 輸出:胖胖, 18, 北京市

不過對于可變參數(shù)兩種語言的實(shí)現(xiàn)幾乎相同,形式上都是對參數(shù)進(jìn)行特殊標(biāo)記,Java 是通過在參數(shù)前面加...標(biāo)識,ruby 則在參數(shù)前面使用 *  號標(biāo)識,解釋器會對這種語法用數(shù)組進(jìn)行轉(zhuǎn)換,兩者代碼量也差不多,沒有什么差別,簡單看下示例代碼:

 public void names(String ...names) {         System.out.println("params :" + Arrays.toString(names));     }      new Person().names("java", "ruby", "go", "c++");  // 輸出結(jié)果 :params :[java, ruby, go, c++]
 def names(*names)   p "params: #{names}"  end  Person.new.names("java", "ruby", "go", "c++") # 輸出結(jié)果:params: [\"java\", \"ruby\", \"go\", \"c++\"]

簡單通過 2 段代碼的對比,我們可以對兩種語言的方法參數(shù)得出以下結(jié)論:

  • Java 方法會嚴(yán)格按照定義,強(qiáng)制要求類型,值必傳,否則編譯期會報(bào)錯(cuò),并且無法在聲明時(shí)定義參數(shù)的默認(rèn)值

  • Ruby 方法參數(shù)未設(shè)定默認(rèn)值,不傳參數(shù),只會在執(zhí)行期報(bào)錯(cuò),但如果聲明時(shí)定義參數(shù)默認(rèn)值,則參數(shù)可不傳

  • Ruby 方法參數(shù)無需定義類型,動(dòng)態(tài)語言的類型大多是推斷出來的

  • 可變參數(shù)兩者實(shí)現(xiàn)方式相同,Java 通過 類型...names 實(shí)現(xiàn),Ruby 通過 *names 語義實(shí)現(xiàn)

方法的基本使用大概就講到這里,函數(shù)方法定義平時(shí)使用不多就暫時(shí)先不聊,繼續(xù)了解還可以看看:定義帶塊的方法,關(guān)鍵字參數(shù)等都是一些語法糖,就不詳細(xì)講解了,接下來聊聊類和模塊

類和模塊

Ruby 也是通過 class 關(guān)鍵字定義類,簡單的用法參考以下代碼:

class Hello end  h = Hello.new

Java 也是通過 class 定義類,不同的是最外層的類 Java 必須使用 public 進(jìn)行修飾,具體請看示例代碼:

public class Hello {      public static void main(String[] args) {         Hello h = new Hello();     } }

那么 Ruby 和 Java 在定義類方面有什么區(qū)別?

  • Ruby 類只有 initialize 構(gòu)造函數(shù),Java 可以根據(jù)參數(shù)不同定義不同的構(gòu)造函數(shù),Java 構(gòu)造函數(shù)必須于類名相同

  • Ruby 和 Java 在類的命名規(guī)則上是一致的,類名必須是首字母大寫開頭

  • Java 通過 public class 修飾類(內(nèi)部類通過 class 修飾),Ruby 則通過 class 修飾類

  • Java 類名必須與文件名相同,Ruby 的文件名和類名不要求強(qiáng)制關(guān)聯(lián)

兩種編程語言在構(gòu)造函數(shù)上對比的示例代碼:

# 帶構(gòu)造函數(shù)的 Ruby 類 class Hello  def initialize(name="Ruby") # 默認(rèn)參數(shù)   @name = name  end   def say_hello  # 實(shí)例方法   p "hello #{@name} ! how are you?"  end end  h = Hello.new("james") h.say_hello #=> "hello james ! how are you?" // 帶構(gòu)造函數(shù)的 java 類 public class Hello {      private String name;     // 有參構(gòu)造函數(shù)     public Hello(String youName) {         this.name = youName;     }      public void sayHello() {         System.out.println("hello! " +name+ " how are you ?");     }      public static void main(String[] args) {         Hello h = new Hello("jack");         h.sayHello();     } } #=> "hello! jack how are you ?"

方法聊到這里,下來聊聊方法里的常量

常量對比

如果在 Java 和 Ruby 中定義常量,參考示例代碼:

// Java 中定義常量 public class Hello {   // 常量必須是 static final 修飾,代表不可變     public static final String VERSION = "1.0";      public static void main(String[] args) {        // Hello.VERSION = "1.5";    // 嘗試修改則會在編譯期報(bào)錯(cuò)         System.out.println(Hello.VERSION);     } } #=>"1.0" # Ruby 中定義常量 class PhoneNumber  BeiJing = "020"  GuangZhou = "021" end  p PhoneNumber::BeiJing  #=> "020" p PhoneNumber::GuangZhou  #=> "021"  Phonenumber::BeijING = "303"  #=> Ruby 可以修改常量,不會報(bào)錯(cuò),但會提示警告  p PhoneNumber.Beijing  #=> ERROR undefined method !

在定義常量上的區(qū)別:

  • 命名規(guī)則:Ruby 要求常量首字母大寫,可用駝峰也可全大寫,Java 則要求常量全部大寫,并且必須是 final static 修飾(Java 里的  final 代表不可變,可以聲明類,方法和變量)

  • 調(diào)用方式:Ruby 必須使用 :: 通過類名進(jìn)行外部訪問常量,java 把常量只是當(dāng)成普通的局部變量,使用連接符 . 直接訪問即可

  • 修改變量:Java 不允許修改常量,任何修改的動(dòng)作會讓編譯器報(bào)錯(cuò) Connot assign a value to final variable  并且無法通過編譯,Ruby 則不同,允許修改常量,但解釋器會提示警告信息:warning: already initialized constant

訪問級別

Ruby 和 Java 在方法訪問級別上沒有什么很大不同,只是 Ruby 沒有包(Package)的概念,所有自然也就沒有 Java  里面的包訪問權(quán)限,細(xì)節(jié)上但是還有些許區(qū)別,Ruby 的三種訪問級別的定義方法,具體用法直接看示例代碼:

# 定義方法時(shí)聲明訪問權(quán)限  private def call_v1   p "call_v1 is private"  end   # 定義方法后,再設(shè)定訪問權(quán)限  def call_v2   p "call_v2 is private"  end   private :call_v2  # 設(shè)定 call_v2 為 private   # 對代碼塊設(shè)定, 以下的方法定義為 private   private  def call_v3   p "call_v3 is private"  end   def call_v3   p "call_v4 is private"  end

Java 設(shè)定方法訪問級別的方式則比較單一,只能在定義時(shí)聲明:

private String priv() {        return "priv is private";    }

綜上所述,兩種語言在訪問級別的差異和總結(jié):

Java 方法默認(rèn)修飾符是 包訪問權(quán)限

Ruby 方法默認(rèn)訪問級別是 public(initialize 例外)

Java 方法只能在定義的時(shí)候使用關(guān)鍵字設(shè)定訪問級別

Ruby 常用的則有三種方式可以設(shè)定方法的訪問級別,非常靈活

繼承

Ruby 和 Java 的所有類都是基于 Object 的子類,Ruby 則還有更加輕量級的  BasicObject原始類,這里先不詳細(xì)描述,繼承這個(gè)概念也不多說,面向?qū)ο蟮幕A(chǔ)知識,直接先看兩種語言實(shí)現(xiàn)繼承的方式

Ruby 通過 < 父類名 實(shí)現(xiàn)繼承,示例代碼:

class Car  def drive   p "car start.."  end end  class SuperCar < Car  def speed_up   p "speed to 200km ..."  end end  s = SuperCar.new s.drive s.speed_up  #=> "car start.." #=> "speed to 200km ..."

Java 通過 extends實(shí)現(xiàn)繼承的,示例代碼:

class Car {     void drive(){         System.out.println("Car Start ...");     } }  public class SuperCar extends Car {      void speedUp() {         System.out.println("speed to 200km...");     }      public static void main(String[] args) {         SuperCar c = new SuperCar();         c.drive();         c.speedUp();     } } // Car Start ... // speed to 200km...

關(guān)于類的繼承方面我們可以得出以下總結(jié):

  • Ruby 通過 < 實(shí)現(xiàn)繼承, Java 通過 extends 關(guān)鍵字實(shí)現(xiàn)繼承

  • Ruby ,Java 在類沒有指定父類的情況下都默認(rèn)繼承 Object類

關(guān)于繼承還有一些經(jīng)驗(yàn)分享的就是,繼承的特性更多用于重寫父類和多態(tài),如果是想要復(fù)用公共的功能,但是類之類沒有明顯的繼承關(guān)系的話,就應(yīng)該遵循組合優(yōu)先大于繼承的原則,不過在  Ruby 中很好的通過 Mix-in 擴(kuò)展解決的繼承這個(gè)問題

模塊和Mix-in

模塊使用 module 關(guān)鍵字創(chuàng)建,命名規(guī)則和類一樣,首字母必須大寫,我們先來看看如何創(chuàng)建模塊

module Display  def open   p "open display..."  end end  Display.open # private method `open' called for Display:Module (NoMethodError)

模塊是 Ruby 的特色功能,定位也很明確,有以下幾個(gè)特點(diǎn):

  • 不能擁有實(shí)例,不能被繼承,所以模塊定位清晰,僅僅表示事物的通用行為

  • 函數(shù)僅僅只能在內(nèi)部被調(diào)用,除非使用 module_function 聲明模塊函數(shù)

  • 模塊更多是結(jié)合 Mix-in 和 include 使用,為類提供增強(qiáng)和更多的可能性

Ruby 中的模塊提供的命名空間 namespace 概念就跟 Java  的包(Package)類似,都是用于區(qū)分相同的類,常量,Mix-in 結(jié)合 include 也就類似 Java 里面的靜態(tài)導(dǎo)入,在 Java 中 import  static 可以無需聲明包路徑直接調(diào)用導(dǎo)入類的變量和方法,所謂的 Mix-in 就是利用模塊的抽象能力把非繼承關(guān)系的類之間的共性進(jìn)行抽象和復(fù)用,有些類似  AOP 的概念,可以使代碼既強(qiáng)大又靈活

當(dāng)我們用 OOP 思想對現(xiàn)實(shí)進(jìn)行抽象的時(shí)候,會發(fā)現(xiàn)很多非繼承關(guān)系又存在共同功能的事物,例如智能手機(jī),手表繼承自不同的父類,但是他們又都有看時(shí)間  watch_time的能力,我們用代碼展現(xiàn)這種繼承關(guān)系,請看示例代碼:

class Phone  def call   p "phone call.."  end end  class IPhone < Phone  # iPhone 繼承自 Phone 類,但是不僅可以打電話,還可以看時(shí)間  def watch_time   p "watch_time 12:00:000"  end end  class Watch  # 手表都可以看時(shí)間  def watch_time   p "watch_time 12:00:000"  end end  class AppleWatch < Watch  # AppleWatch 不僅看時(shí)間,還有運(yùn)動(dòng)的功能  def run   p "start run"  end end

結(jié)合上面的代碼,我們可以看到 watch_time 代碼重復(fù),對于不同繼承體系但是相同功能的時(shí)候,就可以用 Mix-in 解決這個(gè)問題,思路如下:

  • 將例如 watch_time 相同的方法和代碼,抽出定義在 module 模塊中

  • 使用 include 引入模塊,將方法引入到實(shí)際的類中

使用 Mix-in 后我們可以看下代碼變化,示例代碼:

module WatchTime  # 抽出通用的方法  def watch_time   p "watch_time 12:00:000"  end end  class Phone  def call   p "phone call.."  end end  class IPhone < Phone  include WatchTime end  class Watch  include WatchTime end  class Apple_watch < Watch  # apple_watch 不僅看時(shí)間,還可以運(yùn)動(dòng)  def run   p "start run"  end end

使用 Mix-in 這種靈活的語法實(shí)現(xiàn)了魚和熊掌兼得,即沒有破壞繼承結(jié)構(gòu)關(guān)系又實(shí)現(xiàn)共性方法的代碼復(fù)用問題,因?yàn)?Java 沒有 Mix-in  的概念所以就不展示示例代碼了,不過 Java 也有自己的解決方案,而且在 Java 的解決代碼復(fù)用問題通常都應(yīng)該遵循 組合大于繼承 的原則,因?yàn)?Java  的語言設(shè)計(jì)讓繼承更多用于多態(tài)而非復(fù)用

運(yùn)算符

簡單說一下運(yùn)算符,雖然大多編程語言的運(yùn)算符非常的簡單,賦值運(yùn)算,邏輯運(yùn)算,條件運(yùn)算符所有語言的使用方式都幾乎差不多,好像沒什么好講的,但 Ruby  靈活的語法是有不少語法糖,還是可以 Java 程序員羨慕的一下的,假設(shè)一張我們在業(yè)務(wù)代碼中經(jīng)常遇到的情況,根據(jù)表達(dá)式取值,當(dāng)表達(dá)式為 true  時(shí)改變變量的值,這種簡單邏輯賦值在 Java 只能這樣寫,請看示例代碼

String value = "abc"; if (condition != null) {   value = condition; } // 看上去很啰嗦

這種情況在 Ruby 中一行代碼可以實(shí)現(xiàn)相同語義:

# 當(dāng) condition 表達(dá)式為 true 執(zhí)行 value = condition , 否則執(zhí)行 value = "abc" value = condition || "abc"

只所以可以實(shí)現(xiàn)是因?yàn)?Ruby 有一個(gè)不同 Java 的特定, Ruby 對象都可以用于進(jìn)行布爾表達(dá)式判斷,判斷邏輯為**對象本身不為 nil 或者  false 表達(dá)式則為 true,否則為 false **

還有一種邏輯則是取相反的情況,例如我們經(jīng)常遇到一種情況是,判斷數(shù)組不為空的時(shí)候取數(shù)組的某一個(gè)下標(biāo),在 Java 中只能這樣寫,示例代碼

List<String> list = Arrays.asList("a", "b", "c"); String item = null; if (list != null) {         item = list.get(0); } // "a"

這種情況可以用邏輯運(yùn)算符 &&, 它剛好與上面 || 相反,也是一行代碼可以實(shí)現(xiàn)相同功能

str_list = ["a", "b", "c"] item = str_list && str_list[0] #=> "a"

我個(gè)人非常喜歡這種簡潔的寫法,不過建議在多人項(xiàng)目中不要用太多語法糖,不然可能會造成項(xiàng)目代碼可讀性混亂

異常處理

很多程序員大部分時(shí)間都花在查錯(cuò)上,所以迅速定位異常很關(guān)鍵,先看看 Ruby 的異常格式 文件名:行號:in 方法名:錯(cuò)誤信息(異常類名)  簡單的用法就不寫示例代碼了,不然占用太多篇幅,兩種語言處理異常方法大同小異,具體處理方式有如下區(qū)別:

  • Ruby 處理異常使用 begin ~ rescue ~ ensure ~ end 這里太簡單就不寫示例代碼了

  • Java 7 使用 try ~ catch ~ finally 到 Java 8 后有了更高效的 try ~ with ~ resources  可自動(dòng)關(guān)閉資源

不過 Ruby 的 Retry 倒是 Java 沒有的特性,它適合對一些容易出錯(cuò)的程序(例如調(diào)用外部 API  )可以進(jìn)行快速重試,具體可以請看示例代碼

class HandleException  def zero   x, y = 100, 0   begin    x = x / y   rescue    p '執(zhí)行異常邏輯'    y = 2    retry   end   x  end end  h = HandleException.new p h.zero  #=>"執(zhí)行異常邏輯" #=>50

上述程序非常簡單,大概邏輯是首次執(zhí)行會拋出異常,然后被 rescue 捕獲后重新復(fù)制,第二次運(yùn)算成功,Java  如果要實(shí)現(xiàn)相同的語義的話,則代碼沒有這么簡潔了,跟上章節(jié)的邏輯運(yùn)算符 &&,|| 類似 resuce  也具備條件表達(dá)式的運(yùn)算,具備很強(qiáng)的表達(dá)能力,我們嘗試對以上述代碼進(jìn)行一些簡化,示例代碼:

x, y = 100, 0 x = x / y rescue 50 # => x = 50

當(dāng)運(yùn)算 x / y 沒有出現(xiàn)異常則運(yùn)算 x = x / y,當(dāng)出現(xiàn)異常被 resuce 捕獲后則運(yùn)算 x = 50,但相同邏輯在 Java  里面就會顯得有點(diǎn)啰嗦,請看示例代碼:

int x = 100, y = 0; try {     x = x / y; }catch (ArithmeticException ae) {     x = 50; } // x = 50

不過像這種小技巧建議只用于簡單的場景,如果業(yè)務(wù)流程復(fù)雜,為了保證代碼清晰易懂還是建議使用標(biāo)準(zhǔn)的 begin ~ rescue ~ ensure ~ end  異常處理語句 ,異常章節(jié)到此結(jié)束,在文章尾部我們總結(jié)一下 Java 和 Ruby 在異常處理的區(qū)別:

  • Ruby 標(biāo)準(zhǔn)異常庫都是繼承 Exception 類,程序通常只能處理 StandarError 異常或其子類

  • Java 異常都是繼承 Throwable ,異常被劃分為 Error 異常和 Exception,程序通常只能處理 Exception 的子類  RuntimeException 以及其子類

  • Ruby 支持 retry 從異常中快速重試,rescue 表達(dá)式簡化異常代碼處理,Java 則沒有該功能

  • Java 主動(dòng)拋異常的使用 throw new Exception,而 Ruby 則使用 raise 方法

兩種語言的基本語法對比就先寫到這里,暫時(shí)就不寫分析和總結(jié)了,因?yàn)槲液罄m(xù)還會繼續(xù)探索 Ruby 和 Java  在其他使用層面的使用區(qū)別對比,例如字符串,數(shù)據(jù)類型,集合,哈希,最后想留一個(gè)問題:你覺得靜態(tài)語言和動(dòng)態(tài)語言最明顯的區(qū)別在哪里?他們各自會存在什么問題?在什么場景下你會偏向動(dòng)態(tài)語言,什么場景你會偏向靜態(tài)語言?

到此,相信大家對“Ruby和Java的基礎(chǔ)語法有哪些區(qū)別”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI