Skip to content

Programming by Design

If you're not prepared to be wrong, you'll never come up with anything original. – Sir Ken Robinson

  • About
  • Java-PbD
  • C-PbD
  • ASM-PbD
  • Algorithms
  • Other

Short-Circuit Evaluation – Advanced Example

Posted on December 28, 2012November 19, 2024 By William Jojo
Algorithms

(Updated November 19, 2024)

Short-Circuit Evaluation – Advanced Example

The Problem

As we know, with the conditional operators && (and) and || (or), we can join multiple Boolean expressions together to form a more complex expression. You may also recall that these operators operate in a mode known as short-circuit. This means that once truth is established, the evaluation will not proceed further.

This is both a blessing and a curse, depending on your perspective. Consider a loop that needs to be simple and fast. This loop needs to trim non-letter/non-digit characters from the ends of a string, like in the following:

"word" becomes word

or

"What!" becomes What

or

/****/ becomes null

The Design

One approach could be to set pickets at each end of the string, move them inward toward the center as needed, and then take the substring() of the result. The following shows the setup:

         0   1   2   3   4   5
       +-----------------------+
 s ->  | " | W | o | r | d | " |
       +-----------------------+
         b                   e
        -->                 <--

Essentially, we have a string s and variables b and e (begin and end) to represent the extreme ends of the string s.

Some source code to produce the setup might look something like this:

public static String removeNonLetDig(String s) {
  int b = 0, e = s.length()-1;

  // Do work here...    
}

Since we should move only one picket at a time, we will consider two loops - one for each end - moving a picket toward the center. The next picture depicts the result we are striving for:

         0   1   2   3   4   5
       +-----------------------+
 s ->  | " | W | o | r | d | " |
       +-----------------------+
             b           e

The loops are simple - move the picket as long as we view a non-letter/non-digit character. The isLetterOrDigit() method of the Character wrapper class will do nicely. We will want a condition like:

!Character.isLetterOrDigit(s.charAt(b))

Crossing over of the indexes b and e means we've run out of string to work with, so we should consider that ( b <= e or e >= b ).

Now, we just move the pickets to the appropriate positions with something like the following:

  public static String removeNonLetDig(String s) {
    int b = 0, e = s.length()-1;
    
    // Trim from the beginning
    while (!Character.isLetterOrDigit(s.charAt(b)) && b <= e)
      b++;
    
    // Trim from the end
    while (!Character.isLetterOrDigit(s.charAt(e)) && e >= b)
      e--;
    
    if (b <= e)
      return s.substring(b, e + 1);
    else
      return null;
  }

The code for the method removeNonLetDig() is small, concise, and perhaps even clever in its simplicity. But we are about to reveal a detail in testing that has been overlooked up to this point.


The New Problem

The following code is complete for testing the new method and includes reasonable test values with predictable results based on the initial discussion at the beginning of the post.

ShortCircuit.java
public class ShortCircuit {
  
  // Remove punctuation from ends of a string
  public static String removeNonLetDig(String s) {
    int b = 0, e = s.length()-1;
    
    // Trim from the beginning
    while (!Character.isLetterOrDigit(s.charAt(b)) && b <= e)
      b++;
    
    // Trim from the end
    while (!Character.isLetterOrDigit(s.charAt(e)) && e >= b)
      e--;
    
    if (b <= e)
      return s.substring(b, e + 1);
    else
      return null;
  }
  
  public static void main(String[] args) {
    
    String w = "\"word\"";
    String x = "\"What!\"";
    String p = "/******/";
    
    System.out.println(w + " = " + removeNonLetDig(w));
    System.out.println(x + " = " + removeNonLetDig(x));
    System.out.println(p + " = " + removeNonLetDig(p));
  }
}

The conditions specified in the while loops have been crafted based on our thought process from the design. The problem is when we get to main() method, we will call removeNonLetDig() with a value that will cause a StringIndexOutOfBoundsException in the first while loop.

Why?

The charAt(b) method is invoked before we validate that the value of b is within the supported range.

How are we checking for b in the valid range?

With the b <= e test. But it appears later in the condition.

Does that matter?

In this case, very much so. We should rely on the nature of short-circuit evaluation to help us avoid this run-time error. If b > e, we don't want to try and get a character from the string since we know we would be out of bounds. Having the b <= e first and evaluate to false on an && operator means the second half will be ignored - because it only matters if the first half is true!

The final, corrected version is shown below with the while loops modified:

ShortCircuit.java
public class ShortCircuit {
  
  // Remove punctuation from ends of a string
  public static String removeNonLetDig(String s) {
    int b = 0, e = s.length()-1;
    
    // Trim from the beginning
    while (b <= e && !Character.isLetterOrDigit(s.charAt(b)))
      b++;
    
    // Trim from the end
    while (e >= b && !Character.isLetterOrDigit(s.charAt(e)))
      e--;
    
    if (b <= e)
      return s.substring(b, e + 1);
    else
      return null;
  }
  
  public static void main(String[] args) {
    
    String w = "\"word\"";
    String x = "\"What!\"";
    String p = "/******/";
    
    System.out.println(w + " = " + removeNonLetDig(w));
    System.out.println(x + " = " + removeNonLetDig(x));
    System.out.println(p + " = " + removeNonLetDig(p));
  }
}

Additional Thoughts

Consider how you would fix this problem if we did not have a short-circuit evaluation.

One solution could be introducing a boolean value to indicate we should continue. The highlighted code shows what is needed for just one of the loops.

  public static String removeNonLetDig(String s) {
    int b = 0, e = s.length()-1;
    boolean ok;
    
    // Trim from the beginning
    ok = true;
    while (ok && b <= e) {
      if (!Character.isLetterOrDigit(s.charAt(b)))
        b++;
      else
        ok = false;
    }

    // repeat for the other end
  }

Another solution could be to use break to get us out of the loop sooner. Again, the highlighted code shows the changes to just one of the loops.

  public static String removeNonLetDig(String s) {
    int b = 0, e = s.length()-1;
    
    // Trim from the beginning
    while (b <= e) {
      if (!Character.isLetterOrDigit(s.charAt(b)))
        b++;
      else
        break;
    }

    // repeat for the other end
  }

Post navigation

❮ Previous Post: CISS-110 Syllabus
Next Post: CISS-110 Project 1 ❯

Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Copyright © 2018 – 2025 Programming by Design.