Chapter 8: Using Library Classes (for Basic Input/Output Operations)
8.0
Introduction
In previous chapters we have seen how user defined classes can be created and used for solving different real life problems. Any program needs input/output operations. For input/output operations, java takes help of library classes. You have already noticed that every java program, written so far, have made use of output statements like System.out.println (....); or System.out.print (...); and so on. Those output statements have three parts separated by dots (.). The rightmost portion – println (..) or print (..) -stands for a method or function lying defined in a library of classes called System that controls several aspects of the run-time environment. The library class System belongs to the java.lang package that gets automatically included or imported with every java program. The System contains three predefined stream variables -- in, out, err. [A stream can be thought of as a flow of bytes or characters.] System.out refers to the standard output stream (console VDU), System.in refers to the standard input stream (i.e. console keyboard) and System.err refers to the standard error stream which is also the console VDU, by default. In chapter-7 we have also made use of the input statement System.in.read (..) that calls the method to read a character from keyboard. The read () method is applicable on the input stream System.in that is capable of reading from a keyboard. Thus we find that a user defined class can import and use any member methods or functions available within the java’s library classes. Such reuse of library classes in a java program makes coding much easier, simpler and systematic. Although System classes get automatically included through java.lang package, there are many more java’s built-in library packages, which are to be explicitly imported using import statement while a user wants to include them in a user defined class for reuse. In example-2.4, you have seen such an import of classes from java.util.* package while defining the DateDemo class. Java provides many built-in library classes for the support of operations involving Input/Output, String handling, Graphics, Networking, etc. Therefore, Java can be regarded as a language with many modules of class libraries. In all previous chapters we have seen just the use of java’s I/O statements. Now we have to understand the inner details that are going on behind every such call for input/output operations. So we will begin this chapter with the discussions on simple I/O operations and then pass on to the String Handling operations.
8.1
Simple Input/output Operations
Unlike most other languages Java does not provide any special statement for input/output operations. It is all done by invoking the methods of java.io.* classes. System classes can handle only simple I/O operations, which take place only through standard input/output devices i.e. the console keyboard (System.in), standard output device – the VDU screen (System.out) and standard error device – the same VDU screen (System.err). For I/O operations through any other I/O devices and for handling different data types, the java.io.* classes are to be utilized. A java program is capable of reading from any input stream and can write to any output stream other than keyboard and VDU. Of course, appropriate physical peripheral devices are to be connected with the logical stream interfaces to perform proper I/O operations. A stream is a logical entity that can either collect from an input device or hand-over to an output device any data or information as a flow of bytes or characters. A stream gets linked with a physical device by taking help of Java’s I/O classes. Physical devices may be different but all linked streams behave in the same manner in a run time environment. That is the beauty of having a separate library of I/O classes. Stream Input
Stream
Program
Output
Stre Buffer
Buffer
Fig – 8.1 Java Program interfacing with Input / Output Streams In an ordinary sense, a stream is nothing but a sequence of characters or bytes coming from a data input source and going out towards a data output sink. Please allow me to quote from the Complete Reference Java 2 book (where you can find the details of all I/O classes)– “Streams are a clean way to deal with input/output without having every part of your code to understand the difference between a keyboard and a network.” Thus to a programmer, I/O operations become device independent. 8.1.1
Byte Streams and Character Streams
There are two types of java streams – byte stream and character stream. Byte streams are used for reading or writing binary data. Character streams are used for handling character type data. Character streams are more efficient than byte stream for I/O operations. Byte streams are defined by two hierarchies – at top abstract level: InputStream and OutputStream classes and -- at concrete level: for each one of them several subclasses to handle different devices like – disk, files, memory buffers, etc.
Similarly, character streams are also defined at two levels -- on top: Reader and Writer classes for Unicode character streams and -- at implementation level: different read () and write () methods for different I/O devices. All java programs automatically import java.lang package, which includes a class called System. System.out refers to the standard output stream object and System.in refers to the standard input stream object. However, these streams can be redirected to any compatible I/O devices. Byte oriented System.in object is a more complex to handle. For reading data from console keyboard, modern Java makes use of character oriented stream objects to make program writing easier. We will first see how to read character(s) from a keyboard. 8.1.2
Reading from a Keyboard
Characters to be read from a keyboard come via a memory buffer (fig-8.1) and that is why to handle any keyboard input, a BufferedReader and read () method is used. Each time read () method is called, a character is read from the input stream and returns the same as a binary equivalent of that character. Study the codes and outputs shown in picture 8.1 –
Picture 8.1 Top – Source codes; Bottom-- Outputs (What is the integer equivalent of a ‘blank’ character?)
Now study another example-8.1 of keyboard inputs. Example –8.1 Keyboard Character Input Demo //java.io.* library classes are to be imported import java.io.*;
// java.io library classes included
public class BRchin { public static void main() throws IOException { char ch; BufferedReader conin = new BufferedReader (new InputStreamReader (System.in)); System.out.println (" Enter characters and end entry with 'q':"); do { ch = (char) conin.read(); // converted from binary to char System.out.print (ch); } while (ch != 'q'); System.out.println (“ \n Out of Loop as you have typed ‘q’ to quit.”); } } Mark the inclusion of the statement “ throws IOException” after the main () method. Also observe carefully the portion of the code BufferedReader conin = new BufferedReader (new InputStreamReader (System.in)); by which a new BufferedReader type object instance, called conin, gets created and connected with the System.in ( i.e. keyboard) device as an object of InputStreamReader class type. Thus the physical keyboard becomes connected with the logical Input Stream. Moreover, the read () method (which helps reading a character as its binary equivalent) is called by the code – conin.read(). The binary representation of the input character is again converted to char format for users to see that one as a character.
Picture 8.2 Run this program to see what it does. It will go on reading the typed characters until ‘q’ button is pressed (Picture 8.2). Why printing does not take place after every character entry? As System.in is line buffered (that means no further action will be taken until a line-end signal is sensed), no input has been passed to the program until you press Enter (indicating line-end). Whatever characters are typed before pressing the return key, remain stored in the ReaderBuffer and handed over to the program when enter or return key is pressed. Although print () statement is included in the while loop, immediate printing was not taking place. That is because, the read () method (used for character reading) is putting the pressed character to the input buffer and not to the printer stream directly. Another member function readLine () of the BufferedReader class can be used for String inputs from a keyboard. Example 8.2 Demo of Reading Strings from a keyboard import java.io.*; public class BRLin { public static void main() throws IOException { BufferedReader conin = new BufferedReader (new InputStreamReader (System.in)); String str1; String str2 = " "; // A Null String is created System.out.println ("Enter text lines and quit by typing stop"); do { str1 = conin.readLine(); System.out.println (str1); str2 =(str2 + str1); // Concatenation of Strings } while (!str1.equals("stop")); System.out.print (str2); }
}
Picture 8.3 By running this program you will observe the output as shown in Picture 8.3. The entered string is echoed on the VDU screen line by line. When you type stop, only then the entire concatenated typed material (str2) is printed out. Verify the outputs with the program codes. 8.1.3
Reading Integer Inputs from a Keyboard
Reading integer data from a keyboard can be performed either using Character Oriented Input operations or by using Byte Oriented Input operations. Both these input operations are not so straightforward and easy as output operations. Character oriented operation needs call of some conversion method to convert (i.e. parse) the String object into some integer value. Character oriented input takes help of InputStreamReader (which translates binary data received from InputStream objects into a stream of characters) and BufferedReader, which stores the input received from an InputStreamReader object. For Byte Oriented operations DataInputStream object is used. After creating a new DataInputStream object, different input values can be read as follows – DataInputStream in = new DataInputStream (System.in); int i = in.readInt(); char ch = in.readChar(); double d = in.readDouble(); ......
As byte oriented IO operation using Data Streams is machine dependent, it will not be wise to use them for modern java applications and that is why no example will be shown here. Exception Handling for I/O Operations As java makes exception handling mandatory for IO operations, all reading statements must be placed in a try block having a construction shown below – try { // reading statements } catch (Exception e {...} Let us now study an example of reading integer data through a keyboard using exception handling mechanism, further details of which will be explained in chapter-11. Example-8.4 Character Oriented Integer Input with ParseInt () method of IntegerWrapper import java.io.*; class CharOrintInput { public static void main () throws IOException { // create a buffer reader using System.in BufferedReader keyin InputStreamReader(System.in));
=
new
BufferedReader(new
String str; int i =0; System.out.println ("Enter numeric data."); str = keyin.readLine(); try { i = Integer.parseInt(str);}
// converting string into integer value
catch (NumberFormatException e) { System.out.println ("Invalid data entry Format."); } System.out.println (" Data value entered: " + i);} }
The statement – str = keyin.readLine(); – reads the keyed-in character sequence and the statement -- i = Integer.parseInt(str); -- converts that character sequence into integer value by taking help of Integer wrapper class’s parseInt(..) conversion method. Please take note of the try—catch use of the exception handling mechanism. 8.1.4
Writing Console Output
We have already seen the use of print() and println() methods of the System.out class. System.out is a byte stream and can be used for simple input/output operations only. However, character based alternative is mostly accepted in modern times. The PrintWriter stream is character based and widely used in professional programs for console output. It has a construct – PrintWriter (OutputStream type object, true | false) Let us see its use in a program. /* Example-8.5 Use of PrintWriter class for Console write */ import java.io.*; public class PrintWrite { public static void main() { PrintWriter vdu = new PrintWriter (System.out, true); vdu.println( " This shows the use of PrintWriter for write on console ."); int i =27; vdu.println(" Printing an integer value : " + i); double d= 41.3241; vdu.println(" Printing a double value : " + d); char ch = 'A'; vdu.println(" Printing a Character : " + ch); String str = " Computer"; vdu.println(" Printing a String : " + str); } }
Picture 8.4 Run this program and see the output (Picture 8.4). Here one vdu object of PrintWriter class type is created to logically link the VDU screen (i.e. System.out) with the program output stream. The use of the parameter true indicates that automatic flush of the output buffer will occur when a newline (‘\n’) character appears. The main beauty of using PrintWriter class is that any output device can be linked with its println () method. Further discussions on this point will be made in chapter-11. 8.2
String Operations
A string is regarded as a sequence of characters. Every string can be regarded as an object of a String class. The String class has many built-in methods to perform operations like -to compare two strings, to search for a sub-string, to concatenate two strings, to change case of letters within a string, etc..... Once a String object is created, no change in the characters, comprising the string, can be allowed in java. String objects can be created either implicitly (i.e. declaring within double quotes) or explicitly (using new keyword). The java.lang package contains the definition of both String and StringBuffer classes. Once declared, the contents of a String instance cannot be changed. Every String becomes a fixed length, immutable character sequence. Those are limitations of a String class. However, StringBuffer is a peer class of String having much more flexibility. Unlike String, StringBuffer is capable of growing and changing. We will first discuss about the String class and then about the StringBuffer class.
8.2.1
String class
(i) The String Constructors for Explicit String Creation: --The default constructor to create an empty string has the form -String str = new String(); A string can be created also from a given array of characters as shown below – char chars[] = { ‘x’, ‘y’, ‘z’ }; String str1 = new String(chars); Thus a string str1 = “xyz” gets created. Please note that a character set can be used to create String explicitly using the new operator. However Strings can be created implicitly in a much simpler way by using the string literals. A String object gets created automatically for every string literal. For example, the statement -String str2 = “ BlueJ”; creates implicitly characters.
the string object str2 with “BlueJ” as the sequence of
Such implicitly created strings can call all methods supported by the String class. For example, the length () method can be applied to string object “BlueJ” as shown below – System.out.println (“The string length is = “ + str2.length( )); A complete java program can help you in understanding the use of String class. Example-8.6 Demo of String Handling public class StringDemo { public static void main() { char chars[] = { 'b','o','o','k'}; String str1 = new String(chars); // using characters String str2 = "On Java"; // using string literal System.out.println (" First string: " + str1); System.out.println (" Second string: " + str2); // calling length() method
System.out.println (" First string length =" + str1.length ()); System.out.println (" Second string length = " + str2.length ()); } } This program will give the output – First string: book Second string: On Java First string length = 4 Second string length = 7 [why 7 --? explain.] 8.2.2
String Concatenation with different data types
Concatenation means joining different strings together placing them one after another. A sentence can be thought of as concatenation of words with blank (or white space) characters placed in between. Strings can concatenate with other types of data as shown in example-8.7. Example-8.7 Demo of Concatenation with Different Data Types public class StringDataType { public static void main() { String name = "Naren"; int age = 14; String str = name + " is " + age + " years old."; System.out.println (str); } } This program will give the output – Naren is 14 years old. Be careful about the use of (+) in a java statement while using multiple data types for string concatenation. Observe carefully the outputs of example-8.8. Example-8.8 The Role of + in different situations
public class StringMix { public static void main() { String str1 = " Result1:" + 2 + 7; String str2 = " Result2:" + (2 + 7); System.out.println (str1); System.out.println (str2); } } The output will show -Result1: 27 Result2: 9 8.2.3
[Try to understand – why the outputs differ?]
Different Accessor Methods of the class String
Methods by which string objects can be manipulated are called accessor methods built-in with the class String. We will discuss about the most commonly used accessor methods here. Method Prototype Action Description --------------------------------------------------------------------------------------------------------------char charAt( int index) Returns char at specified index(0,1,2..) int compareTo( string1, string2)
Compares two strings (difference in alphabetic order)
boolean equals( String str)
Compares this string with specified str
boolean equalsIgnoreCase(String str)
as before but ignoring case differences
int indexOf(char ch)
returns ch position in this string
int lastIndexOf(char ch)
returns last position of ch in this string
String replace( char oldCh, char newCh)
replace oldCh with newCh in this string
String substring( int startIndex, int endIndex)
returns a sub-string of this string
String toLowerCase()
convert all characters to lower case
String toUpperCase()
convert all characters to upper case
String trim()
remove leading and trailing white spaces from this string
boolean startsWith( String str)
checks whether this string’s starting matches with the given str ----------------------------------------------------------------------------------------------------------The use of accessor methods of String class is made in example-8.9. Example-8.9 Demo of Different Accessor Methods of String class public class AccessorMethods { public static void main () { String str1 = "computer applications --"; String str2 = " BlueJ development environment."; System.out.println (" charAt() position 3 of str1 is :: " + str1.charAt(3)); String str3 = "abc"; String str4 = "abd"; System.out.println (" Comparing str4 with str3:: " + str4.compareTo(str3)); System.out.println (" Comparing str3 with str3:: " + str3.compareTo(str3)); String str5 = "string test"; String str6 = "String Test"; System.out.println (" Equality Test for str5 & str6:: " + str6.equals(str5)); System.out.println (" Equality Test Ignoring Case::"+str6.equalsIgnoreCase(str5)); System.out.println (" Substring str1 from position 4:: " + str1.substring(4)); System.out.println (" Substring str1 from index 8 to 20::" + str1.substring(8,20)); System.out.println (" Case Conversion of str1 ::" + str1.toUpperCase()); String str7 = " Testing trim method. "; System.out.println (" Demo of trim() method on str7 ::" + str7.trim()); } } If you run this program, the following output will appear on the terminal screen -charAt() position 3 of str1 is :: p Comparing str4 with str3:: 1 Comparing str3 with str3:: 0 Equality test str5 & str6:: false Equality test Ignoring Case:: true Substring str1 from position 4:: uter applications – Substring str1 from index 8 to 20:: application Case conversion of str1:: COMPUTER APPLICATIONS – Demo of trim() method on str7 :: Testing trim method.
8.2.4
StringBuffer Class
Unlike objects of String class, objects of StringBuffer class are capable of growing and changing. StringBuffer class defines 3 constructors – StringBuffer () – the default constructor reserves room for 16 characters; StringBuffer (int size) – accepts an integer argument and sets the size as specified; StringBuffer (String str) – accepts a String argument plus reserves room for 16 more characters. The StringBuffer is more flexible and can support many additional methods like – append (..) – concatenates existing string with another string or a number or an object asked to be appended; it allows subsequent calls to be chained together. For example – class appendExample { public static void main() { String longstr; int i = 12; StringBuffer strbfr = new StringBuffer (50); // buffer size is set to 50 //chaining of append method longstr = strbfr.append(“Value”).append(i).append(“ is an Integer.”).toString(); System.out.println (longstr); } } This program will give an output – Value 12 is an Integer. insert(..) – can insert string or char or object at specified location in an existing String; the general form is as follows – StringBuffer insert (int position, String str) StringBuffer insert (int position, char ch) StringBuffer insert (int position, Object obj) where position indicates at which point the insertion will take place. Now an example – class insertExample { public static void main() { StringBuffer strbfr = new StringBuffer (“ I must Java.”); strbfr.insert(7, “ learn ”); System.out.println (strbfr); } }
By running this program you will get the output – I must learn Java. Length () – The current length of a stringBuffer can be found out by calling this method. Capacity () -- whereas the total allocated capacity of the string buffer can be found out by calling capacity() method. ensureCapacity( int capacity) – by calling this method you can ensure a desired capacity of a string buffer instead of relying on the default allocation of buffer size. setLength( int length) -- size of an already created string buffer can be reduced to a specified length. setCharAt(int position, char ch) -- change the character at the specified position with the new character ch. charAt( int where) can be used to obtain the character at the specified location. reverse () – characters within a string buffer object can be reversed by calling reverse () method. delete (int startpoint, int endpoint) -- can delete a sequence of characters from the specified starting point unto the end point. deleteCharAt( int position) – can delete a single character at the specified location. replace( int startpoint, int endpoint, String str) -- can replace a set of characters from the specified starting point to the end point by the specified string str. substring( int startIndex) , substring( int startIndex, int endIndex) -- can return only a portion of a string buffer from start point up to the end or from the start point up to the specified end point. The above list is not complete. For the complete list, you can refer to Java’s Complete Reference Manual. However usefulness of the methods of string buffer class can be understood from the example – 8.10 as shown below :-/* Example –8.10 Use of String Buffer Class */ public class StringBufDemo { public static void main() { StringBuffer strbf = new StringBuffer (" My String buffer for testing."); System.out.println (" String length is::" + strbf.length()); System.out.println (" Buffer capacity is::" + strbf.capacity()); System.out.println (" charAt(5) now :: " + strbf.charAt(5));
strbf.setCharAt(11, 'B'); System.out.println (" New look of the string buffer :: " + strbf); strbf.reverse(); System.out.println (" The reverse of my string is ::" + strbf); strbf.delete(1, 12); System.out.println (" After delete operation :: " + strbf); } } If you run this program, the following output will be obtained: -String length is:: 30 Buffer capacity is:: 46 CharAt(5) now :: t New look of the string buffer:: My String for testing. The reverse of my string is:: .gnitset rof reffuB gnirtS yM After deletion operation:: . reffuB gnirtS yM Try to understand the importance of String Buffer use.
8.3
Static Variables & Methods
As mentioned earlier, the keyword static is used to call a member method of a class without creating an instance of that class. Besides the main () method, it is also possible to declare any data member or method member of a class as static if we wish to access them without any object reference. Instance variables, declared as static in a class definition, will be treated as global variables. All instances of that class will share the same static variables. Initialization of the static variables can be carried out in a block marked as static {....} as shown in example8.11. Methods declared as static have several restrictions, such as – • • •
They can call only other static methods. They must only access static data. They cannot refer to this keyword in any way.
It is illegal to refer to any instance variables inside a static method. Static methods and variables can be used independently of any object. To call static method from outside of a class, one can use –
Classname.method(...) --- where Classname is the name of the class where the static method remains declared. This form is similar to non-static methods where reference is made in the form of objectname.method(). Just observe that in example- 8.11, the static method display () – defined in the class StaticDemo – is used directly by the class StaticBeauty without creating an object-instance. That is the beauty of a static method. In the similar way, static data can also be used directly from anywhere simply by specifying classname.variable_name. /* Example – 8.11 Independent Use of Static method */ public class StaticDemo { static int x =6; static int y, sum; static double z = 3.2; static int a = 54; static void display() { System.out.println (" value of a = " + a); System.out.println (" value of x = " + x); System.out.println (" value of x + a = " + sum); System.out.println (" value of y = " + y); System.out.println (" value of z = " + z); } static { y = x * x; sum = x + a; }
// static block
}
class StaticBeauty { public static void main( ) { StaticDemo.display(); // calling static display() method of StaticDemo class
} } If you run this program, the following display will appear on the terminal screen – value of a = 54 value of x = 6 value of x + a = 60 value of y = 36 value of z = 3.2
8.4
Concept of Packages & import statements
Java has a feature called packages, which helps in storing different class definitions (for re-use) in an orderly manner. Packages can be regarded as containers of related classes and interfaces [discussed in chapter 9 – section 6] avoiding any naming conflicts. You have already made use of packages like java.io [containing input output related classes], java.util [containing utility related classes], etc. The java language package, java.lang, gets automatically included with any java program; but to include other packages exclusive use of import statement becomes essential. You have already made use of such import statements like import java.util.*; import java.io.*; at the top of a java source code. The asterisk (*) indicates that all the classes of that package are to be imported. However any particular class of a package can also be included by specifying the class name as shown below:-import java.util.Vector;
// only Vector class is included
In addition to java’s own library packages, any programmer can create his/her own packages containing useful classes or interfaces for subsequent reuse. Suppose you want to develop bank-transaction software. The required classes like BalanceCheck, CashWithdraw, DepositAmount, etc. can be compiled and stored in a package to which you can give a name, say, Banking. Such a package can be included with any banking related program. That is the main advantage of packaging which can avoid name conflicts and help re-use very efficiently.
The *. class files generated by the compiler must be placed in a directory having the name same as that of the package. The *. class files for java.util package are stored under the directory util which is a sub-directory of the directory java. A java program may have the following four internal parts:-• • • •
A single package statement [ optional] Any number of import statements [ optional] A single public class declaration ( essentially required) Any number of classes private to the package [ optional]
In all previous examples, package statement has not been used although other three parts have been used in programs as per specific requirements. The general form of the package statement is – package <package_name>; Suppose you choose the package-name as MyPackage. In that case all the *.class files which are to be included as a part of MyPackage must be stored in a directory called MyPackage. Directory name must match exactly with the package name. The general form of a multileveled hierarchical package statement will be – package < pkg1.pkg2.pkg3>; Such a package hierarchy remains stored in a file system as pkg1\pkg2\pkg3 [in windows] or pkg1/pkg2/pkg3 [in Linux/Unix]. The CLASSPATH can also take care of the directories where you have stored your packages. 8.5 Conclusion This chapter deals with the Input/Output and other library classes available in the java packages. Special emphasis has been given on the methods available with input/output classes, String classes and StringBuffer classes. With suitable examples their uses have been demonstrated. The specialty of static variables and methods has also been explained. introduction to java’s package concept has been given.
A brief
It may not be out of place to mention that besides the packages already mentioned, java has many more packages like --java.net for networking applications,
java.awt and java.applet for window’s programming and applet manipulation and control, java.beans for software component building, java.rmi for remote method invocation, java.security for security functions, java.sql for database manipulation, etc. Discussions about all these advanced topics have been kept out of scope from a beginner’s book like this one. However, discussions about the uses of java.awt and java.applet classes for window’s programming will be made in chapter-12.