Click here to Skip to main content
15,860,861 members
Articles / Programming Languages / Java / Java SE

Java Mini Puzzler

Rate me:
Please Sign up or sign in to vote.
4.86/5 (29 votes)
1 May 2009CPOL9 min read 39.3K   16   13
Three examples of Java code that doesn't do what you'd expect

Introduction 

By and large, Java is a wonderful language. There are, however, some quirks in its behavior that can cause grief to the unwary programmer. Sometimes things don’t work the way you expect them to, and that’s what we are going to take a look at here.

Some of the following code is adapted from projects I’ve worked on and some is code I specifically wrote to help people studying for the Sun Certified Programmer Exam for Java 6 to see how well they understood a topic.

Let’s start with a relatively easy one and save the tougher ones for later.

It’s a Long Way

While working on a project, I had to convert a String variable to Long. Knowing the Long class (like the other wrapper classes for primitives) has static methods that do just the thing, I started typing in my IDE and found that there are four methods that might do the job. Here’s a list of the candidates:


  • Long.decode(String nm)
  • Long.getLong(String nm)
  • Long.parseLong(String s)
  • Long.valueOf(String s)

Given that each of these takes a String and returns a Long, what does the following code return? (Note: The longValue() method returns the value of the Long object as a primitive long.)

Java
public long getValueFromString() {
  String aLong = "23";
  Long retrievedLong = Long.getLong( aLong );
  return retrievedLong.longValue();
}

Here’s the list of possible answers:

  1. 23
  2. 0 (zero)
  3. It depends

Before you continue reading, what do you think the right answer is?

Finished so soon? Alright then, let’s take a look at the possible answers and see how you did.
Now it seems reasonable that Long’s getLong() method should return the value of the String as a Long, so answer ‘A’ looks pretty good. Then again, if it were that easy why would I bother including this? Answer ‘B’ doesn’t seem very reasonable - unless getLong() isn’t really converting the value of the String. So that leaves answer ‘C’ as the primary suspect. It’s not obvious and seems rather vague. It’s just the sort of answer you might expect from a puzzle - which could be reason enough to go back to answer ‘A’. <grin>

OK, enough thinking. Time to give you the answer so we can keep going - the correct answer is ‘C’. - it depends.

It turns out that Long’s getLong() method doesn’t try to convert the value of the passed in String directly. Instead, it takes the value and looks for a System property with the same name. If it finds one, it retrieves the associated value and converts that to a Long. Which means that what the getLongValue() method returns depends on the value of the System property “23″.

So what happens if there is no System property named “23″? In that case, getLong() will return a null and the getValueFromString() method will throw a NullPointerException when it tries to call the getValue() method because retrievedLong is null. Ouch!

I found this the hard way. I needed to convert a String and picked a likely method from the list provided by my IDE. I was greatly surprised when my unit test failed, so I looked up the JavaDoc on it and realized my mistake.

There are a two morals to this story:


  1. Unit tests are your friends.

  2. Use the JavaDoc, and make sure you write some for the people using your code.

Ready for the next puzzle? It’s called...

Zapped by Static

I was modifying some legacy code (defined as any code with no unit tests) and found something unexpected when I tried to use it. The original code was rather complicated (possibly because there were no tests), but this simplified version has the same odd behavior.

Java
public class Greeting {
    static {
        initName();
    }

    static String name = "Sue";

    static Test instance = new Test();

    public static String getName() {
        return name;
    }

    private static void initName() {
        name = "Bond, James Bond";
    }

    public static void main(String[] args) {
        System.out.println("My name is " + Test.getName() + ".");
    }
}

Before we get to the question, let’s take a look at the Greeting class. There’s one static variable, three static methods and one static initializer. (That’s the block of code that starts with “static” and calls the initName() method.) Other than the static initializer, it looks like a pretty simple class that's easy to understand, doesn’t it?

In case you’re not familiar with static initializers, let me paraphrase a bit of Sun’s Java Tutorial:

