Abstract: Java does not use the "goto" statement, although it is a reserved word. We do have something similar though: labeled breaks.
Welcome to the 110th edition of The Java(tm) Specialists' Newsletter. I am back in South Africa again, and trying to catch up with the mountain of work that had accumulated during my international travels in the first half of this year. I created a map of the world showing all the countries with subscribers to The Java(tm) Specialists' Newsletter in green. The white spaces still need colouring in, so if you live in, e.g. Albania, Mozambique, Lesotho, please send send me a quick email.
Java in Action: The Serverside was kind enough to accept me as speaker at their conference in Orlando, Florida, in October 2005. Please please let me know if you are going, I would love to meet you.
We are having a rather wet start to winter down here in the southern hemisphere. We cut down some trees last year, and some of the logs are rather big. Helene and I are having a running competition to see who can keep the fire burning longer, which involves squeezing the biggest pieces into the fireplace. She first managed for 3 days, then I kept one burning for 5 days, even getting up at 2:00am to make sure that there was enough wood. I think Helene is now trying to set a new record, so I will have to be on my guard. Problem is that we are slowly running out of wood, so we will either have to sacrifice another tree, or buy firewood, otherwise Helene might start burning our furniture (again :) [In case you love trees, we only burn alien trees, such as Blue Gum and Silky Oak.]
Talking of trees, I bought a second-hand mountain bike last week, and have been trying to increase my level of fitness. Last Friday morning, I cycled to Silverboomkloof with my son Maxi, a tiny nature reserve not far from where we live in Somerset West. This is one of the only places in the world where the Silver Tree Leucadendron argenteum grows. How they got there remains a mystery, since these trees are endemic to Table Mountain, about 50km away.
javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.
Yesterday I was reading through some of the latest Java 5 source code, and stumbled across a snippet of code in java.lang.String that looked rather surprising. Before we look at it, I would like to point out that I strongly discourage the use of break and continue. They are leftovers from the days of C and should be avoided since they can make your code hard to read.
public class String { public String toLowerCase(Locale locale) { // ... /* Now check if there are any characters that need to be changed. */ scan: { int c; for (firstUpper = 0 ; firstUpper < count ; firstUpper += Character.charCount(c)) { c = codePointAt(firstUpper); if (c != Character.toLowerCase(c)) { break scan; } } return this; } // *snip* }
This code struck me as bizarre. I had seen a label before a switch and before a loop, but never a label before a code block (i.e. an open curly brace '{').
It appears that you can write a label before any statement. When you break to that label, you jump to the end of that statement. There are lots of places where this does not make sense, and you would be able to write rather weird code, such as:
public class StrangeLabels { public static void main(String[] args) { what: break what; // not an infinite loop, but pointless code what: new Runnable() { // we can define the same label twice // we cannot access the label from in here public void run() { } }.run(); what: System.out.println("Hello"); // completely pointless int i; what: i = 42; // label on the assignment } }
I do not think that any of those applications of the labeled statement break are sensible. However, you might decide to use the labeled break to jump out of try block without throwing an exception:
public class LabelTryFinally { public static void main(String[] args) { what: try { if (true) { break what; // you can jump out of the try block, but // of course the finally first is executed } System.out.println("in try"); } finally { System.out.println("in finally"); } } }
The code simply outputs "in finally" and exits.
Is there an actual use case for this code? Probably not. I doubt that the micro-improvements (if any) in performance would warrant cryptic code. In The Java Language Specification, 3rd Edition, Sun give an example on pages 388-389 that is almost impossible to read. Even the code in java.lang.String took me a good few minutes to understand.
Here is a way that you could use the labeled statement in the same spirit as was used by Sun in the java.lang.String class:
/** * Both sort functions iterate through the array to see whether * it already is sorted. If it is, they return the original * array, otherwise they construct a new array, copy the old * values over sort that and return it. */ public class LabeledStatementBreakTest { /** * The approach I often see used for this type of problem. */ public static int[] sortWithoutBreak(int[] vals) { // first check if the array is sorted already boolean sorted = true; for (int j = 1; j < vals.length && sorted; j++) { sorted = vals[j - 1] <= vals[j]; } if (sorted) return vals; int[] sortedArray = new int[vals.length]; System.arraycopy(vals, 0, sortedArray, 0, vals.length); java.util.Arrays.sort(sortedArray); return sortedArray; } /** * Using a labeled statement combined with a break to jump * around the method. */ public static int[] sortWithBreak(int[] vals) { // first check if the array is sorted already scan: { for (int j = 1; j < vals.length; j++) { if (vals[j - 1] > vals[j]) break scan; } // sorted already return vals; } int[] sortedArray = new int[vals.length]; System.arraycopy(vals, 0, sortedArray, 0, vals.length); java.util.Arrays.sort(sortedArray); return sortedArray; } /** * This is the approach I normally use to solve this. */ public static int[] sortHeinz(int[] vals) { // first check if the array is sorted already if (isSorted(vals)) return vals; int[] sortedArray = new int[vals.length]; System.arraycopy(vals, 0, sortedArray, 0, vals.length); java.util.Arrays.sort(sortedArray); return sortedArray; } private static boolean isSorted(int[] vals) { for (int j = 1; j < vals.length; j++) { if (vals[j - 1] > vals[j]) return false; } return true; } public static void main(String[] args) { int[] vals1 = {1, 4, 5, 2, 3}; int[] vals2 = {-1, 3, 3, 5, 12, 30}; // output should always be "true" System.out.println(vals1 != sortWithoutBreak(vals1)); System.out.println(vals2 == sortWithoutBreak(vals2)); System.out.println(vals1 != sortWithBreak(vals1)); System.out.println(vals2 == sortWithBreak(vals2)); System.out.println(vals1 != sortHeinz(vals1)); System.out.println(vals2 == sortHeinz(vals2)); } }
This is the first time in a long time that I have seen something in the core of the Java Programming Language that was completely new to me.
Kind regards
Heinz
We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)
We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.