2015-02-04 68 views
0

當與含有在Java對象表達式處理我總是檢查它們是否null在第一表達式和所&&然後,以避免一個NullPointerException表達式引用對象(例如obj.length()),因爲&&評估的左手側首先表達(或者我認爲?)。爲什麼這個表達式按照這個順序進行評估?

那麼,爲什麼當ArrayList的長度爲2時,這個表達式給了我一個IndexOutOfBoundsException

 ArrayList<String> tokens = new ArrayList<String>(); 
     tokens.add("hello"); 
     tokens.add("!"); 
     System.out.println(tokens.size()); // 2 

     if(tokens.size() == 3 && tokens.get(0).equals("r") && 
      (tokens.get(2).length() == 0) || tokens.get(2).equalsIgnoreCase("search")) { 
      System.out.println("hi"); 
     } 

它應該檢查大小肯定是3,因此它可以引用列表中的第3個對象。然而,它似乎是首先評估OR表達式,我認爲呢?

編輯:對我模糊的道歉。這裏假定ArrayList不是null。我使用的ArrayList爲null的例子僅用於說明目的。這裏實際發生的是ArrayList中的第3個對象在大小爲2時被訪問,儘管我有一個大小檢查作爲第一個表達式,導致IndexOutOfBoundsException(null是大小爲2的ArrayList的第三個對象)

編輯2:更新了代碼以提供更好的示例。我期望代碼運行並且if語句失敗(是false)。不過,我得到了IndexOutOfBoundsException

編輯3:道歉一次,我得到了一個IndexOutOfBoundsException不是NullPointerException

由於此代碼段是我無法表達分離出來,因爲我知道這的確會解決這個問題

+2

有可能'tokens'爲空,或者包含null對象? – MeetTitan

+0

Per @MeetTitan我建議添加'System.out.println(「tokens:」+ tokens);''''和'System.out.println(「tokens [0]:」+ tokens [0]);'if before your if '條款。另外,爲了加快速度,我會將每個條件作爲一個單獨的(嵌套的)子句來隔離它們。 – eebbesen

+0

ArrayList絕對不包含空對象。絕對包含兩個實例化的對象,其大小爲2 :) – Rob

回答

2

您的問題是運算符優先級。這裏是你的條件,格式化過單獨的線路:

tokens.size() == 3 
&& tokens.get(0).equals("r") 
&& (tokens.get(2).length() == 0) 
|| tokens.get(2).equalsIgnoreCase("search") 

&&經營者擁有的||運算符優先級。什麼你基本上這裏是:

(tokens.size == 3 && something && something) 
|| (tokens.get(2).equalsIgnoreCase("search")) 

由於列表的大小不是3,由運營商&&聯結部失敗。但由於||運算符的優先級較低,因此它將在下一個進行評估。由於左側有false,因此會嘗試評估右側。

所以,你要做到這一點適當的方式將

tokens.size() == 3 
&& tokens.get(0).equals("r") 
&& 
((tokens.get(2).length() == 0) || tokens.get(2).equalsIgnoreCase("search")) 

注額外對周圍的||項括號。

+0

AH,你可以看到這個。我以爲我已經有了這些括號,而且我不能爲我的生活弄清楚這一點。謝謝! – Rob

0

我們需要確保tokens不爲空,也tokens.get(n)不爲空。

試試這個:

if(tokens != null && 
    (tokens.size() == 3 && tokens.get(0) != null && tokens.get(0).equals("r")) && 
    (tokens.get(2) != null && tokens.get(2).length() == 0) || 
    (tokens.get(2) != null && tokens.get(2).equalsIgnoreCase("search"))) { 
     System.out.println("hi"); 
} 

雖然我建議如果嵌套以提高可讀性報表。像這樣:

void sayHi() { 
    System.out.println("hi"); 
} 
if(tokens != null) { 
    if(tokens.size() == 3) 
     if(tokens.get(0) != null && tokens.get(0).equals ("r") 
      if(tokens.get(2) != null && tokens.get(2).length() == 0) { 
       sayHi(); 
      } 
    if(tokens.get(2) != null && tokens.get(2).equalsIgnoreCase("search") { 
     sayHi(); 
    } 
} 

編輯爲了避免IndexOutOfBoundsException,我們將做到以下幾點:

void sayHi() { 
    System.out.println("hi"); 
} 
if(tokens != null) { 
    if(tokens.size() >= 3) { 
     if(tokens.get(0) != null && tokens.get(0).equals ("r") 
      if(tokens.get(2) != null && tokens.get(2).length() == 0) { 
       sayHi(); 
      } 
     if(tokens.get(2) != null && tokens.get(2).equalsIgnoreCase("search") { 
      sayHi(); 
     } 
    } 
} 

這可以確保tokens不爲空,也有tokens至少3項,並tokens.get(n)不爲null。

之前,我們有大小檢查之外的「搜索」聲明。現在,我們將它包含在大小檢查中,以防止代碼在tokens不包含該索引處的對象時運行。

+0

謝謝你的回答,但是我在這個問題上犯了一個錯誤。我得到一個IndexOutOfBoundsException,你可以看到這個如果你運行更新代碼@RobertHealy – Rob

+0

,看看我的編輯。 – MeetTitan

+0

你說得對,但它不能解釋爲什麼 – Rob

0

我會嘗試一下本作你的問題索引越界希望它會幫助你

if(tokens.size() == 3){ 

    if(tokens.get(0).equals("r") && 
     (tokens.get(2).length() == 0) || 
     tokens.get(2).equalsIgnoreCase("search")) { 

       System.out.println("hi"); 
     } 
    } 

對不起,我英文不好

+0

感謝您的回答,但是我在該問題中犯了一個錯誤。我得到一個IndexOutOfBoundsException,如果你運行更新的代碼 – Rob

相關問題