"A static initialization block is a normal block of code enclosed in braces, { }, and preceded by the static keyword. They can appear anywhere in the class body, and the Java runtime guarantees they are called in the order in which they appear in the source code."

That sounds kind of cool, but what’s the point? Why would you use one? Well, a static initializer executes when the class is loaded into memory and it is normally used to do some kind of one-time processing for the class. In this case, the initializer calls the initName() method when the Greeting class is loaded into memory -- before it’s main() method executes.

So, getting back to the question at hand (What does the above code do when you run the class?), here are the possible answers:


  1. It prints “My name is Sue.”
  2. It prints “My name is Bond, James Bond.”

  3. Nothing, because it doesn’t compile.
  4. None of the above.

I recommend taking some time to figure out your own answer before reading any further. You’ll get more out of this if you do. Don’t worry, I don’t mind the wait.

Ready to look at the answers? Good.

First things first. Answer C, "Nothing, because it doesn't compile" is not correct. I just included it so I can tell you that I don’t like that kind of answer on a puzzle, or Java certification exam for that matter. While it may have been a useful skill years ago, when our only tools were stone knives and bearskins, we’ve had better tools for so long now that it seems unreasonable to ask a question where “it won’t compile” is the right answer. OK, enough ranting - back to the puzzle.

What about answer B? Well, having read this far you should know the whole point of this is to show you code that looks simple but behaves strangely. So you probably didn’t pick answer B , and you would be right in doing so. The code does not print  “My name is Bond, James Bond.”
What about the ever popular “None of the above.” Sorry, not this time. Answer D is not correct either.

By the process of elimination, the correct answer must be A. But it doesn’t make sense for it to print “My name is Sue.” - does it? Don't trust me on this, copy the code into a file and run it yourself, then come back for the explanation.

To say I was surprised when I saw this for the first time would be an understatement. I didn’t believe the results; it didn’t make any sense to me so I stepped through it in the debugger. If you do the same, you can see that the initName() method does get called before the main() method, and that when initName() finishes, the value of “name” is “Bond, James Bond” - just as we expected.

So what’s going on? How does “name” get set to “Sue”? If you continue stepping through the code, you’ll find out. Notice that right after the static initializer, we declare and initialize the “name” variable. Which seems kind of odd because the initName() method already set “name” to a value - so it must already exist, right?

Sort of. The compiler sets aside space for the variable and includes code to initialize it. But, because “name” is a static variable, its initialization happens when the class is loaded into memory instead of when the class constructor is called. It also appears that, like a static initializer, static variable initialization happens “in the order in which it appears in the source code.” So after the static initializer is called, the code that declares and initializes “name” to “Sue” executes and overwrites the value we expected to see.

And that is why answer A is correct. Believe it, or not. 

Same Difference


For the final puzzle, let’s take a look at something I found while preparing to lead a study group focusing on the Sun Certified Programmer Exam for Java 6.

There’s not much code, but this puzzle involves autoboxing and unboxing combined with the prefix increment operator (just to make it interesting) as we compare two variables.

Java
public class Bitwise {

    public static void main(String[] args) {

        Integer a = 5; Integer b = 5;

        System.out.println(++a == ++b);


        Integer c = 12345; Integer d = 12345;

        System.out.println(++c == ++d);

    }

}

What does this code do when you run it?

  1. It prints two lines, “true” followed by “true”.
  2. It prints two lines, “false” followed by “false”.
  3. It prints two lines, “true” followed by “false”.
  4. It prints two lines, “false” followed by “true”.

OK, let’s work through this. All the variables are of type Integer, so when we compare them using ‘==’, we’re really comparing the reference values, not their primitive values. So even though ‘a’ and ‘b’ have the same primitive values (as do ‘c’ and ‘d’), they’re each referring to a new Integer instance - thanks to autoboxing. That means the references should be different and the ‘==’ comparison should resolve to ‘false’, which means the answer should be B.

