1

This is what I wrote for a coding bat project thing. For some reason it says that this way it doesn't work but if I flip it, it works. Why is that? When it inputs something with less than 3 chars it gets an error message according to codingbat.

// Given a string, return a new string where "not " has been added to the front. 
// However, if the string already begins with "not", return the string unchanged. 
// Note: use .equals() to compare 2 strings. 

// notString("candy") → "not candy"
// notString("x") → "not x"
// notString("not bad") → "not bad"

        public String notString(String str) {
                  String m;
          if ( str.substring (0,3).equalsIgnoreCase("not") && str.length () >= 3 ) // this line doesn't work in it's current state 
          // but works if I flip the two boolean expressions over the &&

                    m = str;
          else {
                    m = "not " + str;
                }
       return m;
GrandMasterFlush
  • 6,269
  • 19
  • 81
  • 104
Max
  • 51
  • 1
  • 1
  • 7
  • 1
    Because you are first getting `substring` and then checking its `length`. What would happen if `length` is less than 3. First part of `&&` would result in error. My guess is it is compiler's way of handling this scenario. – Prateek Oct 23 '13 at 23:11
  • 3
    Instead of using `str.substring (0,3).equalsIgnoreCase("not")` you could use `str.startsWith("not")` and if we want to ignore the case you wound add `str.toLowerCase().startsWith("not")` – vallentin Oct 23 '13 at 23:11

3 Answers3

6

If the length of the string is not at least 3, then str.subtring(0, 3) will fail with a IndexOutOfBoundsException.

The reason that it works when flipped is called short circuit evaluation. Flipped:

if ( str.length() >= 3 && str.substring (0,3).equalsIgnoreCase("not") )

The first condition is evaluated. If it's less than 3, then Java knows that the whole condition is false, because false && anything is false. It won't evaluate the other expression, because it doesn't have to evaluate it. The IndexOutOfBoundsException doesn't come for this reason.

The JLS, Section 15.23 talks about this:

The conditional-and operator && is like & (§15.22.2), but evaluates its right-hand operand only if the value of its left-hand operand is true.

Additionally, the logical-or operator (conditional-or operator) || works similarly. It will only evaluate its right-side operand if the left-side operand is false (JLS Section 15.24).

rgettman
  • 176,041
  • 30
  • 275
  • 357
3

The code you posted above will crash with a StringIndexOutOfBoundsException if str is shorter than three characters, because you're trying to take a 3-character substring of a string that's not long enough.

However, when you flip it around, you check the length of the string first. This means that you know right away that the && will fail (because str.length >= 3 is false), so you short-circuit out of the conditional right then and there. As a result, you never try to take the impossible substring, and you avoid the crash.

As mentioned in the link, both of the logical operators work this way (&& (AND) and || (OR)). If they're able to figure out what to return after evaluating only the left-hand side, the right-hand side never gets touched. So, for example, (true || 1/0 == 0) will always evaluate to true, even though if the right-hand side were to be evaluated, it would throw an exception.

Community
  • 1
  • 1
Henry Keiter
  • 16,863
  • 7
  • 51
  • 80
0

It's because you check

str.substring (0,3).equalsIgnoreCase("not") 

first, before checking a length. So you propably gen an error java.lang.StringIndexOutOfBoundsException if your str is of length less than 3.

You have to check a length first (e.g. by flipping conditions check).

promanski
  • 567
  • 3
  • 12