06. String & StringBuilder Classes

String ClassStrings in Java are NOT arrays of chars as in C. Even a string literal in double quotes (for example, "ABC") is a String object (object of the String class) in Java. The String class is a library class in the java.lang package. More information about the String class:

  • Contents of a String object are always immutable (cannot change characters or size)
  • Every String literal will be unique in memory for a program, i.e., every String literal that has the same characters in a program will refer to the same object, for example:

String str1 = "Hello";

String str2 = "Hello";

if( str1 == str2 ) // is true because they refer to same object, not because contents same

  • Creating String objects:
  • Enclose characters in double quotes, for example: String name="Mary";
  • Use the new operator, for example: String name = new String("Mary");
  • Use the new operator passing a char array, for example:

char [] chArray = {'M', 'a', 'r', 'y'};

String name = new String(chArray);

  • See Java documentation (Internet or book) for complete list & description of constructors
  • String concatenation using the '+' operator (at least one operand must be a String), for example:

String str = "Result = " + number;

    • If the other operand is not a String, it will be converted to a String.
    • If the other operand is a non-String object reference, its toString method will be called.
    • Some of the String methods: (see the online Java API for all of the methods)
    • public boolean equals( String str ) - returns true if the characters in this String and str are identical, otherwise returns false
    • public boolean equalsIgnoreCase(String str) - returns true if the characters in this String and str are identical ignoring their case (if uppercase or lowercase), otherwise returns false
    • public int compareTo(String str) - returns 0 (int) if the characters in this String and str are identical, positive number if the 1st corresponding char's Unicode in this that is different from the char's Unicode in str, has a greater code value, otherwise returns a negative number
    • public int length( ) - returns the # of characters this String
    • public char charAt( int pos) - returns the char in this String at position pos, where pos is an integer from 0 to the length-1.
    • public String substring(int startIndex, int endIndex) - returns a String object which has the characters of this String starting from startIndex to endIndex-1 (remember, index of String chars begin at 0)
    • public String substring(int startIndex) - same as above, except endIndex is end of the String
    • public int indexOf( char ch ) - returns the index of the first occurrence of ch in this String, -1 if not found
    • public int lastIndexOf( char ch) - returns the index of the last occurrence of ch in this String, -1 if not found

Examples of Calling String Methods

public class Main{
  public static void main( String [] args ){
     String str1="Hello There";
     String str2 = "Hello" + " There"; // same object that str1 refers to *
     int pos;  char ch;
     System.out.println(str1.length());
     System.out.println(str1.equals(str2));// compares chars
     System.out.println(str1==str2);// compares references
     str1 += " GoodBye";
     str2 += " GoodBye";
     System.out.println(str1.equals(str2));
     System.out.println(str1==str2);// compares references
     str1 = str2.substring(0, 5);
     pos = str2.lastIndexOf('G');
     str1 += str2.substring(pos);
     ch = str2.charAt(0);
     System.out.println(ch + str1);
  } // end main
} // end class Main

*Note that when str2 is first assigned in its declaration, it happens to refer to the same String object as str1 because they're assigned String literals that have the same characters. If they were assigned differently, as later in the code, then they are NOT the same String objects.

StringBuilder and StringBuffer Classes