Obviously that would be too easy, so let’s look at the other possibilities.

While it doesn’t make sense that two newly created Integer instances would have the same reference, answer A is consistent and that seems a little more plausible than answers C and D. While it may make sense, the truth is that answer A is not correct and neither is answer B.

What? Am I telling you that sometimes you can create two new Integer instances and they’ll point to the same object in memory? Yes, that’s exactly what I’m saying.

You might feel better running the code and looking at the results before you continue reading, just so you know I’m not making this up.

What’s happening is that in order to save memory (according to Kathy Sierra and Bert Bates - authors of the SCJP 6 Study Guide), Java reuses wrapper objects when the primitive value fits in a byte. So if two Booleans or Bytes have the same primitive value, their reference is the same too. The same thing is true for Characters whose value is between \u000 and \u007F, and Shorts and Integers whose value is between -128 and 127.

So when Integers ‘a’ and ‘b’ were set to 5, they both referred to the same Integer instance and the ‘==’ comparison was true.  But since 12345 is outside the magic range, variables ‘c’ and ‘d’ got their own Integer instances so the ‘==’ comparison was false. Strange, but true. 

Summary

Java is a wonderful language, but there are instances of unusual behavior that can really mess with your mind. Don’t let that stop you. Write it down and share it so we can all benefit from your discovery. 

If you’ve got any feedback on this, please post a comment.

History

  • 1st May, 2009: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect LexisNexis
United States United States
Burk Hufnagel has been creating positive User Experiences since 1978 and is a Lead Software Architect at LexisNexis. Burk spends most of his life designing and crafting software, and has made a habit of creating practical solutions for difficult problems.
Recent achievements include co-authoring "97 Things Every Software Architect Should Know", speaking at JavaOne 2008, and being a speaker and mentor at the 2009 IT Architect Regional Conference in Atlanta, GA.

Comments and Discussions

 
GeneralMy vote of 5 Pin
AprNgp22-Dec-11 18:30
AprNgp22-Dec-11 18:30 
GeneralImportant stuff Pin
CurtainDog7-May-09 19:30
CurtainDog7-May-09 19:30 
AnswerRe: Important stuff Pin
BurkHufnagel8-May-09 2:03
BurkHufnagel8-May-09 2:03 
GeneralRe: Important stuff Pin
CurtainDog8-May-09 3:21
CurtainDog8-May-09 3:21 
AnswerRe: Important stuff Pin
BurkHufnagel8-May-09 17:43
BurkHufnagel8-May-09 17:43 
GeneralGood Puzzles Pin
User 25747774-May-09 19:46
professionalUser 25747774-May-09 19:46 
AnswerRe: Good Puzzles Pin
BurkHufnagel6-May-09 5:30
BurkHufnagel6-May-09 5:30 
GeneralTest.getName() code not shown in Puzzle 2 Pin
gcollis4-May-09 17:40
gcollis4-May-09 17:40 
GeneralRe: Test.getName() code not shown in Puzzle 2 Pin
BurkHufnagel5-May-09 9:21
BurkHufnagel5-May-09 9:21 
Good catch!

The class was originally named Test and I renamed it to make more sense in the article. I'll get it changed as quickly as I can. In the mean time, just replace "Test" with "Greeting" and it should run properly.

Thanks for the debug help,
Burk
GeneralExample #3 (Same Difference) is/was troubling Pin
BurkHufnagel2-May-09 14:34
BurkHufnagel2-May-09 14:34 
GeneralRe: Example #3 (Same Difference) is/was troubling Pin
adatapost2-May-09 16:12
adatapost2-May-09 16:12 
GeneralRe: Example #3 (Same Difference) is/was troubling Pin
BurkHufnagel2-May-09 17:20
BurkHufnagel2-May-09 17:20 
GeneralRe: Example #3 (Same Difference) is/was troubling Pin
AprNgp22-Dec-11 18:27
AprNgp22-Dec-11 18:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.