## Section 2.3

Strings, Objects, and Subroutines

THE PREVIOUS SECTION introduced the eight primitive data types and the type

String. There is a fundamental difference between the primitive types and theStringtype: Values of typeStringare objects. While we will not study objects in detail until Chapter 5, it will be useful for you to know a little about them and about a closely related topic: classes. This is not just because strings are useful but because objects and classes are essential to understanding another important programming concept, subroutines.Recall that a subroutine is a set of program instructions that have been chunked together and given a name. In Chapter 4, you'll learn how to write your own subroutines, but you can get a lot done in a program just by calling subroutines that have already been written for you. In Java, every subroutine is contained in a class or in an object. Some classes that are standard parts of the Java language contain predefined subroutines that you can use. A value of type

String, which is an object, contains subroutines that can be used to manipulate that string. You can call all these subroutines without understanding how they were written or how they work. Indeed, that's the whole point of subroutines: A subroutine is a "black box" which can be used without knowing what goes on inside.Classes in Java have two very different functions. First of all, a class can group together variables and subroutines that are contained in that class. These variables and subroutines are called static members of the class. You've seen one example: In a class that defines a program, the

main()routine is a static member of the class. The parts of a class definition that define static members are marked with the reserved word "static", just like themain()routine of a program. However, classes have a second function. They are used to describe objects. In this role, the class of an object specifies what subroutines and variables are contained in that object. The class is atype-- in the technical sense of a specification of a certain type of data value -- and the object is a value of that type. For example,Stringis actually the name of a class that is included as a standard part of the Java language. It is also a type, and actual strings such as"Hello World"are values of typeString.So, every subroutine is contained either in a class or in an object. Classes

containsubroutines called static member subroutines. Classes alsodescribeobjects and the subroutines that are contained in those objects.This dual use can be confusing, and in practice most classes are designed to perform primarily or exclusively in only one of the two possible roles. For example, although the

Stringclass does contain a few rarely-used static member subroutines, it exists mainly to specify a large number of subroutines that are contained in objects of typeString. Another standard class, namedMath, exists entirely to group together a number of static member subroutines that compute various common mathematical functions.

To begin to get a handle on all of this complexity, let's look at the subroutine

System.out.printas an example. As you have seen earlier in this chapter, this subroutine is used to display information to the user. For example,System.out.print("Hello World")displays the message, Hello World.

Systemis one of Java's standard classes. One of the static member variables in this class is namedout. Since this variable is contained in the classSystem, its full name -- which you have to use to refer to it in your programs -- isSystem.out. The variableSystem.outrefers to an object, and that object in turn contains a subroutine namedSystem.out.printrefers to the subroutineoutin the classSystem.(As an aside, I will note that the object referred to by

System.outis an object of the classPrintStream.PrintStreamis another class that is a standard part of Java.Anyobject of typePrintStreamis a destination to which information can be printed;anyobject of typePrintStreamhas aSystem.outis just one possible destination, andSystem.out.printis the subroutine that sends information to that destination. Other objects of typePrintStreammight send information to other destinations such as files or across a network to other computers. This is object-oriented programming: Many different things which have something in common -- they can all be used as destinations for information -- can all be used in the same way -- through aPrintStreamclass expresses the commonalities among all these objects.)Since class names and variable names are used in similar ways, it might be hard to tell which is which. All the built-in, predefined names in Java follow the rule that class names begin with an upper case letter while variable names begin with a lower case letter. While this is not a formal syntax rule, I recommend that you follow it in your own programming. Subroutine names should also begin with lower case letters. There is no possibility of confusing a variable with a subroutine, since a subroutine name in a program is always followed by a left parenthesis.

Classes can contain static member subroutines, as well as static member variables. For example, the

Systemclass contains a subroutine namedexit. In a program, of course, this subroutine must be referred to asSystem.exit. Calling this subroutine will terminate the program. You could use it if you had some reason to terminate the program before the end of themainroutine. (For historical reasons, this subroutine takes an integer as a parameter, so the subroutine call statement might look like "System.exit(0);" or "System.exit(1);". The parameter tells the computer why the program is being terminated. A parameter value of 0 indicates that the program is ending normally. Any other value indicates that the program is being terminated because an error has been detected.)Every subroutine performs some specific task. For some subroutines, that task is to compute or retrieve some data value. Subroutines of this type are called functions. We say that a function returns a value. The returned value must then be used somehow in the program.

You are familiar with the mathematical function that computes the square root of a number. Java has a corresponding function called