Java also has in its java.lang package two mutable (changeable) string classes: StringBuilder and StringBuffer. The information about the classes below apply to both the StringBuilder and StringBuffer, but is described only in terms of StringBuilder:

  • StringBuilder chars may change, and its size may grow or shrink
  • Has a logical size (# of chars. being used) and a capacity or physical size (# of chars. allocated memory)
  • By default, the capacity is 16 characters larger than the logical size when instantiated
  • new StringBuilder("word")would have a logical size of 4 and a capacity of 20
  • new StringBuilder()would have a logical size of 0 and a capacity of 16
  • StringBuilder constructors:
  • StringBuilder() - creates an object with no characters, logical size of 0 and capacity of 16
  • StringBuilder(int length) - creates an object with no characters, logical size of 0 and capacity of length
  • StringBuilder( String str ) -creates an object with the characters in str, logical size = # chars in str and capacity of 16 more than logical size

Examples:

StringBuilder sb1 = new StringBuilder();

StringBuilder sb2 = new StringBuilder( 30 );

StringBuilder sb3 = new StringBuilder("UC Extension");

Some of the StringBuilder methods:

  • public int length( ) - returns the logical size (# of chars) in this StringBuilder object
  • public int capacity( ) - returns the capacity (physical size) of this StringBuilder object
  • public void setLength( int newLength ) - changes the logical size of this StringBuilder to newLength (used to truncate) (the StringBuffer version of this method is synchronized-- discussed later)
  • public char charAt( int index ) - returns the char in this StringBuilder object at the specified index (beginning index is 0) (the StringBuffer version of this method is synchronized-- discussed later)
  • public void setCharAt( int index,char ch ) - replaces the character in this StringBuilder object at the specified index with ch (the StringBuffer version of this method is synchronized-- discussed later)
  • append methods - append the argument (converted to chars):
    • public synchronized StringBuilderappend(ObjName o)
    • ObjName may be Object, String, char [], boolean, char, int, long, float, double
  • insert methods - similar to append methods, except they insert the argument (converted to chars) after offset:

StringBuilder insert( int offset, argument), where argument may be Object, String, char[], boolean, char, int, long, float, or double

  • public void getChars( int begin, int end, char [ ] dst, int dstBegin) - assigns chars in this StringBuilder object in positionsbegin to end-1 to the char arraydst starting at index dstBegin indst (the StringBuffer version of this method is synchronized-- discussed later)
  • public String toString( ) - returns the chars in this StringBuilder in a String object

Examples of Calling StringBuilder Methods

public class TryStringBuilder{
  public static void main( String [] args ){
     StringBuilder sb1= new StringBuilder("Hello");
     System.out.println(sb1); // calls sb1.toString()
     System.out.println("sb1 length: "+ sb1.length());
     System.out.println("sb1 capacity: "+ sb1.capacity());
     sb1.append("World");
     sb1.insert(5, 2012); // figure out where this inserts!
     System.out.println(sb1);
     System.out.println("sb1 length: "+ sb1.length());
     System.out.println("sb1 capacity: "+ sb1.capacity());
     sb1.setLength(5);
     System.out.println("sb1 is now: "+ sb1);
     System.out.println("sb1 capacity: "+ sb1.capacity());
     System.out.println("sb1 length: "+ sb1.length());
  } // end main
} // end TryStringBuilder

Note: The StringBuilder & StringBuffer classes are the same except that StringBuilder is not synchronized (StringBuffer is), so if the Java program is not running more than one thread, use StringBuilder (more efficient) -- everything described and all examples with StringBuilder could also be applied to StringBuffer.

/*
EXERCISE 6.1: Modify the Customer class to have two StringBuilders, one for first name, one for last name,
 but still have a constructor with a String parameter that will parse the String into two (use the mutator).. 
 - Keep the accessor that returns one String for the name, but return the name in the form "last, first".
 Change the mutator so it has one String for the name, and parses the parameter into two parts,
 assuming the form "last, first" (with one space after the comma). 
 - Assign the part before the comma to the StringBuilder for the lastName, and the rest after the ", " to the StringBuilder for the firstName. DON'T instantiate new StringBuilders in this method (nor in the constructor)!
  The declarations to use are given in the Catalyst link for this exercise.
*/
public class Exercise_6_1_Customer
{
 private StringBuilder lastName = new StringBuilder();
 private StringBuilder firstName = new StringBuilder();
 
 // private String s_CustomerName;   // Removed and used String Builder as HW requirement
 private long l_CustomerAcctNum;
 private Exercise_5_3_SavingsAccount oExercise_5_3_SavingsAccount;
 
 public Exercise_6_1_Customer()
 {
  oExercise_5_3_SavingsAccount = new Exercise_5_3_SavingsAccount();  // in case, might prevent exception
 }
 public Exercise_6_1_Customer(String customerName, long customerAcctNum, double balance)
 {
  setCustomerName(customerName);
  l_CustomerAcctNum = customerAcctNum;
  oExercise_5_3_SavingsAccount = new Exercise_5_3_SavingsAccount(balance);
 }
 
 public String getCustomerName()
 {
  if(lastName.length() != 0 && firstName.length() != 0)
   return lastName + ", " + firstName;
  else if(lastName.length() != 0)
   return lastName.toString();
  else
   return "";
  //return s_CustomerName;
 }
 
 public long getCustomerAcctNum()
 {
  return l_CustomerAcctNum;
 }
 
 public Exercise_5_3_SavingsAccount getSavingsAccount()
 {
  return oExercise_5_3_SavingsAccount;
 }
 
 public void setCustomerName(String CustomerName)
 {
  //s_CustomerName = CustomerName;       // is it require to check for empty string ??
  
  lastName.setLength(0);    // Not submitted in HW submission -> MUST clear lastName builder or next set gives exception
  firstName.setLength(0);    // Not submitted in HW submission
  if(CustomerName != null && CustomerName.trim() != "")
  {
   CustomerName = CustomerName.trim(); // Not submitted in HW submission
   lastName.insert(0, CustomerName.substring(0, CustomerName.indexOf(',')));
   firstName.insert(0, CustomerName.substring(lastName.length()+2));
  }
 }
 
 public void display()
 {
  System.out.println("Customer Name: " + getCustomerName());
  System.out.println("Customer A/C no: " + l_CustomerAcctNum);
  System.out.println("Customer Balance: " + oExercise_5_3_SavingsAccount.getBalance());
 }
 
 public static void main(String[] args)
 {
  // Test case
  Exercise_6_1_Customer oExercise_6_1_Customer = new Exercise_6_1_Customer("DEF, ABC", 1234567890, 1000.00);
  oExercise_6_1_Customer.display();
  
  oExercise_6_1_Customer.setCustomerName("ABC, DEF");
  oExercise_6_1_Customer.display();
  
  oExercise_6_1_Customer.setCustomerName("");
  oExercise_6_1_Customer.display();
  oExercise_6_1_Customer.setCustomerName(null);
  oExercise_6_1_Customer.display();
 }
}
/*
Output:
Customer Name: ABC, DEF
Customer A/C no: 1234567890
Customer Balance: 1000.0
Customer Name: ABC, DEF
Customer A/C no: 1234567890
Customer Balance: 1000.0
Customer Name:
Customer A/C no: 1234567890
Customer Balance: 1000.0
Customer Name:
Customer A/C no: 1234567890
Customer Balance: 1000.0
*/

Tokenizing Strings: StringTokenizer

The StringTokenizer class:

  • is in java.util package
  • is used to break down a String into Tokens
  • constructors (2 out of 3 shown here):
    • public StringTokenizer(String str, String delim) - Constructs a string tokenizer for str. The characters in the delim argument are the delimiters for separating tokens. Delimiter characters themselves will not be treated as tokens.
    • public StringTokenizer(String str) - Constructs a string tokenizer for str. The tokenizer uses the default delimiter set, which is " \t\n\r\f": the space character, the tab character, the newline character, the carriage-return character, and the form-feed character.
  • NOTE: the delimiters are considered a set of delimiter chars, and if there are several delimiters (any in the delimiter String, no particular order), they will be skipped when the StringTokenizer finds the next token.

Some of the methods:

  • public boolean hasMoreTokens() - Tests if there are more tokens available from this tokenizer's string. If this method returns true, then a subsequent call to nextToken with no argument will successfully return a token.
  • public String nextToken() - Returns the next token from this string tokenizer.

Throws: NoSuchElementException - if there are no more tokens in this tokenizer's string.

  • public int countTokens() - Calculates and returns the number of times that this tokenizer's nextToken method can be called before it generates an exception. The current position is not advanced.

Tokenizing Strings: String's split method

The String class' split method is declared as follows:

public String[] split(String regex)

  • an instance method in the String class (so you need to call it on a String object)
  • will return an array of Strings for which each element is a token of the String
  • the parameter must be a regular expression (not discussed here, will need to look up on your own)
  • the delimiter chars (as shown) will use only ONE delimiter between tokens (may give an empty token if two delimiters in a row)
  • to get the tokens of a String using a set of delimiters, pass the delimiters in a String with square brackets around the delimiter chars (example below)

Example of using the split method:

public class TrySplit {
    public static void main( String [] args )  {
       String testStr = " 2.5, 3,000";//space in front
       String [] tokens;
       tokens = testStr.split("[ ,]");//space & comma
       for( int i=0; i < tokens.length; ++i ){
      System.out.println("\"" + tokens[i] + "\"");
       } // end for
    } // end main
} // end TrySplit
/* Output:
""
"2.5"
""
"3"
"000"
*/

/*
Exercise 6.2: Redo the setName method you wrote in Exercise 6.1 that used the StringBuilder for the last name and first name in the Customer class to use either a StringTokenizer of split method in the setName instance method (if you used one of these before, use the other for this).
*/
public class Exercise_6_2_SplitMethod
{ 
 // Note: Used Split method with old string variables for firstName and lasrName
 private String firstName = "";
 private String lastName = "";
 // private String s_CustomerName = "";         // --> used in old homework
 private long l_CustomerAcctNum;
 private Exercise_5_3_SavingsAccount oExercise_5_3_SavingsAccount;
 
 public Exercise_6_2_SplitMethod()
 {
  oExercise_5_3_SavingsAccount = new Exercise_5_3_SavingsAccount();  // in case, might prevent exception
 }
 public Exercise_6_2_SplitMethod(String customerName, long customerAcctNum, double balance)
 {
  setCustomerName(customerName);
  l_CustomerAcctNum = customerAcctNum;
  oExercise_5_3_SavingsAccount = new Exercise_5_3_SavingsAccount(balance);
 }
 
 public String getCustomerName()
 {
  if(lastName.length() != 0 && firstName.length() != 0)   // Added extra condition from previous homework to avoid exception
   return lastName + ", " + firstName;
  else if(lastName.length() != 0)
   return lastName.toString();
  else
   return "";
  //return s_CustomerName;    // --> used in old exercise
 }
 
 public long getCustomerAcctNum()
 {
  return l_CustomerAcctNum;
 }
 
 public Exercise_5_3_SavingsAccount getSavingsAccount()
 {
  return oExercise_5_3_SavingsAccount;
 }
 
 public void setCustomerName(String CustomerName)
 {
  //s_CustomerName = CustomerName; // --> used on old homework
  lastName = firstName = "";   // Reset values
  String [] tokens;
  if(CustomerName != null && CustomerName.trim() != "") // To avoid exception  --> Not submitted in previous HW submission
  {
   CustomerName = CustomerName.trim();     // Not submitted in previous HW submission
   if(CustomerName.contains(", "))      // To avoid exception
   {
    tokens = CustomerName.split(", ");
    lastName = (tokens.length >= 0)? tokens[0] : "";
    firstName = (tokens.length >=1)? tokens[1] : "";
   }
   // lastName.insert(0, CustomerName.substring(0, CustomerName.indexOf(',')));  // last homework using StringBuilder
   // firstName.insert(0, CustomerName.substring(lastName.length()+2));    // last homework using StringBuilder
  }
 }
 
 public void display()
 {
  System.out.println("Customer Name: " + getCustomerName());
  System.out.println("Customer A/C no: " + l_CustomerAcctNum);
  System.out.println("Customer Balance: " + oExercise_5_3_SavingsAccount.getBalance());
 }
 
 public static void main(String[] args)
 {
  // Test case
  Exercise_6_2_SplitMethod oExercise_6_2_SplitMethod = new Exercise_6_2_SplitMethod("Lastname, Firstname", 1234567890, 1000.00);
  oExercise_6_2_SplitMethod.display();
  // other test cases
  oExercise_6_2_SplitMethod.setCustomerName("ABC, DEF");  oExercise_6_2_SplitMethod.display();
  oExercise_6_2_SplitMethod.setCustomerName("ABC");   oExercise_6_2_SplitMethod.display();
  oExercise_6_2_SplitMethod.setCustomerName("");   oExercise_6_2_SplitMethod.display();
  oExercise_6_2_SplitMethod.setCustomerName(null);  oExercise_6_2_SplitMethod.display();
  
  // Quiz 6 test
  String str = "a+b/(c-d)";
  String [] strArray = str.split("[+-/()]");   //a-b--c-d
  System.out.println(strArray.length);  // -> length = 5
  
  String str1="ABCDE";
  System.out.println(str1.substring(1,3));
 }
}
/*
Output:
Customer Name: Lastname, Firstname
Customer A/C no: 1234567890
Customer Balance: 1000.0
Customer Name: ABC, DEF
Customer A/C no: 1234567890
Customer Balance: 1000.0
Customer Name:
Customer A/C no: 1234567890
Customer Balance: 1000.0
Customer Name:
Customer A/C no: 1234567890
Customer Balance: 1000.0
Customer Name:
Customer A/C no: 1234567890
Customer Balance: 1000.0
*/