[Java] Using == to compare Strings

This is a very common mistake, probably because of the misinformation about what the == operator really does. This mistake is about using == instead of equals() to compare String contents.

When should I use them?

  • == is used to compare values of primitive types (int, float, boolean, …), but it’s also used to compare object references (memory addresses).
  • equals() method should be used to compare contents (information) of Objects. Note that the initial implementation returns the same as obj1 == obj2, in other words, it compares references. But this method is generally override by programmers to compare object contents, and this is the case of String (remember that String is an Object, not a primitive).

In conclusion, to compare String contents we must use equals(). But it is worth noting that Strings content can be also compared with == operator in some situations. Let’s see some examples:

// These two have the same value
new String("test").equals("test") --> true 

// ... but they are not the same object
new String("test") == "test" --> false 

// ... neither are these
new String("test") == new String("test") --> false 

// ... but these are because literals are interned by 
// the compiler and thus refer to the same object
"test" == "test" --> true 

// concatenation of string literals happens at compile time,
// also resulting in the same object
"test" == "te" + "st" --> true

// but .substring() is invoked at runtime, generating distinct objects
"test" == "!test".substring(1) --> false

Why does line 12 and 16 evaluate to true? Because of String interning. What happens in these cases is that the compiler interns String literals in memory at compile time (this is done to save memory). In line 12 and 16 the String literals that are beign compared are in the same memory location, so the comparison with == operator returns true.
However, this is not recommended unless you want better performance (comparing memory addresses is a lot “cheaper” than a loop) and you are sure that the Strings being compared are interned literals.

[Java] Using nextInt() before nextLine()

Well, this mistake (that has an honorable place in the list of Common Mistakes in Java1) is one of the most common mistakes I’ve seen from Java beginners. It’s about using scanner.nextInt() before scanner.nextLine() (from Scanner object). What happens is that when these methods are used in that order, it looks like the nextLine() is being skipped.

Why does this happens?

What happens is that nextInt() doesn’t read the new-line character "\n" (inputted by user after pressing Enter key, it’s also called line separator), while nextLine() does. Let’s give an example, so it’s easier to visualize:

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);

    System.out.print("Number: ");
    int number = scanner.nextInt();

    System.out.print("String1: ");
    String string1 = scanner.nextLine();

    System.out.print("String2: ");
    String string2 = scanner.nextLine();

    System.out.println(number + ", " + string1 + ", " + string2);
}

Output:

Number: 10
String1: String2: christprogramming
10, , christprogramming

Explanation:
- We are using Scanner to read input. System.out.println() are just for debug purposes.
- At line 5, nextInt() is called in order to read an integer. This method consumes the integer, but not the new-line character.
- At line 8, we call nextLine(), but as seen in output, it looks like if it were skipped. Why? Because it consumes the new-line character that was not consumed by nextInt().
- At line 11, we again call nextLine() but this time, works as expected because there are not any remaining characters to read.

Notes:
- This is a logic error, since every method work as intended, but they are not used correctly.
- nextInt() reads a number, but doesn’t consume line separator. nextString(). While nextLine() reads the String and consumes the new-line character. According to Java Docs:
… This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line.
- In fact, this mistake happens with other methods too, like nextDouble(), nextLong(), nextFloat() that don’t read new-line character.

So, how to solve this?

There are two simple solutions:

  1. Add a nextLine() extra, between the nextInt() and nextLine(). This extra nextLine() will consume the new-line character, so the following nextLine() will work fine.
    ...
    int number = scanner.nextInt();
    scanner.nextLine(); // Consumes "\n"
    String string1 = scanner.nextLine();
    ...
    

  2. The second way is using nextLine() instead of nextInt() to read the number. Remember that nextLine() will consume "\n", so there won’t be problems. But since nextLine() returns a String, we will have to convert this String to a integer. We can use Integer.parseInt(...) (if you want Double, use Double.parseDouble(...) and similar for other primitive types) in order to do this:

    ...
    int number = Integer.parseInt(scanner.nextLine()); // For example: Integer.parseInt("123")
    String string1 = scanner.nextLine();
    ...
    

Using the second way, we can receive an Exception from the Integer.parseInt(...) method if the String passed as argument cannot be converted to a number (in this case an int). To handle this Exception, you will have to use a try-catch block.


  1. Coming soon… 

About me and this blog

So here is where the story begins. My first post. My name is Christian Tapia Sabogal, and I’m studying System’s Engineering. I’m a StackOverflow fan and really enjoy answering people’s questions, at the time I learn and research about topics I don’t know. ¬†As you could realize I’m not an English native speaker, so forgive the mistakes I make please. I’m making this blog in order to keep track of my progress as a programmer. I will try to post articles about interesting topics, generally about Java and Python (for the time being). See you in later articles!