Control Flow Syntax

Control Flow and Branching Statements

6.27.2013

I was flipping through the Java Tutorial Book looking for interesting topics, and I found a section called "Branching Statements".  What I found was a different way in how to approach loops.  In this section, it uses 'break' and 'continue' to traverse through the loop.  When breaking from a 'for loop', it will immediately exit from the current loop, ignoring 'if statements' if there are any.

Using a break statement in a set of nested for-loops

Something that I immediately learned from this is that break only affects loops.  Good on me for paying attention in class!  In addition, the non-labeled break statements will only leave the inner most loop.

Take for example this simple code:

for(int i = 0; i < 2; i++) {
System.out.print("Sam ");
for (int j = 0; j < 5; j++) {
System.out.print("John ");
if (j == 3)
break;
}
}

It should print Sam John John John John Sam John John John John - because after j equals to 3, it will immediately exit the inner j loop and execute the outer i loop again.  Simple enough.

Using labeled breaks to leave nested for-loop statements

Now moving into new territory, which is Labeled breaks. Searching around the internet, many agree it is bad practice to use break labels to leave nested for-loops.  I felt this is still an interesting topic to look over.

We look at this code example:

search:
for (int i = 0; i < anArray.length; i++) {
for (int j = 0; j < anArray[i].length;j++) {
if (anArray[i][j] == toSearch) {
isFound = true;
break search;
}
}
}

As we can see, once this nested for loop finds a number in a 2d array, it will be forced out by the 'break search' statement and continue on with the program.  Looking from a novice perspective, it is apparent how it will save some cpu cycles of having to search through the rest of the 2d array after the value is found.

A different approach to exiting nested for-loop statements

Other suggestions for this solution would be to create a helper method to return from the search once the specified value was found.

public static boolean findNumber(int search, int[][] array) {

for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length;j++) {
if (array[i][j] == search) {
return true;
}
}
}
return false;
}

and in main...

System.out.println(findNumber(toSearch, anArray) ? toSearch + " was found!" : toSearch + " was not found");

Using a helper method, you are able to achieve the same results as the labeled break statement.


An alternative if/else syntax

On a side note, some of you (and me before I read this section) are wondering what the weird syntax of "boolean ? statement : statement" is.  This is definitely a space saver when it comes to interacting with a boolean expression doing two different actions.  The first part is of the syntax is a boolean variable or function.  After follows a '?'.  Now comes the interesting part...  The first statement before the colon indicates the action to be taken if your boolean expression evaluates to true.  The colon represents an 'else' and will execute in the event that the boolean expression evaluates to false.  Therefore we are able to save the code space of writing the if/else statement, in addition to the repeat of the print statement.  Definitely something I think will come in handy in the future.

Tl;dr - Boolean expression ? statement : statement

//if/else alternative
boolean factOrNot = false;
System.out.println(factOrNot ? "True" : "False");

Prints "False"

Using continue to traverse through a for-loop.

You may use a continue statement when you want to skip the rest of the code segment within a for-loop.  Look at this code example:

String search = "There are that many t's in this sentence, is there?";
int count = 0;
for (int i = 0; i < search.length(); i++) {
if (search.charAt(i) != 't' && search.charAt(i) != 'T')
continue;
count++;
}
This for loop looks at each character of the string.  When the character equals to either 't' or 'T', the if-statement is skipped, and therefore the continue statement is skipped and the counter is incremented,  But what is interesting is when the character does not equal to 't' or 'T'.  Once the program reaches the continue statement, it will skip the current iteration of the for-loop including incrementing the counter.  The result will be the program counting 't' and 'T' 7 times from the string.

Finding leap years!

Now its time to do something a little more applicable to the real world, like checking if a year is a leap year!  I used this website here to help me determine what year is a leap year.  If it is divisible by 4, but not those that are divisible by 100, but can be divisible by 400, it is a leap year.  Confusing right?  So lets take for example 2000.  Divisible by 4, check.  Divisible by 100, you are going to have to check if it is divisible by 400, yes it is.  Check.  It is a leap year!

First things first, and you will want to set up a simple user input system to allow the user to input a year.  Along with some simple instance variables.  isLeap will determine if the year will be a leap year, and year will be the variable that will hold user input.

Scanner sc = new Scanner(System.in);
boolean isLeap = false;
int year = 0;

Next we want to create a state machine that will ask the user for a number, evaluate the number, give the proper response, and then ask the user again for another number.

We create a sentinel value -1 to indicate when we want to leave the loop and exit the program.  I am assuming that the year they will input will be positive for this example's purposes.

while(year != -1)
System.out.println("Please type a year to check if it is a leap year please!"); year = sc.nextInt();

Next, using what we learned we create a labeled break statement. What was interesting about these relations are that the once a condition is met, you must check to see if another meets a different condition.

check: if (year % 4 == 0){ if (year % 100 == 0){ if(year % 400 == 0){ isLeap = true; break check; } isLeap = false; break check; } isLeap = true; }

What we see is that it will check to see if the condition is met, and assign the proper value to isLeap. While looking back at the code, I actually found a different solution that provided much better readibility, at the expense of a couple extra assignments in some cases.

isLeap = false; if (year % 4 == 0) { isLeap = true; if (year % 100 == 0) { isLeap = false; if (year % 400 == 0) { isLeap = true; } } }
isLeap is assigned before the comparison, saving us the hassle of having to keep track of its current state in the 3 conditions. As you can see, the second code example has much better readability than the first, at the expense of a couple lines of code execution, which really is not that much. This is a great example of how break statements can cause readability issues compared to alternative approaches.

Summary


This about sums up today's studies. Lets go over some of the things I learned today.

  1. Break statements will only break from loops, it ignores if statements.
  2. Break statements affect the innermost loop only
  3. Labeled breaks can be a way to exit nested for loops, but adds readability issues as shown in the last example
  4. An alternative syntax for if/else statements "? :"
  5. Continue statement will skip the rest of the current loop iteration, skipping any code after the continue statement and executing the next iteration of the for-loop.
  6. Now you know how to determine if a year is a leap year!
Hope you found this post helpful, and if you have any suggestions feel free to comment or send me a message. This is definitely more along the lines of basics, but definitely got to get those down before I approach harder topics!

On a last note, I am not endorsing the use of break statements, as they have a tendency to cause more harm then good, but as a way to exploring the usages of them in terms of the basics of the Java Language, so that there may be a point when a break statement may be appropriate way of coding something.

Comments

Popular posts from this blog

Uncle Bob's Clean Architecture

C4 Model: Describing Software Architecture

Running RabbitMQ with Docker