|
JavaFAQ Home » Java Lectures by Anatoliy Malyarenko

Characters and strings
Abstract
Contents of the lecture.
- Characters.
- Why two string classes?
- Creating strings and string buffers.
- Accessor methods.
- Modifying string buffers.
- Converting objects to strings.
- Converting strings to numbers.
- Strings and the Java compiler.
Introduction
The Java platform contains three classes that you can use when working with character
data:
- Character -- A class whose instances can hold a single character value. This class also defines handy methods that can manipulate or inspect single-character data.
- String -- A class for working with immutable (unchanging) data composed of multiple characters.
- StringBuffer -- A class for storing and manipulating mutable data composed of multiple characters.
Characters
An object of Character type contains a single character value. You use a Character
object instead of a primitive char variable when an object is required -- for example, when
passing a character value into a method that changes the value or when placing a character
value into a data structure, such as a vector, that requires objects. The following sample
program, CharacterDemo, creates a few character objects and displays some information
about them:
| Code: |
public class CharacterDemo {
public static void main(String args[]) {
Character a = new Character(’a’);
Character a2 = new Character(’a’);
Character b = new Character(’b’);
int difference = a.compareTo(b);
if (difference == 0) {
System.out.println("a is equal to b.");
} else if (difference < 0) {
System.out.println("a is less than b.");
} else if (difference > 0) {
System.out.println("a is greater than b.");
}
System.out.println("a is "
+ ((a.equals(a2)) ? "equal" : "not equal")
+ " to a2.");
System.out.println("The character " + a.toString()
+ " is " + (Character.isUpperCase(a.charValue()) ?
"upper" : "lower") + "case.");
}
}
|
The following is the output from this program:
a is less than b.
a is equal to a2.
The character a is lowercase.
The CharacterDemo program calls the following constructors and methods provided by
the Character class:
Character(char)
The Character class's only constructor, which creates a Character object containing
the value provided by the argument. Once a Character object has been created, the value it
contains cannot be changed.
compareTo(Character)
An instance method that compares the values held by two character objects: the object
on which the method is called (a in the example) and the argument to the method (b in the
example). This method returns an integer indicating whether the value in the current object
is greater than, equal to, or less than the value held by the argument. A letter is greater than
another letter if its numeric value is greater.
equals(Object)
An instance method that compares the value held by the current object with the value
held by another. This method returns true if the values held by both objects are equal.
toString()
An instance method that converts the object to a string. The resulting string is one
character in length and contains the value held by the character object.
charValue()
An instance method that returns the value held by the character object as a primitive
char value.
isUpperCase(char)
A class method that determines whether a primitive char value is uppercase. This is
one of many Character class methods that inspect or manipulate character data.
Why two string classes?
The Java platform provides two classes, String and StringBuffer, that store and
manipulate strings -- character data consisting of more than one character. The String
class provides for strings whose value will not change. For example, if you write a method that
requires string data and the method is not going to modify the string in any way, pass a String
object into the method. The StringBuffer class provides for strings that will be modified; you
use string buffers when you know that the value of the character data will change. You typically
use string buffers for constructing character data dynamically: for example, when reading text
data from a file. Because strings are constants, they are more efficient to use than are string
buffers and can be shared. So it's important to use strings when you can.
Following is a sample program called StringsDemo, which reverses the characters of a
string. This program uses both a string and a string buffer.
| Code: |
public class StringsDemo {
public static void main(String[] args) {
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
StringBuffer dest = new StringBuffer(len);
for (int i = (len - 1); i >= 0; i--) {
dest.append(palindrome.charAt(i));
}
System.out.println(dest.toString());
}
}
|
The output from this program is:
doT saw I was toD
Creating strings and string buffers
A string is often created from a string literal -- a series of characters enclosed in double
quotes. For example, when it encounters the following string literal, the Java platform creates
a String object whose value is Gobbledygook.
"Gobbledygook"
The StringsDemo program uses this technique to create the string referred to by the
palindrome variable:
| Code: |
String palindrome = "Dot saw I was Tod";
|
You can also create String objects as you would any other Java object: using the new
keyword and a constructor. The String class provides several constructors that allow you to
provide the initial value of the string, using different sources, such as an array of characters,
an array of bytes, or a string buffer.
Here's an example of creating a string from a character array:
| Code: |
char[] helloArray = { ’h’, ’e’, ’l’, ’l’, ’o’ };
String helloString = new String(helloArray);
System.out.println(helloString);
|
The last line of this code snippet displays: hello.
You must always use new to create a string buffer. The StringsDemo program creates
the string buffer referred to by dest, using the constructor that sets the buffer's capacity:
| Code: |
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
StringBuffer dest = new StringBuffer(len);
|
This code creates the string buffer with an initial capacity equal to the length of the
string referred to by the name palindrome. This ensures only one memory allocation for dest
because it's just big enough to contain the characters that will be copied to it.
By initialising the
string buffer's capacity to a reasonable first guess, you minimise the number of times memory
must be allocated for it. This makes your code more efficient because memory allocation is a
relatively expensive operation.
Getting the length of a string or a string buffer
Methods used to obtain information about an object are known as accessor methods.
One accessor method that you can use with both strings and string buffers is the length
method, which returns the number of characters contained in the string or the string buffer.
After the following two lines of code have been executed, len equals 17:
| Code: |
String palindrome = "Dot saw I was Tod";
int len = palindrome.length();
|
In addition to length, the StringBuffer class has a method called capacity, which
returns the amount of space allocated for the string buffer rather than the amount of space
used. For example, the capacity of the string buffer referred to by dest in the StringsDemo
program never changes, although its length increases by 1 for each iteration of the loop. The
following figure shows the capacity and the length of dest after nine characters have been
appended to it.