Math.sqrt. This function is a static member subroutine of the class namedMath. Ifxis any numerical value, thenMath.sqrt(x)computes and returns the square root of that value. SinceMath.sqrt(x)represents a value, it doesn't make sense to put it on a line by itself in a subroutine call statement such asMath.sqrt(x); //This doesn't make sense!What, after all, would the computer do with the value computed by the function in this case? You have to tell the computer to do something with the value. You might tell the computer to display it:

System.out.print( Math.sqrt(x) ); // Display the square root of x.or you might use an assignment statement to tell the computer to store that value in a variable:

lengthOfSide = Math.sqrt(x);The function call

Math.sqrt(x)represents a value of typedouble, and it can be used anyplace where a numerical value of type double could be used.The

Mathclass contains many static member functions. Here is a list of some of the more important of them:

Math.abs(x), which computes the absolute value ofx.- The usual trigonometric functions,
Math.sin(x),Math.cos(x), andMath.tan(x). (For all the trigonometric functions, angles are measured in radians, not degrees.)- The inverse trigonometric functions arcsin, arccos, and arctan, which are written as:
Math.asin(x),Math.acos(x), andMath.atan(x).- The exponential function
Math.exp(x)for computing the number e raised to the powerx, and the natural logarithm functionMath.log(x)for computing the logarithm ofxin the base e.Math.pow(x,y)for computingxraised to the powery.Math.floor(x), which roundsxdown to the nearest integer value that is less than or equal tox. (For example,Math.floor(3.76)is 3.0.)Math.random(), which returns a randomly chosendoublein the range0.0 <= Math.random() < 1.0. (The computer actually calculates so-called "pseudorandom" numbers, which are not truly random but are random enough for most purposes.)For these functions, the type of the parameter -- the value inside parentheses -- can be of any numeric type. For most of the functions, the value returned by the function is of type

doubleno matter what the type of the parameter. However, forMath.abs(x), the value returned will be the same type asx. Ifxis of typeint, then so isMath.abs(x). (So, for example, whileMath.sqrt(9)is thedoublevalue 3.0,Math.abs(9)is theintvalue 9.)Note that

Math.random()does not have any parameter. You still need the parentheses, even though there's nothing between them. The parentheses let the computer know that this is a subroutine rather than a variable. Another example of a subroutine that has no parameters is the functionSystem.currentTimeMillis(), from theSystemclass. When this function is executed, it retrieves the current time, expressed as the number of milliseconds that have passed since a standardized base time (the start of the year 1970 in Greenwich Mean Time, if you care). One millisecond is one thousandth second. The value ofSystem.currentTimeMillis()is of typelong. This function can be used to measure the time that it takes the computer to perform a task. Just record the time at which the task is begun and the time at which it is finished and take the difference.Here is a sample program that performs a few mathematical tasks and reports the time that it takes for the program to run. On some computers, the time reported might be zero, because it is too small to measure in milliseconds. Even if it's not zero, you can be sure that most of the time reported by the computer was spent doing output or working on tasks other than the program, since the calculations performed in this program occupy only a tiny fraction of a second of a computer's time.

