9.5 Avoiding Errors and Debugging

Avoiding Errors

  1. Although we have mentioned it previously, it may bear repeating that a declaration like
       String s;
    only creates a variable that is capable of acting as a reference to a string. It does not create such a string and, in fact, it does not initialize s to any value at all. If, on the other hand, we write
       String t = null;
    then t will be initialized although it does not refer to a string. In this state, t can be printed (producing the word null) or compared to other string references. As a third possibility, if we write
       String u = "";
    then u is a reference to a string containing no characters. With the three declarations shown here, an attempt to compare s to either t or u will produce a compilation error while the expression t == u has the value false.
  2. Remember that comparisons of strings, like comparisons of any objects, should not be made using the == operator. As we have said before, if s1 and s2 are references to strings, then s1 == s2 will be equal only if s1 and s2 refer to the same object, not if they refer to equal objects stored at different locations. Always use either equals or compareTo when comparing strings.
  3. The fact that strings are immutable objects can often cause problems. Once a string object has been created, it cannot be altered. This implies that methods that have string parameters cannot alter them in any way. On the other hand, if we want to change the value of a string reference, we can do so by assigning it a new value. For example, the statement
       s = s.toUpperCase();
    first evaluates the expression s.toUpperCase() to produce a new string which is a copy of s but with all lower case letters converted to upper case. The assignment then changes the reference s so that it now refers to the newly created string. The original string to which s referred is no longer available (unless some other variable refers to it).
  4. Do not confuse characters with strings that are one character long. These are very different creatures. If, for example, we were to write
       char c = '*';
       String s = "*";

    then we can illustrate the results as follows:

    We can convert from one type to another but this must be done with care. We cannot use a simple assignment or even an assignment with a cast. If we wanted to assign the value of a one-character string s to a character c, we could write
       c = s.charAt(0);
    On the other hand, if we wanted to assign a character c to a string s, we could write
       s = String.valueOf(c);
  5. The operator +, as we have seen, is overloaded so that, when either operand is a string, it means concatenation rather than addition. Attempting to join two characters using + to produce a string does not have the desired effect. As an example, the statement
       System.out.println('x' + 'y');
    will not print xy. The actual output is 241!
          The reason for this is that Java interprets + in this case to mean addition (because no strings are involved). As we saw in Chapter 2, we can do arithmetic involving characters with Java using the Unicode encoding values of the characters in the arithmetic operations. As you can verify from the table on page 600, the Unicode values of 'x' and 'y' are 120 and 121 respectively. The sum of these values is 241.
          We can force Java to concatenate characters to form strings in a number of ways. For our example, the simplest way to achieve this is to write the argument of the println command as
       "" + 'x' + 'y'
    By placing an empty string at the beginning of the expression, we make Java interpret the first + to mean concatenation. Evaluating the expression from left to right, Java would obtain the following result:
       "" + 'x' + 'y' => "x" + 'y' => "xy"
  6. If you want to create a string that replaces one character in a string by some other character, you cannot use the charAt method to do so. As an example, if we wish to replace the character at index 4 in the string s by an asterisk, it is a mistake to attempt to write something like
       s.charAt(4) = '*';     // wrong!
    The problem here is that the left side of the assignment statement contains a method call that returns a char value rather than the identifier of a location in which a char value can be stored. A correct way to achieve the desired effect is to write
       s = s.substring(0,4) + '*' + s.substring(5);
  7. Although strings and arrays of characters have many things in common, they are not the same and they must be treated appropriately. For example, if s is a string and a is an array of characters, then,

Debugging

  1. In tracing programs involving strings, it is a good idea to print strings with some delimiter on either side of them. For example, to determine the value of a string s, one might write the string
    "|" + s + "|"
    This has a couple of purposes:
  2. The two-parameter version of the substring method that has the header
       String substring (int start, int pastEnd)
    is a frequent source of problems because the second parameter specifies the index after the last character of the substring rather than the last character itself. If you work with the substring method long enough, you may begin to realize that the way that the method is designed is, in fact, a good idea but it does tend to cause grief to beginning programmers.

Exercise 9.5

  1. Suppose that we are given the declarations
       String s;
       String t = null;
       String u = "";
       String v = " "; 
    State, with reasons, what would occur if the program containing these declarations attempted to print the value of each expression.
          a. s.length()                    b. t.length()
          c. u.length()                    d. v.length()
  2. Given the declaration
       String [] names = new String [10];
    state, with justification, the result of each statement.
    1. System.out.println(names[0]);
    2. System.out.println(names.length);
    3. System.out.println(names.length());
    4. System.out.println(names[0].length());
  3. Using the table on page 600 where necessary, determine what would be printed by each statement.
    1. System.out.println("" + '$' + '2');
    2. System.out.println('$' + '2');
    3. System.out.println('$' + 2);
    4. System.out.println("$" + '2');
    5. System.out.println("$" + 2);
    6. System.out.println('$' + '2' + ".00");
  4. Write a method whose heading is
       public static String changeFirst (String s, char oldChar, char newChar)
    The method should return a string in which the leftmost occurrence of oldChar in s is replaced by newChar. If oldChar does not appear in s, the method should simply return s.