A string buffer's length is the number of characters it contains; a string buffer's capacity
is the number of character spaces that have been allocated. The String class doesn't have a
capacity method, because a string cannot change.
Getting characters by index from a string or string buffer
You can get the character at a particular index within a string or a string buffer by using
the charAt accessor. The index of the first character is 0; the index of the last is length()-1.
For example, the following code gets the character at index 9 in a string:
| Code: |
String anotherPalindrome = "Niagara. O roar again!";
char aChar = anotherPalindrome.charAt(9);
|
Indices begin at 0, so the character at index 9 is 'O', as illustrated in the following figure:

Use the charAt method to get a character at a particular index. The figure also shows
that to compute the index of the last character of a string, you have to subtract 1 from the value
returned by the length method.
If you want to get more than one character from a string or a string buffer, you can use
the substring method. The substring method has two versions, as shown in the following
table:
| Method |
Description |
String substring(int)
String substring(int,int) |
Returns a new string that is a substring of this string or string buffer. The first integer argument specifies the index of the first
character.
The second integer argument is the index of the last character -1. The length of the substring is therefore the first int
minus the second int. If the second integer is not present, the substring extends to the end of the original string.
|
The following code gets from the Niagara palindrome the substring that extends from
index 11 to index 15, which is the word "roar":
| Code: |
String anotherPalindrome = "Niagara. O roar again!";
String roar = anotherPalindrome.substring(11, 15);
|
Use the substring method to get part of a string or string buffer. Remember that indices
begin at 0.

