String is one of the most widely used class in Java. Part of java.lang package, the String class represents character strings. Strings receive special treatment in Java, because they are used frequently in a program
- String is associated with string literal in the form of double-quoted texts such as "Hello, Java!". You can assign a string literal directly into a String variable, instead of calling the constructor to create a String instance.
- The '+' operator, which performs addition on primitives (such as int and double), is overloaded to operate on String objects. '+' performs concatenation for two String operands.
- String is immutable. That is, its content cannot be modified once it is created. For example, the method replace(...), substring(...), toUpperCase(), etc constructs and returns a new String instead of modifying the its existing content.
Creating a String
There are two data types in Java: primitive types and reference types. Primitive types contains only value and stored in the call stack. This means primitive types require less storage spaces (and size is fixed) and are cheaper to manipulate. On the other hand, objects (instance of a class) are stored in the program heap, they reference a memory location, which stores the data. This is require complex memory management and more storage spaces. For performance reason, Java's String is designed to be in between a primitive and a class.
A String can be constructed by either:
- directly assigning a string literal to a String reference (just like a primitive)
- via the "new" operator and constructor, similar to any other classes.
// Implicit literal String slit = "Hello, Java"; // Explicit new String snew = new String("Dariawan Blog");
In the first statement, slit is declared as a String reference and initialized with a string literal "Hello, Java". In the second statement, snew is declared as a String reference and initialized via the new operator and constructor to contain "Dariawan Blog". However, creating String using "new" operator is not recommended, why?
String Literal vs. String New
String Constant Pool
Java has provided a special mechanism for keeping the String literals, called string constant pool. If two string literals have the same contents, they will share the same storage inside the string pool, to conserve storage for frequently-used strings. On the other hand, String objects created via the new operator and constructor are kept in the heap. Just like any other object, each String object in the heap has its own storage. There is no sharing of storage in heap even if two String objects have the same contents.
you can use the method equals() of the String class to compare the contents of two Strings. You can use the relational equality operator '==' to compare the references (or pointers) of two objects.
String s1 = new String("java"); // new object String s2 = new String("java"); // new object String s3 = "java"; // literal String s4 = "java"; // literal System.out.println(s1 == s2); // false, different pointers System.out.println(s1.equals(s2)); // true, same contents System.out.println(s1.equals(s3)); // true, same contents System.out.println(s1 == s4); // false, different pointers System.out.println(s1.equals(s4)); // true, same contents System.out.println(s3 == s4); // true, s3 and s4 share storage in constant pool System.out.println(s3.equals(s4)); // true, same contents
for equals(...) and '==' let's talk about String comparison...
String class provides equals(...) and equalsIgnoreCase(...) methods to compare two strings:
String s1 = "xyz"; String s2 = "xyz"; String s3 = "XYZ"; System.out.println(s1.equals(s2)); // true System.out.println(s2.equals(s3)); // false System.out.println(s1.equalsIgnoreCase(s3)); // true System.out.println(s1.equals(s3.toLowerCase())); // true
And we know that '==' operator will refer to pointers of two objects:
String s1 = "xyz"; String s2 = "xyz"; String s3 = "XYZ"; System.out.println(s1 == s2); // true System.out.println(s2 == s3); // false System.out.println(s1 == s3.toLowerCase()); // false
As you can see, s1 == s3.toLowerCase() resulting false, since although s3 already lowered-case, the '==' will refer to the pointer of s3 which is is not the same pointer as s1.
String class implements Comparable interface, which provides compareTo() method. Besides compareTo() String also have compareToIgnoreCase() method:
- int compareTo(String anotherString): Compares two strings lexicographically.
- int compareToIgnoreCase(String str): Compares two strings lexicographically, ignoring case differences.
The comparison is based on the Unicode value of each character in the strings. The character sequence represented by this String object is compared lexicographically to the character sequence represented by the argument string. If strings are equal then it returns zero or else it returns either greater or less than zero.
String s1 = "xyz"; String s2 = "xyz"; String s3 = "XYZ"; System.out.println(s1.compareTo(s2)); // 0 System.out.println(s2.compareTo(s3)); // 32 -> greater than 0 System.out.println(s3.compareTo(s1)); // -32 -> less than 0 System.out.println(s1.compareToIgnoreCase(s3)); // 0
String can be concatenated by using “+” operator or by using concat() method.
- String concat(String str): Concatenates the specified string to the end of this string.
String s1 = "ping"; String s2 = "pong"; // + operator System.out.println(s1 + s2); // pingpong // concat method System.out.println(s1.concat(s2)); // pingpong
Use length method to get the number of characters in a String.
- int length(): Returns the length of this string.
String s = "Good morning!"; System.out.println(s.length()); // length is 13
Substring methods will returns part of the string based on specified indexes.
String s = "Greetings, developer!"; s = s.substring(11); System.out.println(s); // developer! s = s.substring(3, 7); // from "developer!" System.out.println(s); // elop
String index is started from 0, and last index is length - 0. We can use method charAt(...) to get the char at respective index.
String s = "Dariawan"; char c1 = s.charAt(0); System.out.println(c1 == 'D'); // true char c2 = s.charAt(s.length()-1); System.out.println(c2 == 'n'); // true
methods indexOf(...) or lastIndexOf(...) of a String also utilize this index.
String s = "Dariawan"; System.out.println(s.indexOf("ria")); // r start from 2 System.out.println(s.indexOf('a', 2)); // 'a' after index 2 (r) is in 4 System.out.println(s.lastIndexOf('a')); // last index of 'a' is 6
Following example using various methods of String available in Java 8:
String s1 = "xyz"; String s2 = "XYZ"; // All are Java 8 methods: System.out.println(s1==s2); // compares reference address - false System.out.println(s1.equals(s2)); // compares the values - false System.out.println(s1.equalsIgnoreCase(s2)); // compares the values ignoring the case - true System.out.println(s1.length()); // calculates length - 3 System.out.println(s1.charAt(1)); // extract 2nd character - y System.out.println(s1.toUpperCase()); // returns string in ALL CAPS - XYZ System.out.println(s2.toLowerCase()); // returns string in ALL lowercase - xyz System.out.println(s1.replace("y", "Y")); // search and replace "y" with "Y" - xYz System.out.println(s1.trim()); // trims surrounding whitespace - xyz System.out.println(s1.contains("yz")); // check for the values "yz" - true System.out.println(s1.toCharArray()); // convert String to aray of characters - xyz System.out.println(s1.isEmpty()); // Check if String is empty - false System.out.println(s1.endsWith(".")); // Checks if string ends with "." - false