public class TimedComputation { /* This program performs some mathematical computations and displays the results. It then reports the number of seconds that the computer spent on this task. */ public static void main(String[] args) { long startTime; // Starting time of program, in milliseconds. long endTime; // Time when computations are done, in milliseconds. double time; // Time difference, in seconds. startTime = System.currentTimeMillis(); double width, height, hypotenuse; // sides of a triangle width = 42.0; height = 17.0; hypotenuse = Math.sqrt( width*width + height*height ); System.out.print("A triangle with sides 42 and 17 has hypotenuse "); System.out.println(hypotenuse); System.out.println("\nMathematically, sin(x)*sin(x) + " + "cos(x)*cos(x) - 1 should be 0."); System.out.println("Let's check this for x = 1:"); System.out.print(" sin(1)*sin(1) + cos(1)*cos(1) - 1 is "); System.out.println( Math.sin(1)*Math.sin(1) + Math.cos(1)*Math.cos(1) - 1 ); System.out.println("(There can be round-off errors when" + " computing with real numbers!)"); System.out.print("\nHere is a random number: "); System.out.println( Math.random() ); endTime = System.currentTimeMillis(); time = (endTime - startTime) / 1000.0; System.out.print("\nRun time in seconds was: "); System.out.println(time); } // end main() } // end class TimedComputationHere is a simulated version of this program. If you run it several times, you should see a different random number in the output each time.

A value of type

Stringis an object. That object contains data, namely the sequence of characters that make up the string. It also contains subroutines. All of these subroutines are in fact functions. For example,lengthis a subroutine that computes the length of a string. Suppose thatstris a variable that refers to aString. For example,strmight have been declared and assigned a value as follows:String str; str = "Seize the day!";Then

str.length()is a function call that represents the number of characters in the string. The value ofstr.length()is anint. Note that this function has no parameter; the string whose length is being computed isstr. Thelengthsubroutine is defined by the classString, and it can be used with any value of typeString. It can even be used withStringliterals, which are, after all, just constant values of typeString. For example, you could have a program count the characters in "Hello World" for you by sayingSystem.out.print("The number of characters in "); System.out.println("the string \"Hello World\" is "); System.out.println( "Hello World".length() );The

Stringclass defines a lot of functions. Here are some that you might find useful. Assume thats1ands2refer to values of typeString:

s1.equals(s2)is a function that returns abooleanvalue. It returnstrueifs1consists of exactly the same sequence of characters ass2, and returnsfalseotherwise.s1.equalsIgnoreCase(s2)is another boolean-valued function that checks whethers1is the same string ass2, but this function considers upper and lower case letters to be equivalent. Thus, ifs1is "cat", then s1.equals("Cat")isfalse, while s1.equalsIgnoreCase("Cat")istrue.s1.length(), as mentioned above, is an integer-valued function that gives the number of characters ins1.s1.charAt(N), whereNis an integer, returns a value of typechar. It returns theN-th character in the string. Positions are numbered starting with 0, sos1.charAt(0)is actually the first character,s1.charAt(1)is the second, and so on. The final position iss1.length() - 1. For example, the value of"cat".charAt(1)is 'a'. An error occurs if the value of the parameter is less than zero or greater thans1.length() - 1.s1.substring(N,M), whereNandMare integers, returns a value of typeString. The returned value consists of the characters ins1in positionsN,N+1,...,M-1. Note that the character in positionMis not included. The returned value is called a substring ofs1.s1.indexOf(s2)returns an integer. Ifs2occurs as a substring ofs1, then the returned value is the starting position of that substring. Otherwise, the returned value is -1. You can also uses1.indexOf(ch)to search for a particular character,ch, ins1. To find the first occurrence ofxat or after positionN, you can uses1.indexOf(x,N).s1.compareTo(s2)is an integer-valued function that compares the two strings. If the strings are equal, the value returned is zero. Ifs1is less thans2, the value returned is a number less than zero, and ifs1is greater thans2, the value returned is some number greater than zero. (If both of the strings consist entirely of lowercase letters, then "less than" and "greater than" refer to alphabetical order. Otherwise, the ordering is more complicated.)s1.toUpperCase()is aString-valued function that returns a new string that is equal tos1, except that any lower case letters ins1have been converted to upper case. For example, "Cat".toUpperCase() is the string "CAT". There is also a functions1.toLowerCase().s1.trim()is aString-valued function that returns a new string that is equal tos1except that any non-printing characters such as spaces and tabs have been trimmed from the beginning and from the end of the string. Thus, ifs1has the value "fred ", thens1.trim()is the string "fred".For the functions

s1.toUpperCase(),s1.toLowerCase(), ands1.trim(), note that the value ofs1is not changed. Instead a new string is created and returned as the value of the function. The returned value could be used, for example, in an assignment statement such as "s2 = s1.toLowerCase();".

Here is another extremely useful fact about strings: You can use the plus operator, +, to concatenate two strings. The concatenation of two strings is a new string consisting of all the characters of the first string followed by all the characters of the second string. For example, "Hello" + "World" evaluates to "HelloWorld". (Gotta watch those spaces, of course.) Let's suppose that

nameis a variable of typeStringand that it already refers to the name of the person using the program. Then, the program could greet the user by executing the statement:

System.out.println("Hello, " + name + ". Pleased to meet you!");Even more surprising is that you can concatenate values belonging to one of the primitive types onto a

Stringusing the + operator. The value of primitive type is converted to a string, just as it would be if you printed it to the standard output, and then it is concatenated onto the string. For example, the expression "Number" + 42 evaluates to the string "Number42". And the statementsSystem.out.print("After "); System.out.print(years); System.out.print(" years, the value is "); System.out.print(principal);can be replaced by the single statement:

System.out.print("After " + years + " years, the value is " + principal);Obviously, this is very convenient. It would have shortened several of the examples used earlier in this chapter.

[ Next Section | Previous Section | Chapter Index | Main Index ]