Java String
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.
For example:
// 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 Compare
String class provides equals(...) and equalsIgnoreCase(...) methods to compare two strings:
- boolean equals(Object anObject): Compares this string to the specified object.
- boolean equalsIgnoreCase(String anotherString): Compares this String to another String, ignoring case considerations.
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 Concatenation
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
String Length
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
Substring methods will returns part of the string based on specified indexes.
- String substring(int beginIndex): Returns a string that is a substring of this string.
- String substring(int beginIndex, int endIndex): Returns a string that is a substring of this string.
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
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
String Methods
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