为什么按此顺序评估此表达式?

时间:2015-02-04 20:45:13

标签: java

当处理包含Java中对象的表达式时,我总是检查它们是null在第一个表达式后跟&&,然后检查引用该对象的表达式(例如obj.length())以便避免使用NullPointerException,因为&&首先评估表达式的左侧(或者我认为是这样?)。

那么,当IndexOutOfBoundsException的长度为2时,为什么这个表达式会给我ArrayList

        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仅用于说明目的。这里实际发生的是,当大小为2时,正在访问ArrayList中的第3个对象,即使我将大小检查作为第一个表达式,导致IndexOutOfBoundsException(null是大小的第3个对象) 2 ArrayList)

编辑2:更新了代码以提供更好的示例。我希望代码运行和if语句失败(是假的)。但是我得到IndexOutOfBoundsException

编辑3:APOLOGIES,我得到IndexOutOfBoundsException而不是NullPointerException

由于此代码段的代码,我不能将表达式分开,因为我知道这确实可以解决这个问题

3 个答案:

答案 0 :(得分: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") )

请注意||项周围的额外括号。

答案 1 :(得分: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");
}

虽然我建议嵌套if语句以提高可读性。像这样:

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)不为空。

在我们进行&#34;搜索&#34;在尺寸检查之外的声明。现在我们将它包含在大小检查中,以防止代码在tokens不包含该索引处的对象时运行。

答案 2 :(得分: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");
      }
   }

抱歉我的英文不好