More accessor methods for the String class
The String class provides two accessors that return the position within the string of
a specific character or string: indexOf and lastIndexOf. The indexOf method searches
forward from the beginning of the string, and lastIndexOf searches backward from the end
of the string.
The indexOf and lastIndexOf methods are frequently used with substring, which
returns a substring of the string. The following class illustrates the use of lastIndexOf and
substring to isolate different parts of a filename.
Note: The methods in the following Filename class don't do any error checking
and assume that their argument contains a full directory path and a filename with
an extension. If these methods were production code they would verify that their
arguments were properly constructed.
| Code: |
// This class assumes that the string used to initialise
// fullPath has a directory path, filename, and extension.
// The methods won’t work if it doesn’t.
public class Filename {
private String fullPath;
private char pathSeparator, extensionSeparator;
public Filename(String str, char sep, char ext) {
fullPath = str;
pathSeparator = sep;
extensionSeparator = ext;
}
public String extension() {
int dot = fullPath.lastIndexOf(extensionSeparator);
return fullPath.substring(dot + 1);
}
public String filename() {
int dot = fullPath.lastIndexOf(extensionSeparator);
int sep = fullPath.lastIndexOf(pathSeparator);
return fullPath.substring(sep + 1, dot);
}
public String path() {
int sep = fullPath.lastIndexOf(pathSeparator);
return fullPath.substring(0, sep);
}
}
|
Here’s a small program that constructs a Filename object and calls all of its methods:
| Code: |
public class FilenameDemo {
public static void main(String[] args) {
Filename myHomePage = new Filename
("/home/mem/index.html",’/’, ’.’);
System.out.println("Extension = " + myHomePage.extension());
System.out.println("Filename = " + myHomePage.filename());
System.out.println("Path = " + myHomePage.path());
}
}
|
And here's the output from the program:
Extension = html
Filename = index
Path = /home/mem
The extension method uses lastIndexOf to locate the last occurrence of the period
(.)
in the filename.
Then substring uses the return value of lastIndexOf to extract
the filename extension -- that is, the substring from the period to the end of the string.
This code assumes that the filename actually has a period in it; if the filename does
not have a period , then lastIndexOf returns -1, and the substring method throws a
StringIndexOutOfBoundsException.
Also, notice that extension uses dot + 1 as the argument to substring. If the period
character is the last character of the string, then dot + 1 is equal to the length of the string
which is one larger than the largest index into the string (because indices start at 0). However,
substring accepts an index equal to but not greater than the length of the string and interprets
it to mean "the end of the string."
Try this: Inspect the other methods in the Filename class and notice how the lastIndexOf and substring methods work together to isolate different parts of a filename.
While the methods in the example above use only one version of the lastIndexOf
method, the String class actually supports four different versions of both the indexOf and
lastIndexOf methods. The four versions work as follows:
indexOf(int character)
lastIndexOf(int character)
Return the index of the first (last) occurrence of the specified character.
indexOf(int character, int from )
lastIndexOf(int character, int from )
Return the index of the first (last) occurrence of the specified character, searching
forward (backward) from the specified index.
indexOf(String string)
lastIndexOf(String string)
Return the index of the first (last) occurrence of the specified String.
indexOf(String string, int from )
lastIndexOf(String string, int from )
Return the index of the first (last) occurrence of the specified String, searching forward
(backward) from the specified index.
More accessor methods for the StringBuffer class
Like String, StringBuffer provides length and charAt accessor methods.
In
addition to these two accessors, StringBuffer also has a method called capacity. The
capacity method differs from length in that it returns the amount of space currently allocated
for the StringBuffer, rather than the amount of space used. For example, the capacity of
the StringBuffer in the reverseIt method shown here never changes, while the length of
the StringBuffer increases by one for each iteration of the loop:
| Code: |
public class ReverseString {
public static String reverseIt(String source) {
int i, len = source.length();
StringBuffer dest = new StringBuffer(len);
for (i = (len - 1); i >= 0; i--)
dest.append(source.charAt(i));
return dest.toString();
}
}
|
Modifying string buffers
The reverseIt method uses StringBuffer's append method to add a character to the
end of the destination string: dest.
| Code: |
public class ReverseString {
public static String reverseIt(String source) {
int i, len = source.length();
StringBuffer dest = new StringBuffer(len);
for (i = (len - 1); i >= 0; i--)
dest.append(source.charAt(i));
return dest.toString();
}
}
|
If the appended character causes the size of the StringBuffer to grow beyond its
current capacity, the StringBuffer allocates more memory. Because memory allocation
is a relatively expensive operation, you can make your code more efficient by initialising
a StringBuffer's capacity to a reasonable first guess, thereby minimising the number of
times memory must be allocated for it. For example, the reverseIt method constructs the
StringBuffer with an initial capacity equal to the length of the source string, ensuring only
one memory allocation for dest.
The version of the append method used in reverseIt is only one of the StringBuffer
methods that appends data to the end of a StringBuffer. There are several append methods
that append data of various types, such as float, int, boolean, and even Object, to the end
of the StringBuffer. The data is converted to a string before the append operation takes
place.
Inserting and setting characters
At times, you may want to insert data into the middle of a StringBuffer. You do this
with one of StringBufffer's insert methods. This example illustrates how you would insert
a string into a StringBuffer:
| Code: |
StringBuffer sb = new StringBuffer("Drink Java!");
sb.insert(6, "Hot ");
System.out.println(sb.toString()); |
This code snippet prints:
Drink Hot Java!
With StringBuffer's many insert methods, you specify the index before which you
want the data inserted. In the example, "Hot " needed to be inserted before the 'J' in "Java".
Indices begin at 0, so the index for 'J' is 6. To insert data at the beginning of a StringBuffer,
use an index of 0. To add data at the end of a StringBuffer, use an index equal to the current
length of the StringBuffer or use append.
Another useful StringBuffer modifier is setCharAt, which replaces the character at
a specific location in the StringBuffer with the character specified in the argument list.
setCharAt is useful when you want to reuse a StringBuffer.
The toString method
It's often convenient or necessary to convert an object to a String because you need
to pass it to a method that accepts only String values.
The reverseIt method uses
StringBuffer's toString method to convert the StringBuffer to a String object before
returning the String.
| Code: |
public class ReverseString {
public static String reverseIt(String source) {
int i, len = source.length();
StringBuffer dest = new StringBuffer(len);
for (i = (len - 1); i >= 0; i--)
dest.append(source.charAt(i));
return dest.toString();
}
}
|
All classes inherit toString from the Object class and many classes in the java.lang
package override this method to provide an implementation that is meaningful to that class.
For example, the "type wrapper" classes -- Character, Integer, Boolean, and the others --
all override toString to provide a String representation of the object.
The valueOf method
As a convenience, the String class provides the class method valueOf. You can use
valueOf to convert variables of different types to Strings. For example, to print the value of
pi:
| Code: |
System.out.println(String.valueOf(Math.PI));
|
Converting strings to numbers
The String class itself does not provide any methods for converting a String to a
floating point, integer, or other numerical type. However, four of the "type wrapper" classes
(Integer, Double, Float, and Long) provide a class method named valueOf that converts
a String to an object of that type. Here's a small, contrived example of the Float class's
valueOf:
| Code: |
String piStr = "3.14159";
Float pi = Float.valueOf(piStr);
|
Literal strings
In Java, you specify literal strings between double quotes:
"Hello World!"
You can use literal strings anywhere you would use a String object. For example,
System.out.println accepts a String argument, so you could use a literal string in place
of a String there.
| Code: |
System.out.println("Might I add that you look lovely today.");
|
You can also use String methods directly from a literal string.
| Code: |
int len = "Goodbye Cruel World".length();
|
Because the compiler automatically creates a new String object for every literal string
it encounters, you can use a literal string to initialise a String.
| Code: |
String s = "Hola Mundo";
|
The above construct is equivalent to, but more efficient than, this one, which ends up
creating two Strings instead of one:
| Code: |
String s = new String("Hola Mundo");
|
The compiler creates the first string when it encounters the literal string "Hola Mundo!",
and the second one when it encounters new String.
Concatenation and the + operator
In the Java programming language, you can use + to concatenate Strings together:
| Code: |
String cat = "cat";
System.out.println("con" + cat + "enation");
|
This is a little deceptive because, as you know, Strings can't be changed. However,
behind the scenes the compiler uses StringBuffers to implement concatenation. The above
example compiles to:
| Code: |
<p> String cat = "cat";<br />
System.out.println(new
StringBuffer().append("con").
append(cat).append("enation").toString());
|
You can also use the + operator to append values to a String that are not themselves
Strings:
| Code: |
System.out.println("Java's Number " + 1);
|
The compiler converts the non-String value (the integer 1 in the example) to a String
object before performing the concatenation operation.
Summary of the String class
| Method or Constructor |
Purpose |
String()
String (byte[])
String (byte[], int, int)
String (byte[], int, int, String)
String (byte[], String)
String (char[])
String (char[], int, int)
String (String)
String (StringBuffer)
|
Creates a new string object.
For all
constructors that take arguments, the first
argument provides the value for the string. |
Printer Friendly Page
Send to a Friend
Search here again if you need more info!
|