Java Core
Java Core
Java Core
Core Java offers a total immersion approach for C\C++ programmer wanting
to learn java. The course will use JDK(Java Development Kit) and covers all the new language features. This course inclues worked out examples illustrating new JDK features that are fully explained thoughout the course. Core Java has been carefully planned to help students create faster, smaller and more efficient Java application.
Java Evolution
Java History
Java is a general purpose , object-oriented programming language. The fastest growing programming language in the history of computing Developed by Sun Microsystems of USA in 1991. Originally it is called Oak by James Gosling. Originally designed in 1991 for use in embedded consumer applications Java team which headed James Gosling developed a Web browser called Hot Java to locate and run applet programs on Internet in 1994. Oak was renamed Java in 1995. Redesigned in early 1995 with Internet application capabilities Introduced in May, 1995 and immediately supported by the Netscape Web browser. Rapidly overtaking C++ in popularity among commercial software developers Java established itself not only as a leader for Internet programming but also as a general purpose, object-oriented programming language. Java found its home in the heart of the modern programmer. Java is the first programming language that is not tied to any particular hardware or operating system. Programs developed in java can be executed anywhere on any system. Therefore Java comes as a revolutionary technology because it has brought in a fundamental shift in how we develop and use programs.
Java Features
Simple:
Java is a simple language as it does not use pointers, preprocessor header files; go to statement and many more others.
In Java everything is object. All program code and data within objects and classes.
Object oriented:
Distributed:
Java is designed as a distributed language for creating applications on networks. It has ability to share both data and programs.
Interpreted:
Interpreting means actually compiling the program line by line and generates the machine code. Java interpreter generates machine code that can be directly executed by the machine is that running the Java program.
Robust:
Java is a robust language as it provides many safeguards to ensure reliable code. It has strict compile time and run time checking for data types.
No viruses can affect the Java program as Java ensures that program cannot gain access to memory locations without proper authorization. Java systems not only verify all memory access but also ensure that no viruses are communicated with an applet.
Secure:
Architecture-neutral:
In Java, changes and upgrade in operating system, processors and system resources will not force any changes in Java programs.
Java programs can be easily moved from one computer system to another, anytime, and anywhere. Java ensures portability in two ways. First, Java compiler generates bytecode instructions that can be implemented on any machin. Secondly the sizes of the primitive data type are machin-independent.
Portable:
High-performance:
Java performance is impressive for an interpreted language , mainly due to the use of intermediate bytecode.
Multithreaded:
Java is capable of dynamically linking in new class libraries, methods and objects.
Dynamic:
1. Platform-dependent Java Virtual Machine (JVM) software must be installed 2. A copy of the JVM is started 3. Each bytecode statement is interpreted (translated) by the JVM into platform-dependent machine language and executed under JVM control.
Java is also unusual in that each Java program is both compiled and interpreted. With a compiler, it translates a Java program into an intermediate language called Java bytecodes-the platform-independent codes interpreted by the Java interpreter. With an interpreter, each Java bytecode instruction is parsed and run on the computer. Compilation happens just once; interpretation occurs each time the program is executed. This figure show how it works.
The Java bytecodes is the machine code instructions for the Java Virtual Machine (Java VM). Every Java interpreter, whether it's a Java development tool or a Web browser that can run Java applets, is an implementation of the Java VM. The Java VM can also be implemented in hardware. Java bytecodes help make "write once, run anywhere" possible.
One can compile your Java program into bytecodes on any platform that has a Java compiler. The
The Java Virtual Machine (Java VM) The Java Application Programming Interface (Java API)
The Java VM is the base for the Java platform and is ported onto various hardware-based platforms. The Java API is a large collection of ready-made software components that provide many useful capabilities, such as graphical user interface (GUI) widgets. The Java API (application programming interface) is grouped into libraries (packages) of related components.
The below figure depicts a Java program, such as an application or applet, that's running on the Java platform. As the figure shows, the Java API and Virtual Machine insulates the Java program from hardware dependencies.
Windows 95 software A Windows-compatible sound card A hard drive; A CD-ROM drive A Microsoft-compatible mouse
Disadvantages of Java
Not supported by all platforms (though third-party JVM software is usually available) Slower in execution than compiled languages Restricts or prohibits machine-level operations required by certain applications (operating systems, etc.)
/** * The HelloWorldApp class implements an application that * simply displays "Hello World!" to the standard output. */ class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); //Display the string. }
class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); //Display the string. } } The Java language supports three kinds of comments:
/* The compiler ignores everything from /* to */. /** text */ */
documentation
This indicates a documentation comment (doc comment, for short). The compilerignores this kind of comment, just like it ignores comments that use /* and */. // The compiler ignores everything from // to the end of the line text
Defining a Class
The first bold line in the following listing begins a class definition block. /** * The HelloWorldApp class implements an application that * simply displays "Hello World!" to the standard output. */
class HelloWorldApp
{ public static void main(String[] args) { System.out.println("Hello World!"); //Display the string. } }
A class--the basic building block of an object-oriented language such as Java--is a template that describes the data and behavior associated with instances of that class. The data associated with a class or object is stored in variables; the behavior associated with a class or object is implemented with methods. Methods are similar to the functions or procedures in procedural languages such as C. In the Java language, the simplest form of a class definition is class name {
... }
The keyword class begins the class definition for a class named name. The variables and methods of the class are embraced by the curly brackets that begin and end the class definition block. The "Hello World" application has no variables and has a single method named main.
System.out.println("Hello World!"); //Display the string. } } Every Java application must contain a main method whose signature looks like this:
public static void main(String[] args)
The method signature for the main method contains three modifiers: public indicates that the main method can be called by any object. static indicates that the main method is a class method. void indicates that the main method doesn't return any value.
The main method in the Java language is similar to the main function in C and C++. When the Java interpreter executes an application (by being invoked upon the application's controlling class), it starts by calling the class's main method. The main method then calls all the other methods required to run your application. If you try to invoke the Java interpreter on a class that does not have a main method, the interpreter refuses to compile your program and displays an error message similar to this: In class NoMain: void main(String argv[]) is not defined
Here the main method accepts a single argument: an array of elements of type String.
/** * The HelloWorldApp class implements an application that * simply displays "Hello World!" to the standard output. */ class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); //Display the string. } }
Using a Class Method or Variable Let's take a look at the first segment of the statement:
System.out .println("Hello World!"); The construct System.out is the full name of the out variable in the System class.
Java Tokens
The smallest individual units in a program are known as TOKEN. A java program is a collection of tokens, comments and white spaces. Java language includes five types of tokens They are:
1) 2) 3) 4) 5)
Reserved Keyword
Keywords have specific meaning and implement Java language has reserved 60 words as keywords.
specific
features
of
the
language.
Identifiers
Identifiers are programmer-designed tokens. They are used methods, variables, objects, labels, packages, and interface in a program.
for
naming
class,
Literals
Literal is a programming language term that essentially means that what you type is what you get. Numbers, characters, and strings are all examples of literals.
Therefore literals 1) Are constants having no identifier? 2) Have their value specified within the program's source code? 3) Can only appear on the right side of an assignment operator (=) or within an expression? 4) Have a data type associated with them?
Integer literals
1. 2. 3. 4.
Represent an integer value Can be expressed in decimal (the default), octal (base 8, or hexadecimal (base 16) Are not enclosed in any special characters Are automatically int (32 bits) unless the suffix 'L' is appended to make it long (64 bits)
Floating-point literals
1. 2. 3. 4.
Represent a real number (having a decimal point) Can be expressed as a standard decimal value or in scientific notation Are not enclosed in any special characters Are automatically double (64 bits) unless the suffix 'F' is appended to make it float (32 bits)
char literals
1. 2. 3. 4.
Represent a single Unicode character (16 bits) Must be enclosed within single quotes (apostrophes) Are often associated with a single key stroke Can represent special characters ("escape sequences") used for device control
String literals
1. Represent a string of characters, such as "Java is fun" 2. Must be enclosed in double quotes 3. Are automatically stored as String class objects by the compiler. They will be covered later.
boolean literals
1. Can only have the value true or false 2. Can only be assigned to boolean variables
Constants
1. Are similar to variables but, once initialized, their contents may NOT be changed? 2. Are declared with the keyword final? 3. By convention, have all capital letters in their identifier. This makes them easier to see within the code.
Operators
An operator is a symbols that takes one or more arguments and operates on them to produce a result.
Separators
Separators are symbols used to indicate where groups of code are divided and arranged. They are basically define the shape and function of our code. Ex: {}, [], ; , . , () etc.
Instance variables, are used to define the attributes of a particular object. Class variables are similar to instance variables, except their values apply to all that class's instances (and to the class itself) rather than having different values for each object. Local variables are declared and used inside method definitions,
Although all three kinds of variables are declared in much the same ways, class and instance variables are accessed and assigned in slightly different ways from local variables. Java does not have global variables-that is, variables that are global to all parts of a program. Instance and class variables can be used to communicate global information between and among objects.
Declaring Variables
To use any variable in a Java program, we must first declare it. Variable declarations consist of a type and a variable name:
Variable definitions can go anywhere in a method definition (that is, anywhere a regular Java statement can go), although they are most commonly declared at the beginning of the definition before they are used:
public static void main (String args[]) { int count; String title; boolean isAsleep; ... }
We can string together variable names with the same type on one line:
int myAge, mySize, numShoes = 28; String myName = "eBIZ"; boolean isTired = true; int a = 4, b = 5, c = 6;
If there value
the the
one in the
initializer a same
variables
initializers
Variable Types
In addition to the variable name, each variable declaration must have a type, which defines what values that variable can hold.
eight a
primitive class
data or
types interface
Integer Type
There are four Java integer types, each with a different range All are signed, which means they can hold either positive or negative numbers. of values.
Floating-point type:
Floating-point numbers are used for numbers with a decimal part. There are two floating-point types: float (32 bits, single precision) and double (64 bits, double precision).
Char type:
The char type is used for individual characters. Because Java uses the Unicode character set, the char type has 16 bits of precision, unsigned.
Constants
Are similar to variables but, once initialized, their contents may NOT be changed? Are declared with the keyword final? By convention, have all capital letters in their identifier. This makes them easier to see within the code. Example 1: This program defines a number of constants and then displays some of their values.
public class App { public static void main(String[] args) { final final final final final final final boolean YES = true; char DEPOSIT_CODE = 'D'; byte INCHES_PER_FOOT = 12; int FEET_PER_MILE = 5280; float PI = 3.14F; double SALES_TAX_RATE = .06; String ADDRESS = "119 South Street";
Example 2: This program will not compile because an attempt is made to change the value of its constant.
final double SALES_TAX_RATE = .06; SALES_TAX_RATE = .04; // Display the sales tax rate System.out.println(SALES_TAX_RATE); } } Here the compiler error will occur like this
3;
In this expression, x and y are variables, 3 is a literal, and = and / are operators. This expression states operator (/), and the that the result is y variable is divided by 3 using the division stored in x using the assignment operator (=).
Operator Precedence
Java expressions are typically evaluated from left to right, there still are many times when the result of an expression would be indeterminate without other rules. The following expression illustrates the problem:
x = 2 * 6 + 16 / 4
By using the left-to-right evaluation of the expression, the multiplication operation 2 * 6 is carried out first, which leaves a result of 12. The addition operation 12 + 16 is then performed, which gives a result of 28. The division operation 28 / 4 is then performed, which gives a result of 7. Finally, the assignment operation x = 7 is handled, in which the number 7 is assigned to the variable x. But--it's wrong! The problem is that using a simple left-to-right evaluation of expressions can yield inconsistent results, depending on the order of the operators. The solution to this problem lies in operator precedence, which determines the order in which operators are evaluated. Every Java operator has an associated precedence. Following In is a list of all the all Java operators from a highest to lowest equal precedence. precedence.
the
operators in
The precedence level of each row decreases from top to bottom. This means that the [] operator has a higher precedence than the * operator, but the same precedence as the () operator.
[]
()
/ >> > !=
! %
Evaluation of expressions still moves from left to right, but only when dealing with operators that have the same precedence. Otherwise, operators with a higher precedence are evaluated before operators with a lower precedence. Knowing this, take another look at the sample equation:
x = 2 * 6 + 16 / 4
Before using the left-to-right evaluation of the expression, first look to see whether any of the operators have differing precedence. Here the multiplication (*) and division (/) operators both have the highest precedence, followed by the addition operator (+), and then the assignment operator (=). Because the multiplication and division operators share the same precedence, evaluate them from left to right. Doing this, we first perform the multiplication operation 2 * 6 with the result of 12. Then we perform the division operation 16 / 4, which results in 4. After performing these two operations, the expression looks like this:
x = 12 + 4;
Because the addition operator has a higher precedence than the assignment operator, we perform the addition operation 12 + 4 next, resulting in 16. Finally, the assignment operation x = 16 is processed, resulting in the number 16 being assigned to the variable x. As we can see, evaluating the expression using operator precedence yields a completely different result. Just to get the point across, take a look at another expression that uses parentheses for grouping purposes:
x = 2 * (11 - 7);
Without the grouping parentheses, we would perform the multiplication operation first and then the subtraction operation. However, referring back to the precedence list, the () operator comes before all other operators. So the subtraction operation 11 - 7 is performed first, yielding 4 and the following expression:
x = 2 * 4;
The rest of the expression is easily resolved with a multiplication operation and an assignment operation to yield a result of 8 in the variable x.
Integer Operators
There are three types of operations that can be performed on integers:
1. 2. 3. And relational. Unary Binary Both unary unary, binary,
act act
on on
single of typically
integer
Relational operators, act on two integer numbers but return a Boolean result rather than an integer. Unary and binary integer operators typically return an int type. For all operations involving the types byte, short, and int, the result is always an int. The only exception to this rule is when one of the operands is a long, in which case the result of the operation is also of type long.
Unary integer operators act on a single integer. Lists of the unary integer operators.
Operator
++ -~
The increment and decrement operators (++ and --) increase and decrease integer ariables by 1. These operators can be used in either prefix or postfix form. A prefix operator takes effect before the evaluation of the expression it is in; a postfix operator takes effect after the expression has been evaluated. Prefix unary operators are placed immediately before the variable; postfix unary operators are placed immediately following the variable. Following are examples of each type of operator:
y = ++x; z = x--;
In the first example, x is prefix incremented, which means that it is incremented before being assigned to y. In the second example, x is postfix decremented, which means that it is decremented after being assigned to z. Here z is assigned the value of x before x is decremented. The IncDec program, which uses both types of operators.
The IncDec class. class IncDec { public static void main (String args[])
{ int x = 8, y = 13; System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("++x = " + ++x); System.out.println("y++ = " + y++); System.out.println("x = " + x); System.out.println("y = " + y); } } The IncDec program produces the following results: x=8 y = 13 ++x = 9 y++ = 13 x=9 y = 14
Output
The negation unary integer operator (-) is used to change the sign of an integer value.
x = 8; y = -x;
In this example, x is assigned the literal value 8 and then is negated and assigned to y. The resulting value of y is -8.
The Negation class. class Negation { public static void main (String args[]) { int x = 8; System.out.println("x = " + x); int y = -x; System.out.println("y = " + y); } }
Output
The bitwise complement operator (~), which performs a bitwise negation of an integer value. Bitwise negation means that each bit in the number is toggled. In other words, all the binary 0s become 1s and all the binary 1s become 0s. Example:
x = 8; y = ~x;
In this example, x is assigned the literal value 8 again, but it is bitwise complemented before being assigned to y. Well, without getting into the details of how integers are stored in memory, it means that all the bits of the variable x are flipped, yielding a decimal result of -9. This result has to do with the fact that negative numbers are stored in memory using a method known as two's complement.
NOTE: Integer numbers are stored in memory as a series of binary bits that can each have a value of 0 or 1. A number is considered negative if the highest-order bit in the number is set to 1. Because a bitwise complement flips all the bits in a number--including the high-order bit--the sign of a number is reversed.
The Bitwise Complement class. class BitwiseComplement { public static void main (String args[]) { int x = 8; System.out.println("x = " + x); int y = ~x; System.out.println("y = " + y); } }
Output
Binary Integer Operators
Binary integer operators act on pairs of integers. Lists of the binary integer operators.
Operator
+ * / % & | ^ << >> >>>
The Arithmetic program, which shows how the basic binary integer arithmetic operators work.
The Arithmetic class. class Arithmetic { public static void main (String args[]) { int x = 17, y = 5; System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("x + y = " + (x + y));
Output
The bitwise AND, OR, and XOR operators (&, |, and ^) all act on the individual bits of an integer. These operators are sometimes useful when an integer is being used as a bit field.
The Bitwise class. class Bitwise { public static void main (String args[]) { int x = 5, y = 6; System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("x & y = " + (x & y)); System.out.println("x | y = " + (x | y)); System.out.println("x ^ y = " + (x ^ y)); } } The output of running Bitwise follows: x y x x x =5 =6 &y=4 |y=7 ^y=3
In Bitwise, the variables x and y are set to 5 and 6, which correspond to the binary numbers 0101 and 0110. The bitwise AND operation compares each bit of each number to see whether they are the same. It then sets the resulting bit to 1 if both bits being compared are 1; it sets the resulting bit to 0 otherwise. The result of the bitwise AND operation on these two numbers is 0100 in binary, or decimal 4. The bitwise OR operator sets the resulting bit to 1 if either of the bits being compared is 1. For these numbers, the result is 0111 binary, or 7 decimal.
Finally, the bitwise XOR operator sets resulting bits to 1 if exactly one of the bits being compared is 1 and 0 otherwise. For these numbers, the result is 0011 binary, or 3 decimal. The left-shift, right-shift, and zero-fill-right-shift operators (<<, >>, and >>>) shift the individual bits of an integer by a specified integer amount.
Following are some examples of how these operators are used: x << 3; y >> 7; z >>> 2;
In the first example, the individual bits of the integer variable x are shifted to the left three places. In the second example, the bits of y are shifted to the right seven places. Finally, the third example shows z being shifted to the right two places, with zeros shifted into the two leftmost places.
The Shift class. class Shift { public static void main (String args[]) { int x = 7; System.out.println("x = " + x); System.out.println("x >> 2 = " + (x >> 2)); System.out.println("x << 1 = " + (x << 1)); System.out.println("x >>> 1 = " + (x >>> 1)); } } The output of Shift follows: x x x x =7 >> 2 = 1 << 1 = 14 >>> 1 = 3
Output
The number being shifted in this case is the decimal 7, which is represented in binary as 0111. The first right-shift operation shifts the bits two places to the right, resulting in the binary number 0001, or decimal 1. The next operation, a left-shift, shifts the bits one place to the left, resulting in the binary number 1110, or decimal 14. The last operation is a zero-fill-right-shift, which shifts the bits one place to the right, resulting in the binary number 0011, or decimal 3.
Description
Operator
These operators all perform comparisons between integers. The Relational class class Relational { public static void main (String args[]) { int x = 7, y = 11, z = 11; System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("z = " + z); System.out.println("x < y = " + (x < y)); System.out.println("x > z = " + (x > z)); System.out.println("y <= z = " + (y <= z)); System.out.println("x >= y = " + (x >= y)); System.out.println("y == z = " + (y == z)); System.out.println("x != y = " + (x != z)); } } The output of running Relational follows: x= 7 y = 11 z = 11 x < y = true x > z = false y <= z = true x >= y = false y == z = true x != y = true
unary, binary,
only on floating-point
on pairs
single of
operators
Relational
operators,
act
on
two
floating-point
numbers
but
return
boolean
result.
Unary and binary floating-point operators return a float type if both operands are of type float. If one or both of the operands are of type double, however, the result of the operation is of type double.
The unary floating point operators act on a single floating-point number. Lists of the unary floatingpoint operators.
Operator
++ --
The only two unary floating-point operators are the increment and decrement operators. These two operators respectively add and subtract 1.0 from their floating-point operand.
The binary floating-point operators act on a pair of floating-point numbers. Lists of the binary floating-point operators.
Operator
+ * / %
The binary floating-point operators consist of the four traditional binary operations (+, -, *, /), along with the modulus operator (%).
The FloatMath class. class FloatMath { public static void main (String args[]) { float x = 23.5F, y = 7.3F; System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("x + y = " + (x + y)); System.out.println("x - y = " + (x - y)); System.out.println("x * y = " + (x * y)); System.out.println("x / y = " + (x / y)); System.out.println("x % y = " + (x % y)); } } The output of FloatMath follows:
x y x x x x x
Boolean Operators
Operator
& | ^ && || ! == != ?:
The evaluation operators (&, |, and ^) evaluate both sides of an expression before determining the result. The following code shows how the evaluation AND operator is necessary for the complete evaluation of an expression:
while ((++x < 10) && (++y < 15)) { System.out.println(x); System.out.println(y); }
The three boolean operators--negation, equal-to, and not-equal-to (!, ==, and !=) The negation operator toggles the value of a boolean from false to true or from true to false, depending on the original value. The equal-to operator simply determines whether two boolean values are equal (both true or both false). Similarly, the not-equal-to operator determines whether two boolean operands are unequal. The conditional boolean operator (? :) is the most unique of the boolean operators This operator also is known as the ternary operator because it takes three items: a condition and two expressions. The Condition syntax ? for the conditional : operator follows: Expression2
Expression1
The Condition, which itself is a boolean, is first evaluated to determine whether it is true or false. If Condition evaluates to a true result, Expression1 is evaluated. If Condition ends up being false, Expression2 is evaluated.
The Conditional class class Conditional { public static void main (String args[]) { int x = 0; boolean isEven = false; System.out.println("x = " + x); x = isEven ? 4 : 7; System.out.println("x = " + x); } } The results of the Conditional program follow: x=0 x=7
String Operator
There is only one string operator for strings works strings together. operator: the very similarly concatenation operator (+). The concatenation to the addition operator for numbers--it adds
The Concatenation class class Concatenation { public static void main (String args[]) { String firstHalf = "What " + "did "; String secondHalf = "you " + "say?"; System.out.println(firstHalf + secondHalf); } } The output of Concatenation follows:
What did you say?
In the Concatenation program, literal strings are concatenated to make assignments to the two string variables, firstHalf and secondHalf, at time of creation. The two string variables are then concatenated within the call to the println() method.
Assignment Operators
Assignment operators actually work with all the fundamental data types.
Description
Simple Addition Subtraction Multiplication Division Modulus AND OR XOR Examples: = += -= *= /= %= &= |= ^=
Operator
x += 6; x *= (y - 3);
In the first example, x and 6 are added and the result stored in In the second example, 3 is subtracted from y and the result is multiplied by The final result is then stored in x x. x.
Operator
+= -= *= /= %=
Operation
Addition assignment Subtraction assignment Multiplication assignment Division assignment Modulo (remainder) assignment
Example: This program reads a percentage value from the user (such as 5.5) and converts to the correct decimal equivalent (such as 0.055) by using the division assignment operator.
import java.util.*; import java.io.*; public class AppStr { public static void main(String[] args) { // Variable for holding a percentage entered by the user // Prompt for and read the percentage System.out.print("Enter a percentage in n.nn format: "); double percent; Scanner Keyboard = new Scanner(System.in); percent = Keyboard.nextDouble(); //percent = Keyboard.readDouble(); // Convert it to its decimal equivalent and display the result
Conversions
Conversion is performed automatically when mixed numeric types appear within an expression. Variables and constants are not altered, but their values are copied to intermediate areas of larger size or precision to prevent possible data loss during the calculation. This is known as a "widening" conversion. The order of conversion (from narrowest to widest) is as follows. Memorize this table!
The data type resulting from an expression is that of the largest or most precise variable or constant appearing in the expression but is never smaller than int. Example: This program to convert a fahrenheit temperature to celsius will NOT compile.
import java.util.*; import java.io.*; public class Conversion { public static void main(String[] args) { // Variables for holding fahrenheit and celsius temperatures float tempC; // Prompt for and read the fahrenheit temperature System.out.print("Enter the fahrenheit temperature (nn.n): "); Scanner Keyboard=new Scanner(System.in); double tempF; tempF= Keyboard.nextDouble(); // Convert to celsius and display the result tempC = 5 * (tempF - 32) / 9;
To fix the compile error in this code, tempC must be double or tempF must be float . After Correction changing the tempC into double the result is.....
Casts
1. Are a programmer's way of telling the compiler to ignore possible loss of data or precision that might result from a conversion? 2. Should be used with caution. Data loss is not to be taken lightly. 3. The general syntax is
import java.util.*; import java.io.*; public class Application { public static void main(String[] args) { // Variables for holding fahrenheit and celsius temperatures float tempC; // Prompt for and read the fahrenheit temperature System.out.print("Enter the fahrenheit temperature (nn.n): "); Scanner Keyboard=new Scanner(System.in); double tempF; tempF=Keyboard.nextDouble(); // Convert to celsius and display the result tempC = (float) (5 * (tempF - 32) / 9); System.out.println("Celsius equivalent is " + tempC); } }
Arithmetic expressions can be large and complex with several variables, constants, and operators. The order in which operations are performed is the same as in mathematics (multiplication and division first, then addition and subtraction, working from left to right). To avoid confusion, good programmers keep their expressions as simple as possible and use parenthesis for clarity.
Boolean expressions
1. Always result in a boolean value (either true or false) 2. Are used to resolve logic questions, such as determining if two variables have the same value? 3. May contain several different operators?
Comparison operators
1. Used to compare the values of two variables or constants 2. Require that the two operands be either both numeric (including char) or both boolean. A numeric value cannot be compared to a boolean value. 3. Frequently appear in if, for, while, and do-while statements (to be covered later)
Operator
< <= > >= == != Less than
Operation
Less than or equal Greater than Greater than or equal Equal Not equal
Example: This program reads two numeric values from the user and displays the result of several comparisons involving the two numbers.
import java.util.*; import java.io.*; public class Aman { public static void main(String[] args) { // Variables for holding two numeric values entered by the user int x; double y; // Prompt for and read the two numeric values System.out.print("First number (integer): "); Scanner Keyboard=new Scanner(System.in); int x; x=Keyboard.nextInt((); System.out.print("Second number (floating-point): "); Scanner Keyboard=new Scanner(System.in); double y; y=Keyboard.nextDouble(); // Display information comparing the two values System.out.println(" System.out.println(" System.out.println(" System.out.println(" " " " " + + + + x x x x + + + + " " " " <" <= >" >= +y+" "+y+ +y+" "+y+ is " " is is " " is + (x "<" y)); " + (x <= y)); + (x > y)); " + (x >= y));
System.out.println(" " + x + " == " + y + " is " + (x == y)); System.out.println(" " + x + " != " + y + " is " + (x != y)); } }
Logical operators
1. Combine the results of two Boolean expressions into a single boolean value 2. Provide for complex logic. The following table shows the operators and how they can be used to combine the results of two Boolean expressions X and Y:
Operator
& | ^ && ||
Operation
AND OR XOR (exclusive OR) Conditional AND Conditional OR
The conditional AND ( && ) and OR ( || ) are sometimes called "short-circuit" operators because the second operand is not always evaluated depending on the value of the first operand. If the first operand is false, the result of an AND will always be false regardless of the value of the second operand. If the first operand is true, the result of an OR will always be true regardless of the value of the second operand. Example: The following program uses two values entered by the user to determine if a customer is entitled to free shipping. A customer receives free shipping if their order amount is greater than or equal to 100 and they are a preferred customer.
import java.util.*; import java.io.*; public class Aman { public static void main(String[] args) { // Variables for holding order amount and valued customer data to be // entered by the user // Variables for holding information about free shipping boolean isFree; // Prompt for and read order amount and valued customer data System.out.print("Order amount (floating-point): "); Scanner Keyboard= new Scanner(System.in); double amount; amount =Keyboard.nextDouble(); System.out.print("Valued customer? (Y)es or (N)o: "); Char valuedCust; valuedCust = Keyboard.nextChar(); // Determine and display information about free shipping. // Shipping is free if the order amount is greater than or equal $100 // AND the customer is a valued customer.
isFree = (amount >= 100 && (valuedCust == 'Y' || valuedCust == 'y')); System.out.println(" Free shipping? " + isFree); } }
Example: The following program reads a boolean value from the user and displays its opposite value.
public class AppCer { public static void main(String[] args) { // Variable for holding a boolean value entered by the user boolean value; // Prompt for and read the boolean value System.out.print("Enter a boolean value (true or false): "); value = Keyboard.readBoolean(); // Determine the opposite value. If the value is false, XOR with // true results in true. If the value is true, XOR with true results // in false. value ^= true; // Display the new value of the value. System.out.println(" The opposite value is " + value); } }
***try this yourself
Bitwise operations
Bitwise operations act upon individual bits within integer data. They are used to perform the logical operations AND, OR, and XOR (eXclusive OR), complementing (reversing all bits), and shifting (sliding bits to the left or right).
Rule
If both corresponding operand bits are "on" the result bit is "on" If either corresponding operand bit is "on" the result bit is "on" If corresponding operand bits are different the result bit is "on"
if byte a = 17; // Binary value: 0001 0001 Hex value: 11 byte b; after executing the statement b = (byte) ~a;
variable b will have a value of -18 (because 0001 0001 reverses to 1110 1110). Once again, the cast is needed in order to store the int value that results from the operation. Example: The following program can be run to test complement operations.
import java.util.*; import java.io.*; public class Aman { public static void main(String[] args) { // Variable to be read from the user // Prompt for and read an integer value System.out.print("Integer: "); Scanner Keyboard=new Scanner(System.in); int number; number=Keyboard.nextInt(); // Display the result of complementing the number System.out.println(" ~" + number + " = " + ~number); } }
They are an essential part of Java "flow control" by which execution may proceed along alternate logic paths within a program.
The if statement
1. Identifies a single statement or a block of statements to be executed if an expression evaluates to true. 2. Have two forms. The general syntax is either of the following:
The first form is often referred to as a "single statement if". For example,
if (amountDue > 0) System.out.println("You owe " + amountDue); else System.out.println("You owe nothing");
will add to the grand total and display how much is owed if amountDue is greater than zero. Otherwise, the customerRating will be set to 'A' and the "You owe nothing" message will be displayed. The two logic paths are mutually exclusive and merge at the first statement after the end of the else block. 4) Can trap programmers who get sloppy. For example,
Nesting
It is An if or an if-else can be coded within an if or an if-else. Example: permitted.
import java.util.*; import java.io.*; public class Aman { public static void main(String[] args) { System.out.print("Enter age: "); Scanner Keyboard= new Scanner(System.in); int age; age=Keyboard.nextInt(); if (age >= 10) { if (age < 65)
{ System.out.println("$5 admission"); } else { System.out.println("$4 admission"); } } else { if (age < 5) { System.out.println("Free admission"); } else { System.out.println("$2 admission"); } } } }
Notes: 1. The program prompts for and reads a person's age from the user. 2. Based upon the value of age, it displays a different admission fee (under 5 is free, 5-17 is 2 dollars, 18-64 is 5 dollars, and 65 and over is 4 dollars).
Switch statements
Flow control with if and else statements gets cumbersome when a variable must be tested for a large number of possible values, such as a menu selection that permits the user to enter an integer from 1 to 20. The solution to this problem is the switch statement.
switch (expression) { case value1: statements; break; case value2: statements; break; default: statements;
break; }
It has a number subtleties and restrictions: 1. The switch expression must be a primitive of type int or able to be promoted to int. Specifically, it must be either byte, short, int, or char. Expressions of type boolean, long, float, and double will not compile. 2. The value specified on a case must be a constant of type int or must be able to be promoted to int (in other words a byte, short, int, or char). It must also be within the possible range of values of the switch expression. For example, if the switch variable is a byte, a case with a value of 200 would not compile because a byte may only have a value from -128 to 127. The value of a case may be an expression as long as the result is a constant. For example, case 5 + 1: would compile successfully. 3. The break statement is optional and will be covered in more detail in a later lesson. When encountered, it ends the execution of the switch statement. If omitted from a case, processing falls through to the next case (a sometimes undesirable result). 4. Although the compiler doesn't care, cases should be arranged in a high probability to low probability order to enhance processing efficiency. The default can be placed anywhere (even first). It may be nested. A switch can be coded within another switch or in either leg of an if-else. It can also contain if-else code. Example:
import java.util.*; import java.io.*; import java.lang.*; public class Aman { public static void main(String[] args) { // Variables // Prompt for and read data System.out.print("Enter customer's starting balance: "); Scanner Keyboard=new Scanner(System.in); Double balance; balance = Keyboard.readDouble(); System.out.print("Enter transaction amount: "); double amount; amount = Keyboard.readDouble(); System.out.println("Transaction codes are"); System.out.println(" " + "C - charge"); System.out.println(" " + "P - payment"); System.out.println(" " + "R - refund or return"); System.out.print("Enter transaction code: "); char code; code = Keyboard.readChar(); // Process based upon transaction code
switch (code) { case 'C': case 'c': balance += amount; System.out.println("New balance is " + Utility.moneyFormat(balance)); break; case 'P': case 'p': balance -= amount; System.out.println("New balance is " + Utility.moneyFormat(balance)); break; case 'R': case 'r': balance -= amount; System.out.println("New balance is " + Utility.moneyFormat(balance)); break; default: System.out.println("Invalid transaction code"); break; } } }
1. The balance, code, and amount variables hold data entered by the user. 2. After all data has been read from the user, the transaction is processed by the switch statement with the transaction code (code) used as the switch expression. 3. Within the switch, if the value of code matches the value of a particular case, processing jumps to the statement block for that case, otherwise processing jumps to the statement block for the default. Processing will then continue until either a break statement is encountered or the end of the switch is reached. 4. Stacking two or more cases without at break statement constitutes an OR. For example,
initialization - represents the declaration of one or more local variables of the same data type. When loop processing is complete, all such variables are destroyed. condition - represents a binary expression that, if true, allows the loop to continue. The condition
is tested prior to each iteration. If no longer true, processing continues at the first statement after the closing brace of the for loop.
update - represents one or more expressions to be executed at the end of each iteration.
The braces may be omitted if the loop consists of a single statement. This would constitute a "single statement for loop". Example 1: Counting to 10 with a local variable
Counting to 10 without a local variable int i = 1; for (; i <= 10; i++) System.out.println(i); System.out.println("Now i is " + i);
Here loop control variable i is initialized outside the loop, it will not be destroyed when the loop completes. Its final value (which will be 11) is displayed by the statement after the loop. Notice that when no initialization expression is coded, a place holding semicolon is still required. Example 3: Coding multiple initialization and update expressions
for (int i = 1, j = 10; i <= 10; i++, j--) System.out.println(i + " x " + j + " = " + (i * j));
This loop initializes two local variables, i and j, of the same data type before the first iteration. At the end of each iteration, i is incremented and j is decremented. Within each iteration, the product
of i and j is displayed. Notice that commas are used to separate multiple initialization and update expressions. It can be nested. For example, the following program generates a simple 9 x 9 multiplication table:
import java.io.*; public class Aman { public static void main(String[] args) { // This outer loop generates one row of the multiplication // table during each iteration. for (int row = 1; row <= 9; row++) { // This inner loop generates one column of the current row // of the multiplication table during each iteration. for (int column = 1; column <= 9; column++) { // If a one digit number is about to be displayed, preceed it // with four spaces. Otherwise, preceed it with three spaces. if ((row * column) < 10) { System.out.print(" "); } else { System.out.print(" "); } // Display the number. System.out.print((row * column)); } // End the current line. System.out.print(" "); } } }
true, processing continues at the first statement after the closing brace of the while loop. The braces may be omitted if the loop consists of a single statement. This would constitute a "single statement while loop". 1) It does not provide for initialization of variables or automatic update expressions. In spite of these limitations, a while loop can be used in place of nearly any for loop as shown by these examples: Example 1: Counting to 10 without a local variable
import java.io.*; public class Aman { public static void main(String[] args) { // Initialize the row number. int row = 1; // This outer loop generates one row of the multiplication // table during each iteration. while (row <= 9) { // Initialize the column number. int column = 1; // This inner loop generates one column of the current row // of the multiplication table during each iteration. while (column <= 9) { // If a one digit number is about to be displayed, preceed it // with four spaces. Otherwise, preceed it with three spaces.
if ((row * column) < 10) { System.out.print(" "); } else { System.out.print(" "); } // Display the number. System.out.print((row * column)); // Increment the column number. column++; } // End the current line. System.out.print(" "); // Increment the row number. row++; } } }
is still less than or equal to 10. If so, the body of the loop is repeated. Otherwise processing will jump to the next statement. Example 2: An endless loop
import java.io.*; public class Aman { public static void main(String[] args) { // Initialize the row number. int row = 1; // This outer loop generates one row of the multiplication // table during each iteration. do { // Initialize the column number. int column = 1; // This inner loop generates one column of the current row // of the multiplication table during each iteration. do { // If a one digit number is about to be displayed, preceed it // with four spaces. Otherwise, preceed it with three spaces. if ((row * column) < 10) { System.out.print(" "); } else { System.out.print(" "); } // Display the number. System.out.print((row * column)); // Increment the column number. column++; } while (column <= 9); // End the current line.
System.out.print(" "); // Increment the row number. row++; } while (row <= 9); } }
for (int x = 0; x < 10; x++) { if (x == 5) break; else System.out.print(" " + x); }
will end prematurely when x takes on a value of 5. The output displayed will be:
01234
3) It may specify the label of the loop to be abandoned. This makes it possible to abandon a specific loop. For example,
outer: for (int i = 1; i <= 5; i++) { for (int j = 5; j >= 1; j--) { if (i == j) break outer; else System.out.println("i = " + i + ", j = " + j); } }
will end the outer loop when i equals j. The output displayed will be:
i i i i
= = = =
1, 1, 1, 1,
j j j j
= = = =
5 4 3 2
4) It causes an immediate exit from a switch, skipping any remaining code. For example, if key is a char variable having a value entered by the user, the following statements will display whether they entered an 'A' or a 'B':
switch (key) { case 'a': case 'A': System.out.println("You entered an 'A'"); break; case 'b': case 'B': System.out.println("You entered a 'B'"); break; default: System.out.println("You did not enter an 'A' or a 'B'"); break; }
for (int x = 0; x < 10; x++) { if (x == 5) continue; else System.out.print(" " + x); }
will short-circuit when x takes on a value of 5. The output displayed will be:
012346789
3)It may specify the label of the loop to be continued. This makes it possible to skip to the next iteration of the specified loop. For example,
outer: for (int i = 1; i <= 5; i++) { for (int j = 5; j >= 1; j--) { if (i == j) continue outer; else System.out.println("i = " + i + ", j = " + j); } }
will short-circuit to the next iteration of the loop labeled outer when i equals j. The output displayed will be:
i = 1, j = 5
i i i i i i i i i
= = = = = = = = =
1, 1, 1, 2, 2, 2, 3, 3, 4,
j j j j j j j j j
= = = = = = = = =
4 3 2 5 4 3 5 4 5
Defining Classes
To define a class, we use the class keyword and the name of the class:
Following is the code for a class called SimplePoint that represents a point in 2D space:
Ex:
class SimpleRectangle int width = 0; int height = 0; SimplePoint origin = new SimplePoint();
Here the segment of code declares a class SimpleRectangle-- that contains two integer members, width and height. SimpleRectangle also contains a third member, origin, whose data type is SimplePoint. Here the class name SimplePoint is used in a variable declaration as the variable's type. We can use the name of a class anywhere we can use the name of a primitive type. As with SimplePoint, when we create a new SimpleRectangle object, space is allocated for the object and its members, and the members are initialized according to their declarations. The initialization for the origin member creates a SimplePoint object with this code: new SimplePoint() as illustrated here:
This diagram shows the difference between primitive types and reference types
public class Rectangle { public int width = 0; public int height = 0; public Point origin; // four constructors public Rectangle() { origin = new Point(0, 0); } public Rectangle(Point p) { origin = p; } public Rectangle(int w, int h) { this(new Point(0, 0), w, h); } public Rectangle(Point p, int w, int h) { origin = p; width = w; height = h; } // a method for moving the rectangle public void move(int x, int y) { origin.x = x; origin.y = y; } // a method for computing the area of the rectangle public int area() { return width * height; } // clean up! protected void finalize() throws Throwable { origin = null; super.finalize(); }
}
Here the four constructors allow for different types of initialization.
Object
An object is a distinct instance of its class (an actual occurrence). It has its own set of variables (known as "instance variables") and methods (known as "instance methods"). When called, an object's instance methods automatically act upon its instance variables Java program creates many objects from a variety of classes. These objects interact with one another by sending each other messages. Through these object interactions, a Java program can implement a GUI, run an animation, or send and receive information over a network. Once an object has completed the work for which it was created, it is garbage-collected and its resources are recycled for use by other objects.
Creating Objects
In Java, we create an object by creating an instance of a class or, in other words, instantiating a class.
Ex:
The above single statement performs three actions: 1. Declaration: Rectangle rect is a variable declaration that declares to the compiler that the name rect will be used to refer to a Rectangle object. Here a class name is used as the variable's type. 2. Instantiation: new is a Java operator that creates the new object (allocates space for it). 3. Initialization: Rectangle() is a call to Rectangle's constructor, which initializes the object.
Declaring an Object
Like other variable declarations, object declarations can also appear alone, like this: Rectangle rect; Declarations notify the compiler that you will use name to refer to a variable whose type is type. Declarations do not create new objects. Rectangle rect does not create a new Rectangle object, just a variable named rect to hold a Rectangle object. To create a Rectangle object, or any other object, use the new operator.
Instantiating an Object
The new operator instantiates a class by allocating memory for a new object of that type. new requires a single, postfix argument: a call to a constructor. Each Java class provides a set of constructors used to initialize new objects of that type. The new operator creates the object, and the constructor initializes it. Here's an example of using the new operator to create a Rectangle object:
Here, Rectangle(100, 200) is the argument to new. The new operator returns a reference to the newly created object. This reference can be assigned to a variable of the appropriate type, as here.
Initializing an Object
The classes can provide one or more constructors to initialize a new object of that type. We can recognize a class's constructors because they have the same name as the class and have no return type. Here are the declarations for Rectangle's constructors:
If a class has multiple constructors, they all have the same name but a different number of arguments or different typed arguments. The compiler differentiates the constructors, and knows which one to call, depending on the arguments.
Using Objects
Java provides an access control mechanism whereby classes can restrict or allow access to its variables and methods. A class should protect variables against direct manipulation by other objects if those manipulations could endanger the object's state. State changes should then be affected and therefore controlled by method calls.
objectReference.variable
The first part of the variable's name, objectReference, must be a reference to an object.
The notation used to call an object's method is similar to that used when referring to its variables: we append the method name to an object reference with an intervening period (.). Also, we provide any arguments to the method within enclosing parentheses. If the method does not require any arguments, use empty parentheses.
objectReference.methodName(argumentList); or objectReference.methodName();
Creating Classes
The diagram lists the class and identifies the structure of the code.
public
The public modifier declares that the class can be used by any class regardless of its package.
abstract
final
The class keyword indicates to the compiler that this is a class declaration and that the name of the class is NameOfClass.
extends Super
The extends clause identifies Super as the superclass of the class, thereby inserting the class within the class hierarchy
implements Interfaces
To declare that our class implements one or more interfaces, use the keyword implements followed by a comma-delimited list of the names of the interfaces implemented by the class
Variables and methods collectively are called members. Constructors are not methods. Nor are they members.
private
No other class can instantiate our class. Our class may contain public class methods (sometimes called factory methods), and those methods can construct an object and return it, but no other classes can.
protected
public
package
Only classes within the same package as our class can construct an instance of it. Constructors provide a way to initialize a new object.
Implementing Methods
Methods
1. Are named modules of code 2. May optionally receive one or more parameters (arguments) 3. May optionally return a single value 4. Are associated with either a class or an object of a class. The former are called "class methods" and are the focus of this lesson. The latter are called "instance methods" and will be covered in a later lesson.
class-name.method-name(arguments)
If the method is defined within the current class, the class name may be omitted and the general syntax for the call expression is:
method-name(arguments)
Can occur anywhere the returned data type makes sense. Methods that return no value are called in a stand-alone statement. Methods that return a value are called within another expression. This method pushes an object, the one passed in as an argument, onto the top of the stack, and returns it.
Like a class, a method has two major parts: 1. method declaration 2. And method body.
The method declaration defines all of the method's attributes, such as access level, return type, name, and arguments, as illustrated here:
The method body is where all the action takes place. It contains the Java instructions that implement the method.
At minimum, a method declaration has a name and a return type indicating the data type of the value returned by the method:
We declare a method's return type in its method declaration. Within the body of the method, we use the return operator to return the value. Any method that is not declared void must contain a return statement. The Stack class declares the isEmpty method, which returns a boolean:
The data type of the return value must match the method's return type; we can't return an Object type from a method declared to return an integer. The isEmpty method returns either the boolean value true or false, depending on the outcome of a test. The isEmpty method returns a primitive type. Methods also can return a reference type. For example, Stack declares the pop method that returns the Object reference type:
public synchronized Object pop() { int len = items.size(); Object obj = null; if (len == 0)
throw new EmptyStackException(); obj = items.elementAt(len - 1); items.removeElementAt(len - 1); return obj; }
A Method's Name
Java supports method name overloading so that multiple methods can share the same name.
For example
class DataRenderer { void draw(String s) { ... } void draw(int i) { ... } void draw(float f) { ... } }
Overloaded methods are differentiated by the number and type of the arguments passed into the method. In the code sample, draw(String s) and draw(int i) are distinct and unique methods because they require different argument types. We cannot declare more than one method with the same name and the same number and type of arguments because the compiler cannot differentiate them. So, draw(String s) and draw(String t) are identical and result in a compiler error. A class may override a method in its superclass. The overriding method must have the same name, return type, and parameter list as the method it overrides.
Sample programs
The following small samples will help us understand how easy it is to use the class methods of the Math class:
public class AppMath { public static void main(String[] args) { double x; char again; do { Utility.separator(50, '~'); System.out.print("Enter a number: "); x = Keyboard.readDouble(); Utility.skip(); System.out.println(" Ceiling = " + Math.ceil(x)); System.out.println(" Floor = " + Math.floor(x)); System.out.println(" Rounded = " + Math.round(x)); System.out.println(" Squared = " + Math.pow(x, 2)); System.out.println(" Square root = " + Math.sqrt(x)); Utility.skip(); System.out.print("Again? (Y/N): "); again = Keyboard.readChar(); }
Introduction
This array consists of five elements where each is an integer value (217, 138, 92, 12, and 168).
To access a particular element within an array, its corresponding index (offset) is used. For example, the integer value at index location 3 within this array is 12. Notice that the indexes are zero based because the offset of the first element is always zero (you don't have to skip over any other elements to get there). While all programming languages include the ability to process arrays, Java provides enhanced integrity and other features not found in other languages.
Java arrays
Java array require that all elements be of the same data type.
For example, We may create an array of char values, or an array of float values, or an array of boolean values, etc...
Java array are objects and must be declared like one. The general syntax is as follows:
Using either technique, it is important to understand what is created. The following diagram may help:
The array reference (myArray) can be thought of as pointing to the array whose elements reside on the memory heap. Notes: 1. At the time an array reference is declared, it initially contains null (it doesn't point to anything). It doesn't receive a value until an array is assigned to it. 2. An array reference can only be assigned an array of the correct type. In the above example, myArray is declared to be a reference to an int array, so only an array of int values can ever be assigned to it. To attempt otherwise will result in a compile error. 3. An array reference may be reused to point to a different array (of the appropriate type). Like all objects, however, an array that can no longer be r eferenced will be garbage collected. 4. When instantiated, all array elements are automatically initialized to binary zeros. This means all elements of numeric arrays will be zero, all elements of boolean arrays will be false, and all elements of char arrays will be the null character.
Java array can be constructed from a value list. This is an alternative construction technique as shown by
Java array permit an element to be accessed via its unique index. For example,
The following expression will reference the third element (an int with a value of 3)
numbers[2]
Notes: 1. An index must be int or able to be widened to int to avoid a compile error. It may not be boolean, long, float, or double. 2. If an index is negative of exceeds the maximum valid index for the array, a runtime error occurs. The JVM will throw an ArrayIndexOutOfBoundsException. Catching and processing such exceptions is a topic in advanced Java.
Java array have a publicly available length field. This is an int constant representing the number of elements within the array. It is extremely useful when coding a loop to process all the elements within an array. For example, The following small program creates an array, loads it with some random numbers, and displays the array's contents:
public class AppArr { public static void main(String[] args) { double[] values = new double[10]; for (int i = 0; i < values.length; i++) { values[i] = Math.random(); } for (int i = 0; i < values.length; i++) { System.out.println(values[i]); } } }
Notes: 1. In an array object, length is a field and NOT a method. A common mistake is to code length() as you would with a String or StringBuffer object and get a compile error. 2. Because the for loops are limited by the length of the array, the code is very flexible. Changing the number of elements in the array declaration is all that is needed to work with a different sized array.
Object arrays
Object array are declared with the class name as the type. For example
Constructs an array of 5 String object references. It is important to understand that no String objects are created by this declaration. We have simply created an array of null object references which may later be assigned to individual String objects (as shown by the following diagram).
The statement
To display the value of this particular String object, one might code
System.out.println(names[3]);
which retrieves the String object referenced by the fourth element in the names array. Object array are arrays of object references. Each element is either the reference of an instantiated object or is null. The general syntax to access an instance method of the object being referenced is
array-identifier[index].method-name(arguments)
For example, To determine the length of the encapsulated string in the fourth element of the names array one would code the expression
names[3].length()
Object array can result in runtime errors if improperly used. In addition to an ArrayIndexOutOfBoundsException, it is possible for a NullPointerException to occur if an attempt is made to reference an object when the object reference is null. Example: Attempting to call an instance method of an object that doesn't exist.
public class AppObj { public static void main(String[] args) { String[] names = new String[5]; System.out.println("Length of first string: " + names[0].length()); } }
Object array can be constructed from a value list. This requires the instantiation or the existence of the objects to be referenced by each array element. For example,
creates a three element array of String object references. The first element references a String object having the value " abc ", the second element references a String object having the value " def ", and the third references the String object in the literal pool having the value " xyz ".
Strings
A sequence of character data is called a string and is implemented in the Java environment by the String class (a member of the java.lang package). The character-counting program uses Strings in two different places. The first is in the definition of the main() method:
String[] args
This code explicitly declares an array, named args, that contains String objects. The empty brackets indicate that the length of the array is unknown at compilation time because the array is passed in at runtime. The second use of Strings in the example program is these two uses of literal strings (a string of characters between double quotation marks " and "):
At this point, enough memory has been allocated to contain the String references, but no memory has been allocated for the Strings themselves. If we attempted to access one of arrayOfStrings elements at this point, we would get a NullPointerException because the array is empty and contains no Strings and no String objects. We have to allocate the actual String objects separately:
for (int i = 0; i < arrayOfStrings.length; i ++) { arrayOfStrings[i] = new String("Hello " + i);
objects are immutable--that is, they cannot be changed once they've been created. The java.lang package provides a different class, StringBuffer, which we can use to create and manipulate character data on the fly.
String Concatenation
Java lets us concatenate strings together easily using the + operator. The example program uses this feature of the Java language to print its output. The following code snippet concatenates three strings together to produce its output:
Two of the strings concatenated together are literal strings: "Input has " and " chars." The third string--the one in the middle--is actually an integer that first gets converted to a string and then is concatenated to the others.
Inheritance
Introduction
Inheritance is a concept in object-oriented programming where all classes are arranged in a strict hierarchy. Each class in the hierarchy has superclasses (classes above it in the hierarchy) and any number of subclasses (classes below it in the hierarchy). Subclasses inherit attributes and behavior from their superclasses In Java, as in object-oriented programming languages, classes can be derived from other classes. The derived class (the class that is derived from another class) is called a subclass. The class from which its derived is called the superclass.
In fact, in Java, all classes must be derived from some class. The top-most class, the class from which all other classes are derived, is the Object class defined in java.lang. Object is the root of a hierarchy of classes.
The subclass inherits state and behavior in the form of variables and methods from its superclass. The subclass can just use the items inherited from its superclass as is, or the subclass can modify or override it.
Definition:
A subclass is a class that derives from another class. A subclass inherits state and behavior from all of its ancestors.
Creating Subclasses
For example,
suppose that we wanted to create a subclass named SubClass of another class named SuperClass. We would write:
This declares that SubClass is the subclass of the Superclass class. It also implicitly declares that SuperClass is the superclass of SubClass. A subclass also inherits variables and methods from its superclass's superclass, and so on up the inheritance tree. A Java class can have only one direct superclass. Java does not support multiple inheritance. Creating a subclass can be as simple as including the extends clause in your class declaration.
That is, subclasses 1. inherit those member variables declared as public or protected 2. inherit those member variables declared with no access specifier as long as the subclass is in the same package as the superclass. These variables are sometimes known as "friendly". 3. don't inherit a superclass's member variable if the subclass declares a member variable using the same name. The subclass's member variable is said to hide the member variable in the superclass. 4. don't inherit private member variables
Consider this superclass and subclass pair: class Super { Number aNumber; } class Sub extends Super { Float aNumber; }
The aNumber variable in Sub hides aNumber in Super. But we can access aNumber from the superclass with:
super.aNumber
super is a Java language keyword that allows a method to refer to hidden variables and overriden methods of the superclass.
Rule:
A subclass inherits all of the methods within its superclass that are accessible to that subclass (unless the method is overriden by the subclass).
That is, subclasses 1. inherit those methods declared as public or protected 2. inherit those methods declared with no access specifier as long as the subclass is in the same package as the superclass 3. don't inherit a superclass's method if the subclass declares a method using the same name. The method in the subclass is said to override the one in the superclass. 4. don't inherit private methods
Overriding Methods
A subclass can either completely override the implementation for an inherited method or the subclass can enhance the method by adding functionality to it.
ABSTRACT CLASSES
Abstract classes are those which can be used for creation of objects. However their methods and constructors can be used by the child or extended class. The need for abstract classes is that you can generalize the super class from which child classes can share its methods. The subclass of an abstract class which can create an object is called as "concrete class".
Following is an example
Abstract class A { abstract void method1(); void method2() { System.out.println("this is concrete method"); } } class B extends A { void method1() { System.out.println("B is implementation of method1"); } } class demo { public static void main(String arg[]) { B b=new B(); b.method1(); b.method2(); } }
Interfaces
An interface is a collection of method names, without definitions, that can be added to classes to provide additional behavior not included with those methods the class defined itself or inherited from its superclasses. The problem with multiple inheritance is that it makes a programming language far more complex to learn, to use, and to implement. A Java interface is a collection of abstract behavior that can be mixed into any class to add to that class behavior that is not supplied by its superclasses. Specifically, a Java interface contains nothing but abstract method definitions and constants-no instance variables and no method implementations. Interfaces are implemented and used throughout the Java class library whenever a behavior is expected to be implemented by a number of disparate classes. The Java class hierarchy, for example, defines and uses the interfaces java.lang.Runnable java.util.Enumeration, java.util.Observable, java.awt.image.ImageConsumer, and java.awt.image.ImageProducer.
Interfaces, like classes, are declared in source files, one interface to a file. Like classes, they also are compiled using the Java compiler into .class files. Interfaces complement and extend the power of classes, and the two can be treated almost exactly the same. One of the few differences between them is that an interface cannot be instantiated: new can only create an instance of a class.
// java.applet.Applet is the superclass public class Neko extends java.applet.Applet implements Runnable { // but it also has Runnable behavior ... }
After our class implements an interface, subclasses of our class will inherit those new methods (and can override or overload them) just as if our superclass had actually defined them. If your class inherits from a superclass that implements a given interface, we don't have to include the implements keyword in your own class definition. Example-
interface Fruitlike { void decay(); void squish(); ... } class Fruit implements Fruitlike { private Color myColor; private int daysTilIRot; ... } interface Spherelike { void toss(); void rotate(); ... } class Orange extends Fruit implements Spherelike { . . . // toss()ing may squish() me (unique to me) }
Here the class Orange doesn't have to say implements Fruitlike because, by extending Fruit, it already has! Other Example-
class Sphere implements Spherelike { // extends Object private float radius; ... } class Orange extends Sphere implements Fruitlike { . .// users of Orange never need know about the change! }
public class Neko extends java.applet.Applet implements Runnable, Eatable, Sortable, Observable { ... }
public interface Growable { public abstract void growIt(); //explicity public and abstract void growItBigger(); // effectively public and abstract }
In addition to methods, interfaces can also have variables, but those variables must be declared public, static, and final (making them constant). As with methods, we can explicitly define a variable to be public, static, and final. Here's that same Growable definition with two new variables:
public static final int increment = 10; long maxnum = 1000000; // becomes public static and final public abstract void growIt(); //explicitly public and abstract void growItBigger(); // effectively public and abstract }
Interfaces, like classes, can belong to a package by adding a package statement to the first line of the class file. Interfaces can also import other interfaces and classes from other packages, just as classes can.
public class Orange extends Fruit { public germinate(Fruitlike self) { Orange theOrange = (Orange)self; ... } }
Extending Interfaces
When one interface inherits from another interface, that "subinterface" acquires all the method definitions and constants that its "superinterface" defined. To extend an interface, we use the extends keyword just as you do in a class definition:
In multiply inherited interfaces, the rules for managing method name conflicts are the same as for classes that use multiple interfaces; methods that differ only in return type will result in a compiler error.
Package
Introduction
Java provides a powerful means of grouping related classes and interfaces together in a single unit: packages Packages are groups of related classes and interfaces. Packages provide a convenient mechanism for managing a large group of classes and interfaces while avoiding potential naming conflicts.
They allow us to organize your classes into units. Just as we have folders or directories on your hard disk to organize your files and applications, packages allow us to organize your classes into groups so that we only use what we need for each program. They reduce problems with conflicts in names. As the number of Java classes grows, so does the
likelihood that we'll use the same class name as someone else, opening up the possibility of naming clashes and errors if you try to integrate groups of classes into a single program. Packages allow you to "hide" classes so that conflicts can be avoided. They allow you to protect classes, variables, and methods in larger ways than on a class-by-class basis, as you learned yesterday. we'll learn more about protections with packages later today. They can be used to identify your classes. For example, if you implemented a set of classes to perform some purpose, we could name a package of those classes with a unique identifier that identifies you or your organization. The Java API itself is implemented as a group of packages.
Declaring Packages
The syntax for the package statement:
package Identifier;
This statement must be placed at the beginning of a compilation unit (a single source file), before any class declarations. Every class located in a compilation unit with a package statement is considered part of that package Packages can be nested within other packages. When this is done, the Java interpreter expects the directory structure containing the executable classes to match the package hierarchy.
Importing Packages
The import statement enables us to import classes from other packages into a compilation unit. We can import individual classes or entire packages of classes at the same time if we want. The syntax for the import statement follows:
import Identifier;
Identifier is the name of the class or package of classes we are importing. Other Example:
import java.*;
This statement doesn't work because we can't import nested packages with the * specification. This wildcard works only when importing all the classes in a particular package, which is still very useful.
There is one other way to import objects from other packages: explicit package referencing. By explicitly referencing the package name each time we use an object, we can avoid using an import statement. Using this technique, the declaration of the color member variable look like this:
java.awt.Color color;
The first step is to decide what the name of our package is going to be. The name we choose for our package depends on how we are going to be using those classes. Step two in creating packages is to create a directory structure on our disk that matches the package name. If your package has just one name (mypackage), we'll only have to create a directory for that one name. If the package name has several parts, however, we'll have to create directories within directories. For the package name edu.nonsense.eng.fooblitzky, we'll need to create an edu directory and then create a nonsense directory inside edu, an eng directory inside nonsense, and a fooblitzky directory inside eng. Our classes and source files can then go inside the fooblitzky directory.
The Java language package, also known as java.lang, contains classes that are core to the Java language. The classes in this package are grouped as follow:
Object
The grand-daddy of all classes--the class from which all others inherit.
A collection of classes used to wrap variables of a primitive data type: Boolean, Character, Double, Float, Integer and Long. Each of these classes are subclasses of the abstract class Number.
Strings
Two classes that implement character data. is a thorough lesson on the use of both types of strings.
These two classes provide let your programs use system resources. System provides a systemindependent programming interface to system resources and Runtime gives you direct systemspecific access to the runtime environment.
Threads
The Thread, ThreadDeath and ThreadGroup classes implement the multi-threading capabilities so
important to the Java language. The java.lang package also defines the Runnable interface. Runnable makes it convenient for Java class to be active without subclassing the Thread class.
Classes
The Class class provides a runtime description of a class and the ClassLoader class allows you to load classes into your program during runtime.
Math
When an error occurs in a Java program, the program throws an object which indicates what the problem was and the state of the interpreter when the error occurred. Only objects that derive from the Throwable class can be thrown. There are two main subclasses of Throwable: Exception and Error. Exceptions are a form of Throwable that "normal" programs may try to catch. Errors are used for more catastophic errors--normal programs should not catch errors. The java.lang package contains the Throwable, Exception and Error classes, and numerous subclasses of Exception and Error that represent specific problems.
Processes
Process objects represent the system process that is created when you use Runtime to execute system commands. The java.lang packages defines and implements the generic Process class.
The compiler automatically imports this package for us. No other packages are automatically imported.
AWT Package
The java.awt package provides GUI elements used to get input from and display information to the user such as windows, buttons, scrollbars, and text items.
The java.awt.image package contains classes and interfaces for managing image data, such as setting the color model, cropping, color filtering, setting pixel values, and grabbing snapshots of the screen.
The java.awt.peer package contains classes and interfaces that connect platform-independent AWT components to their platform-dependent implementation (such as Motif widgets or Microsoft Windows controls).
Multithreading
Introduction:
Multithreading is a fundamental feature of the Java language specification. The creators of Java understood the importance of multithreading and provided easy to use features for application developers. Two of these features, the Thread class and the Runnable interface, will be covered shortly. Multithreading is not the same as multiprocessing. The latter involves the use of two or more processors (CPUs). Multithreading involves the sharing of a single processor and the interleaving of CPU time as shown by the following diagram:
Because there is only one processor, only one instruction can be executed at a time. In a Java program, the decision as to which thread is currently executing is determined by the JVM. Multithreading is used to execute even the simplest Java program. Even if a program doesn't create its own threads, the Java Virtual Machine creates multiple threads to support the program. One thread performs the processing of the main() method. Other threads manage and monitor system resources. The garbage collector, for example, is always running as a low-priority thread.
Thread
A thread--sometimes known as an execution context or a lightweight process--is a single sequential flow of control within a process.
Definition:
A thread is a single sequential flow of control within a program Example: The following program is a simple Java application that creates and starts two independent threads:
class TwoThreadsTest { public static void main (String[] args) { new SimpleThread("Jamaica").start(); new SimpleThread("Fiji").start(); } } class SimpleThread extends Thread { public SimpleThread(String str) { super(str); } public void run() { for (int i = 0; i < 10; i++) { System.out.println(i + " " + getName()); try { sleep((int)(Math.random() * 1000)); } catch (InterruptedException e) { } } System.out.println("DONE! " + getName()); } }
A thread is similar to the sequential programs described above: a single thread also has a beginning, an end, a sequence, and at any given time during the runtime of the thread there is a single point of execution. The HotJava Web browser is an example of a multithreaded application. Within the HotJava browser we can scroll a page while it's downloading an applet or image, play animation and sound concurrently, print a page in the background while we download a new page, or watch three sorting algorithms race to the finish.
Thread Attributes
Java threads are implemented by the Thread class, which is part of the java.lang package. The Thread class implements a system independent definition of Java threads. But under the hood, the actual implementation of concurrent operation is provided by a system-specific implementation.
In Java, all threads are objects that are constructed, pass between several "states", and die in
1. When initially constructed, the thread is New 2. When all resources the thread requires are available, it enters the Ready state. The thread is ready to use the CPU. 1. When selected by the JVM for processing, the thread enters the Running state. This is the state that all threads aspire to but only one is ever running at an instant in time. 2. When the thread requests to sleep for an interval of time, must wait for a resource (such as completion of I/O), or is suspended by the JVM, it becomes Blocked. It gives up the CPU and will return to the Ready state when the block is removed. 3. When the thread completes its processing or is killed by the JVM, it enters the Dead state. The thread object will still exist, but will no longer be allowed to use the CPU.
All of the action takes place in the thread's body--the thread's run() method. We can provide the body to a Thread in one of two ways: a. by subclassing the Thread class and overriding its run() method, b. by creating a Thread with a Runnable object as its target.
Thread Body
The application in which an applet is running calls the applet's start() method when the user visits the applet's page. The Clock applet creates a Thread, clockThread, in its start() method and starts the thread.
public void start() { if (clockThread == null) { clockThread = new Thread(this, "Clock"); clockThread.start(); } }
First, the start() method checks to see if clockThread is null. If clockThread is null, then the applet has just been loaded or has been previously stopped and a new thread must be created. Otherwise, the applet is already running. The applet creates a new thread with this invocation:
constructed in this way, the clock thread gets its run() method from its target Runnable object--in this case, the Clock applet. The second argument is just a name for the thread. After a thread has been created and initialized, the runtime system calls its run() method. The code in the run() method implements the behavior for which the thread was created.
When we leave the page that displays the Clock applet, the application in which the applet is running calls the applet's stop() method. The Clock's stop() method sets the clockThread to null. This tells the main loop in the run() method to terminate eventually resulting in the thread stopping and being garbage collected.
And finally the Clock's run() method implements the heart of the Clock applet and looks like this:
public void run() { // loop terminates when clockThread is set to null in stop() while (Thread.currentThread() == clockThread) { repaint(); try { Thread.sleep(1000); } catch (InterruptedException e) { } } }
Thread State
Throughout its life, a Java thread is in one of several states. A thread's state indicates what the Thread is doing and what it is capable of doing at that time of its life: is it running? Is it sleeping? Is it dead?
The above diagram illustrates the various states that a Java thread can be in at any point during its life. It also illustrates which method calls cause a transition to another State.
New Thread
The following statement creates a new thread but does not start it, thereby leaving the thread in the "New Thread" state.
When a thread is in the "New Thread" state, it is merely an empty Thread object. No system resources have been allocated for it yet. Thus when a thread is in this state, we can only start the thread or stop it. Calling any method besides start() or stop() when a thread is in this state makes no sense and causes an IllegalThreadstateException.
Runnable
Not Runnable
A thread enters the "Not Runnable" state when one of these four events occurs: 1. Someone invokes its sleep() method. 2. Someone invokes its suspend() method. 3. The thread uses its wait() method to wait on a condition variable. 4. The thread is blocking on I/O. For example, The bold line in the following code snippet puts the current thread to sleep for 10 seconds (10,000 milliseconds):
try
Dead
A thread can die in two ways: either from natural causes, or by being killed (stopped). A thread dies naturally when its run() method exits normally. For example, The while loop in this method is a finite loop--it will iterate 100 times and then exit.
public void run() { int i = 0; while (i < 100) { i++; System.out.println("i = " + i); }}
A thread with this run() method will die naturally after the loop and the run() method completes. We can also kill a thread at any time by calling its stop() method. The following code snippet creates and starts myThread then puts the current thread to sleep for 10 seconds. When the current thread wakes up, the bold line in the code segment kills myThread.
The stop() method throws a ThreadDeath object at the thread to kill it. Thus when a thread is killed in this manner it dies asynchronously. The thread will die when it actually receives the ThreadDeath exception.
IllegalThreadStateException
The runtime system throws an IllegalThreadStateException when we call a method on a thread and that thread's state does not allow for that method call.
For example, IllegalThreadStateException is thrown when we invoke suspend() on a thread that is not "Runnable".
A final word about thread state: the programming interface for the Thread class includes a method called isAlive(). The isAlive() method returns true if the thread has been started and not stopped. Thus, if the isAlive() method returns false we know that the thread is either a "New Thread" or "Dead". If the isAlive() method returns true, we know that the thread is either "Runnable" or "Not Runnable". We cannot differentiate between a "New Thread" and a "Dead" thread; nor can we differentiate between a "Runnable" thread and a "Not Runnable" thread.
Thread Priority
A thread's priority tells the Java thread scheduler when this thread should run in relation to other threads.
Some points 1. Most computers have only one CPU, thus threads must share the CPU with other threads. The execution of multiple threads on a single CPU, in some order, is called scheduling. The Java runtime supports a very simple, deterministic scheduling algorithm known as fixed priority scheduling. 2. Each Java thread is given a numeric priority between MIN_PRIORITY and MAX_PRIORITY (constants defined in class Thread). At any given time, when multiple threads are ready to be executed, the thread with the highest priority will be chosen for execution. Only when that thread stops, or is suspended for some reason, will a lower priority thread start executing. 3. Scheduling of the CPU is fully preemptive. If a thread with a higher priority than the currently executing thread needs to execute, the higher priority thread is immediately scheduled. 4. The Java runtime will not preempt the currently running thread for another thread of the same priority. In other words, the Java runtime does not time-slice. However, the system implementation of threads underlying the Java Thread class may support time-slicing. Do not write code that relies on time-slicing. 5. In addition, a given thread may, at any time, give up its right to execute by calling the yield() method. Threads can only yield the CPU to other threads of the same priority--attempts to yield to a lower priority thread are ignored. 6. When all the "Runnable" threads in the system have the same priority, the scheduler chooses the next thread to run in a simple, non-preemptive, round-robin scheduling order.
Daemon Threads
Daemon threads are those that provide a service for other threads in the system. Any Java thread can be a daemon thread.
Thread Group
All threads belong to a thread group. ThreadGroup, a java.lang class, defines and implements the capabilities of a group of related threads. The ThreadGroup class manages groups of threads for Java applications. A ThreadGroup can contain any number of threads. The threads in a group are generally related in some way, such as who created them, what function they perform, or when they should be started and stopped. ThreadGroups can contain not only threads but also other ThreadGroups. The top most thread group in a Java application is the thread group named "main". We can create threads and thread groups in the "main" group. We can also create threads and thread groups in subgroups of "main" and so on.
The ThreadGroup class has methods that can be categorized as follows: 1. Collection management Method:-methods that manage the collection of threads and subgroups contained in the thread group. 2. Method that Operate on the Group:-these methods set or get attributes of the ThreadGroup object. 3. Method that Operate on All Threads within a Group --this is a set of methods that perform some operation, such as start or resume, on all the threads and subgroups within the ThreadGroup. 4. Access Restriction Methods:-ThreadGroup and Thread allow the security manager to restrict access to threads based on group membership.
The ThreadGroup provides a set of methods that manage the threads and subgroups within the group and allow other objects to query the ThreadGroup for information about its contents.
For example, You can call ThreadGroup's activeCount() method to find out the number of active threads currently in the group. The activeCount() method is often used with the enumerate() method to get an array filled with references to all the active threads in a ThreadGroup. For example, The listCurrentThreads() method in the following example fills an array with all of the active threads in the current thread group and prints their names:
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup(); int numThreads; Thread[] listOfThreads; numThreads = currentGroup.activeCount(); listOfThreads = new Thread[numThreads]; currentGroup.enumerate(listOfThreads); for (int i = 0; i < numThreads; i++) { System.out.println("Thread #" + i + " = " + listOfThreads[i].getName()); } } }
Other collection management methods provided by the ThreadGroup class include activeGroupCount() and list().
The following is a list of ThreadGroup methods that operate at the group level: 1. getMaxPriority(), and setMaxPriority() 2. getDaemon(), and setDaemon() 3. getName() 4. getParent(), and parentOf() 5. toString() So for example, when we use setMaxPriority() to change a group's maximum priority, we are only changing the attribute on the group object; we are not changing the priority of any of the threads within the group.
Consider this small program that creates a group and a thread within that group:
class MaxPriorityTest { public static void main(String[] args) { ThreadGroup groupNORM = new ThreadGroup( "A group with normal priority"); Thread priorityMAX = new Thread(groupNORM, "A thread with maximum priority"); // set Thread's priority to max (10) priorityMAX.setPriority(Thread.MAX_PRIORITY); // set ThreadGroup's max priority to normal (5) groupNORM.setMaxPriority(Thread.NORM_PRIORITY); System.out.println("Group's maximum priority = " + groupNORM.getMaxPriority()); System.out.println("Thread's priority = " + priorityMAX.getPriority());
} }
When the ThreadGroup groupNORM is created, it inherits its maximum priority attribute from its parent thread group. In this case, the parent group priority is the maximum (MAX_PRIORITY) allowed by the Java runtime system. Next the program sets the priority of the priorityMAX thread to the maximum allowed by the Java runtime system. Then the program lowers the group's maximum to the normal priority (NORM_PRIORITY). The setMaxPriority() method does not affect the priority of the priorityMAX thread, so that at this point, the priorityMAX thread has a priority of 10 which is greater than the maximum priority of its group groupNORM. This is the output from the program:
As we can see a thread can have a higher priority than the maximum allowed by its group as long as the thread's priority is set before the group's maximum priority is lowered. A thread group's maximum priority is used to limit a thread's priority when the thread is first created within a group or when you use setPriority() to change the thread's priority. Note that setMaxPriority() does change the maximum priority of all of its sub-threadgroups.
The ThreadGroup class has three methods that allow us to modify the current state of all the threads within that group: 1. resume() 2. stop() 3. suspend() These methods apply the appropriate state change to every thread in the thread group and its subgroups.
This is a list of the methods in the Thread class that call checkAccess() before proceeding: 1. constructors that specify a thread group 2. stop() 3. suspend()
4. 5. 6. 7.
We can define and implement our own access restrictions for thread groups by subclassing SecurityManager, overriding the appropriate methods, and installing it as the current security manager in our application.
public synchronized int get() { while (available == false) { try { wait(); } catch (InterruptedException e) { } } available = false; notifyAll(); // notifies Producer return contents; }
In the above example the Producer/Consumer example, the Consumer thread calls the get() method, so the Consumer thread holds the monitor during the execution of get(). At the end of the get() method, the call to notifyAll() wakes up the Producer thread that is waiting to get the monitor. Now, the Producer thread can get the monitor and proceed. If multiple threads are waiting for a monitor, the Java runtime system chooses one of the waiting threads to run, making no commitments or guarantees about which thread will be chosen.
The wait() method causes the current thread to wait (possibly forever) until another thread notifies it of a condition change. We use wait() in conjunction with notify() or notifyAll() to coordinate the activities of multiple threads using the same resources.
Example:
public synchronized int get() { while (available == false) { try { wait(); // waits for notifyAll() call from Producer } catch (InterruptedException e) {
wait(long timeout)
waits for notification or until the timeout period has elapsed--timeout is measured in milliseconds.
Exception Handling
Introduction
Errors are a normal part of programming. Some of these errors are flaws in a program's basic design or implementation--these are called bugs. Other types of errors are not really bugs; rather, they are the result of situations like low memory or invalid filenames.
The way we handle the second type of error determines whether they become bugs. Java's exception-handling mechanism lets us handle errors without forcing us to spend most of our energy worrying about them.
What Is an Exception?
As the name implies, an exception is an exceptional condition. An exception is something out of the ordinary. Most often, exceptions are used as a way to report error conditions. Exceptions provide notification of errors and a way to handle them. This control structure allows us to specify exactly where to handle specific types of errors.
If Exceptions than?
The most common means of error checking is the function's return value. Consider the problem of calculating the retail cost of an item and displaying it. For this example, the retail cost is twice the wholesale cost:
1. try a block of code that may result in an exception being "thrown" 2. Code one or more blocks designed to automatically catch and handle a specific type of exception if one occurs. At most, only one of these blocks can be called in a single pass through the code. If none of the specified exceptions occurs, none of the blocks will be executed. 3. Optionally code a block that will finally be run in ALL situations, whether an exception occurs or not
try { statements that may result in an exception being thrown; } catch (exception-type1 reference) {
statements to handle the exception; } catch (exception-type2 reference) { statements to handle the exception; } other catch blocks... finally { statements to be ALWAYS executed; }
Example: The following is a modified version of the "shell game" program presented earlier. It contains a try block and two catch blocks. One handles a NullPointerException and the other handles an ArrayIndexOutOfBoundsException. No finally block is specified, so logic comes together after the end of the last catch block.
public class AppExcep { public static void main(String[] args) { // Loop control variable. char again = 'y'; // Main loop. One array is entered and processed in each iteration. while (again == 'Y' || again =='y') { // Instantiate a three element array and load a single String // at a random element location. String[] strings = new String[3]; int randomIndex = (int) ((Math.random()*100) % strings.length); strings[randomIndex] = "Lucky"; // Ask the user to guess the element location. Utility.separator(50, '>'); System.out.print("Pick a number from 1 to " + strings.length + ": "); // "Try" to read their response, use it to index into the array, // and see if they win. try { // If they guess the element location, display a message. Otherwise, // an exception will occur. if (strings[Keyboard.readInt() - 1].equals("Lucky")) { Utility.skip(); System.out.println(" YOU WIN!!!"); } }
// This block is automatically executed if a NullPointerException // occurs to indicate a null array location. catch (NullPointerException err) { Utility.skip(); System.out.println(" Empty shell - YOU LOSE!!!"); } // If an ArrayIndexOutOfBoundsException occurs, this block is // automatically executed. It indicates an invalid number was // used as an index. catch (ArrayIndexOutOfBoundsException err) { Utility.skip(); System.out.println(" Invalid number - YOU LOSE"); } // Ask the user if they want to do it again and repeat the loop as // requested. Utility.separator(40, '='); System.out.print("Again? (Y/N): "); again = Keyboard.readChar(); } } }
Some Terminology
Exception handling can be viewed as a nonlocal control structure. When a method throws an exception, its caller must determine whether it can catch the exception. If the calling method can catch the exception, it takes over and execution continues in the caller. Java exceptions are class objects subclassed from java.lang.Throwable. Because exceptions are class objects, they can contain both data and methods. In fact, the base class Throwable implements a method that returns a String describing the error that caused the exception. This is useful for debugging and if we want to give users a meaningful error message.
Throw an Exception
The method instantiates an object of type Exception. The Exception constructor takes a String parameter. The string contains a message that can be retrieved when the exception is caught. The throw statement terminates the method and gives its caller the opportunity to catch it:
if( correct > total ) { throw new Exception( "Invalid values" ) ; } if ( (float)correct / (float)total > 0.70 ) { returnCode = true ; } return returnCode ; }
To respond to an exception, the call to the method that produces it must be placed within a try block. A try block is a block of code beginning with the try keyword followed by a left and right curly brace. Every try block is associated with one or more catch blocks. Here is a try block:
import java.io.* ; import java.lang.Exception ; public class gradeTest { public static void main( String[] args ) { try { // the second call to passingGrade throws // an excption so the third call never // gets executed System.out.println( passingGrade( 60, 80 ) ) ; System.out.println( passingGrade( 75, 0 ) ) ; System.out.println( passingGrade( 90, 100 ) ) ; } catch( Exception e ) { System.out.println( "Caught exception --" + e.getMessage() ) ; }
} static boolean passingGrade( int correct, int total ) throws Exception { boolean returnCode = false ; if( correct > total ) { throw new Exception( "Invalid values" ) ; } if ( (float)correct / (float)total > 0.70 ) { returnCode = true ; } return returnCode ; } }
The second call to passingGrade() fails in this case because the method checks to see whether the number of correct responses is less than the total responses. When passingGrade() throws an exception, control passes to the main() method. In the example, the catch block in main() catches the exception and prints Caught exception - Invalid values.
try { // method calls go here } catch( SomeExceptionClass e ) { // handle SomeExceptionClass exceptions here } catch( SomeOtherExceptionClass e ) { // handle SomeOtherExceptionClass exceptions here }
When an exception is thrown in the try block, it is caught by the first catch block of the appropriate type. A method that ignores exceptions thrown by the method it calls.
import java.io.* ; import java.lang.Exception ; public class MultiThrow { public static void main( String[] args ) { try { fool() ; } catch( Exception e ) { System.out.println( "Caught exception " + e.getMessage() ) ; } }
static void fool() throws Exception { bar() ; } static void bar() throws Exception { throw new Exception( "Who cares" ) ; } }
In the example main() calls fool() which calls bar(). Because bar() throws an exception and doesn't catch it, fool() has the opportunity to catch it. The fool() method has no catch block, so it cannot catch the exception. In this case, the exception propagates up the call stack to fool()'s caller, main(). A method that catches and rethrows an exception.
import java.io.* ; import java.lang.Exception ; public class MultiThrowA { public static void main( String[] args ) { try { fool() ; } catch( Exception e ) { System.out.println( "Caught exception " + e.getMessage() ) ; } } static void fool() throws Exception { try { bar() ; } catch( Exception e ) { System.out.println( "Re throw exception -- " + e.getMessage() ) ; throw e ; } } static void bar() throws Exception { throw new Exception( "Who cares" ) ; } }
The fool() method calls bar(). The bar() method throws an exception and fool() catches it. In the example, fool() simply rethrows the exception, which is ultimately caught in the application's main() method. In a real application, fool() could do some processing and then rethrow the exception. This arrangement allows both fool() and main() to handle the exception.
import java.io.* ; import java.lang.Exception ; public class MultiThrowFin { public static void main( String[] args ) { try { alpha() ; } catch( Exception e )} { System.out.println( "Caught exception " ) ; } finally() { System.out.println( "Finally. " ) ; } } }
In normal execution (that is, when no exceptions are thrown), the finally block is executed immediately after the try block. When an exception is thrown, the finally block is executed before control passes to the caller. If alpha() throws an exception, it is caught in the catch block and then the finally block is executed. If alpha() does not throw an exception, the finally block is executed after the try block. If any code in a try block is executed, the finally block is executed as well.
public class Throwable { public Throwable() ; public Throwable(String message) ; public String getMessage() public String toString() ; public void printStackTrace() ; public void printStackTrace( java.io.PrintStream s) ; private native void printStackTrace0( java.io.PrintStream s); public native Throwable fillInStackTrace(); }
Java exceptions are Throwable objects (they are instances of Throwable or a subclass of Throwable). The Java packages contain numerous classes that derive from Throwable and thus, build a hierarchy of Throwable classes.
Types of Exceptions
The methods of the Java API and the language itself also throw exceptions. These exceptions can be divided into two classes: Exception and Error. Both the Exception and Error classes are derived from Throwable. Exception and its subclasses are used to indicate conditions that may be recoverable. Error and its subclasses indicate conditions that are generally not recoverable and that should cause your applet to terminate. The various packages included in the Java Development Kit throw different kinds of Exception and Error exceptions, as described in the following sections.
java.awt Exceptions
Classes of the AWT data transfer package may throw this exception: UnsupportedFlavorException (data in improper format)
java.awt.datatransfer Exception
java.beans Exceptions
The classes of the java.beans package throw the following exceptions: IntrospectionException (unable to resolve object during introspection) PropertyVetoException (illegal property change)
java.io Exceptions
The classes in the java.io package throw a variety of exceptions, Any classes that work with I/O are good candidates to throw recoverable exceptions. For example, activities such as opening files or writing to files are likely to fail from time to time. The classes of the java.io package do not throw errors at all.
java.lang Exceptions
The java.lang package contains much of the core Java language. The exceptions subclassed from RuntimeException do not have to be declared in a method's throws clause. These exceptions are considered normal because nearly any method can throw them.
The classes of java.lang.reflect throw the following exception: InvocationTargetException (invoked method has thrown an exception)
java.lang.reflect Exception
java.net Exceptions
The java.net package handles network communications. Its classes most often throw exceptions to indicate connect failures and the like.
The Java Remote Method Invocation classes allow Java objects to exist on remote machines. These classes throw the following error: ServerError (remote server indicates error)
java.rmi Error
java.rmi Exceptions
Java objects whose methods are invoked remotely through RMI may throw exceptions.
java.rmi.server Exceptions
java.security Exceptions
The Java security API allows users to implement security features in Java. The API includes support for digital signatures, data encryption, key management, and access control.
java.security.acl Exceptions
The Java security access control list API allows Java developers to control access to specific
users. The classes of java.security.acl throw the following exceptions: ACLNotFoundException (unable to find access control list) LastOwnerExcepti (attempt to delete last owner of ACL) NotOwnerExcepti (only the owner may modify)
java.sql Exceptions
The Java SQL API throws the following exceptions: DataTruncation (unexpected data truncation) SQLException (SQL error--contains detailed SQL information) SQLWarning (SQL warning)
The Java text API throws the following exception: FormatException (format or parsing error)
java.text Exception
java.util Exceptions
The classes of the java.util package throw the following exceptions: EmptyStackException (no objects on stack) MissingResourceException (resource missing) NoSuchElementException (no more objects in collection) TooManyListenersException (thrown by unicast event listeners) NOTE: Unicast is Java terminology for a singleton server object. Singletons are objects that can be instantiated only once.
The Java utilities zip API throws the following exceptions: DataFormatException (format error) ZipException (Zip error)
java.utils.zip Exceptions
Built-In Exceptions
Here application creates a method and forces it to divide by zero. The method does not have to explicitly throw an exception because the division operator throws an exception when required. An example of a built-in exception.
import java.io.* ; import java.lang.Exception ; public class DivideBy0 { public static void main( String[] args ) { int a = 2 ; int b = 3 ; int c = 5 ; int d = 0 ; int e = 1 ; int f = 3 ; try { System.out.println( a+"/"+b+" = "+div( a, b ) ) ; System.out.println( c+"/"+d+" = "+div( c, d ) ) ; System.out.println( e+"/"+f+" = "+div( e, f ) ) ; }
catch( Exception except ) { System.out.println( "Caught exception " + except.getMessage() ) ; } } static int div( int a, int b ) { return (a/b) ; } }
Applet
Introduction
An applet is a small program that is intended not to be run on its own, but rather to be embedded inside or launched from within another application. The most common use of applets are the small programs launched from Web pages. Applets are graphical and event driven but, for security reasons, may never access the file system of the platform on which they are run.
Limitation of Applet
The restrictions on applets include the following:
Applets can't read or write to the reader's file system, which means they cannot delete files or test to see what programs you have installed on the hard drive. Applets can't communicate with any network server other than the one that had originally stored the applet, to prevent the applet from attacking another system from the reader's system. Applets can't run any programs on the reader's system. For UNIX systems, this includes forking a process. Applets can't load programs native to the local platform, including shared libraries such as DLLs.
Must be the superclass of any applet that is to be embedded in a Web page or viewed by a Java applet viewer. The Applet class provides a standard interface between applets and their environment. Is subclassed to define an applet. For example,
begins the definition of a class named MyApplet that inherits all the features of the Object, Component, Container, Panel, and Applet classes. All that remains is to supply custom features that define application processing.
Other methods exist for retrieving image files, retrieving and playing audio clips, and more.
Initialization
Initialization occurs when the applet is first loaded (or reloaded), similarly to the main() method in applications. The initialization of an applet might include reading and parsing any parameters to the applet, creating any helper objects it needs, setting up an initial state, or loading images or fonts.
To provide behavior for the initialization of our applet, override the init() method in our applet class:
many different times during an applet's lifetime, whereas initialization happens only once. Starting can also occur if the applet was previously stopped. For example, An applet is stopped if the reader follows a link to a different page, and it is started again when the reader returns to this page. To provide startup behavior for your applet, override the start() method:
Stopping
Stopping occurs when the reader leaves the page that contains a currently running applet, or you can stop the applet yourself by calling stop(). By default, when the reader leaves a page, any threads the applet had s tarted will continue running. By overriding stop(), you can suspend execution of these threads and then restart them if the applet is viewed again:
Destroying
Destroying enables the applet to clean up after itself just before it is freed or the browser exits-for example, to stop and remove any running threads, close any open network connections, or release any other running objects. Generally, we won't want to override destroy() unless we have specific resources that need to be released-for example, threads that the applet has created.
To provide clean-up behavior for your applet, override the destroy() method:
Painting
Painting is how an applet actually draws something on the screen, be it text, a line, a colored background, or an image. Painting can occur many thousands of times during an applet's life . We override the paint() method if your applet needs to have an actual appearance on the screen (that is, most of the time).
import java.awt.Graphics;
import java.awt.Font; import java.awt.Color; public class Aman extends java.applet.Applet { Font f = new Font("TimesRoman", Font.BOLD, 36); public void paint(Graphics g) { g.setFont(f); g.setColor(Color.red); g.drawString("Hello again!", 5, 40); } }
This applet implements the paint() method, one of the major methods described in the previous section (actually, it overrides the default implementation of paint(), which does nothing). Because the applet doesn't actually do much (all it does is print a couple words to the screen), and there's not really anything to initialize, you don't need a start(), stop(), init(), or destroy() method.
A sample applet The following statements define a small applet that displays a message when the user clicks a button. The button may then be re-clicked to clear the message:
import java.awt.*; import java.awt.event.*; import java.applet.*; public class Aman extends Applet implements ActionListener { Button b = new Button("Show message"); TextField message = new TextField("", 15); public void init() { resize(300, 100); setBackground(Color.lightGray); b.addActionListener(this); add(b); message.setFont(new Font("Serif", Font.ITALIC, 24)); message.setForeground(Color.red);
message.setEditable(false); add(message); } public void actionPerformed(ActionEvent e) { if (message.getText().length() == 0) { message.setText("Hello world!"); b.setLabel("Clear message"); } else { message.setText(""); b.setLabel("Show message"); } } }
Notes: 1. By importing the java.applet package, accessing the Applet class is made easier 2. The applet needs no WindowListener interface because it isn't a window 3. Processing begins with the init() method. It immediately resizes the window to override any size specified by the applet's HTML tag .Everything else about the applet is virtually the same as we would see in an equivalent windows program (with the exception of window event handling which isn't needed). 4. NOTE: The procedure for compiling a Java applet is identical to the procedure for compiling a Java program. To test the applet's bytecode, however,we must launch the applet viewer program. This is done by entering the command: appletviewer App.php
<HTML> <HEAD> <TITLE>This page has an applet on it</TITLE> </HEAD> <BODY> <P>My second Java applet says: <BR><APPLET CODE="HelloAgainApplet.class" WIDTH=200 HEIGHT=50> Hello Again! </APPLET> </BODY> </HTML>
1. The CODE attribute indicates the name of the class file that contains this applet, including the .class extension. In this case, the class file must be in the same directory as this HTML file. To
indicate applets are in a specific directory, use CODEBASE, described later today. 2. WIDTH and HEIGHT are required and are used to indicate the bounding box of the applet-that is, how big a box to draw for the applet on the Web page. Be sure we set WIDTH and HEIGHT to be an appropriate size for the applet; depending on the browser, if our applet draws outside the boundaries of the space you've given it, we may not be able to see or get to those parts of the applet outside the bounding box. 3. The text between the <APPLET> and </APPLET> tags is displayed by browsers that do not understand the <APPLET> tag (which includes most browsers that are not Java aware). Because our page may be viewed in many different kinds of browsers, it is a very good idea to include some sort of alternate text or HTML tags here so that readers of your page who don't have Java will see something other than a blank line. 4. Note that the <APPLET> tag, like the <IMG> tag itself, is not a paragraph, so it should be enclosed inside a more general text tag, such as <P> or one of the heading tags (<H1>, <H2>, and so on).
Enhances the capabilities of text-only documents to permit special text formatting, links to other pages, and the insertion of objects (audio files, graphic files, etc.). It also provides for the insertion and execution of Java applets. Uses special tags (codes) within the text file. The tags are acted upon by the browser when the Web page is loaded.
Example: Displaying text in bold This will be bold Notes: 1. The tag marks the beginning of bold text and the marks the end of bold text 2. HTML tags are not case sensitive. These tags could have been coded and. 3. Most text formatting tags are paired. There is a beginning tag and ending tag. 4. Other HTML tags exist to specify text size, italicizing, centering, the start of a new paragraph, etc. Example: Inserting a graphic image
Is simplified by the use of various software products. In fact, a detailed understanding of HTML is no longer required to create sophisticated Web pages.
The only HTML you are required to learn in this course involves launching a Java applet. While some packages help generate the tags, it is sometimes necessary to code or edit the tags manually.
getParameter("taxRate")
In this example, the value received from the browser would be a String object having the value ".06" 4. There is no restriction on the number of parameters. Simply code a PARAM tag for each one and place them between the and tags.
import java.awt.*; import java.awt.event.*; import java.applet.*; public class App extends Applet implements ActionListener {
Button b = new Button("Show message"); TextField message = new TextField("", 15); public void init() { resize(300, 100); setBackground(Color.lightGray); b.addActionListener(this); add(b); message.setFont(new Font("Serif", Font.ITALIC, 24)); message.setForeground(Color.red); message.setEditable(false); add(message); } public void actionPerformed(ActionEvent e) { if (message.getText().length() == 0) { message.setText(getParameter("message")); b.setLabel("Clear message"); } else { message.setText(""); b.setLabel("Show message"); } } }
Streams
A stream is a path of communication between the source of some information and its destination. This information can come from a file, the computer's memory, or even from the Internet.
A stream is a path of communication between a source of information and its destination. For example, An input stream allows us to read data from a source, and an output stream allows us to write data to a destination.
To import each individual class or to import the entire java.io package, like this:
Input Streams
Input streams are streams that allow us to read data from a source. These include the root abstract class InputStream, filtered streams, buffered streams, and streams that read from files, strings, and byte arrays.
read()
The most important method to the consumer of an input stream is the one that reads bytes from the source. Here's the first form of read():
InputStream s = getAnInputStreamFromSomewhere(); byte[] buffer = new byte[1024]; // any size will do if (s.read(buffer) != buffer.length) System.out.println("I got less than I expected.");
This form of read() attempts to fill the entire buffer given. If it cannot (usually due to reaching the end of the input stream), it returns the actual number of bytes that were read into the buffer. After that, any further calls to read() return -1, indicating that you are at the end of the stream. Note that the if statement still works even in this case, because -1 != 1024 (this corresponds to an input stream with no bytes in it at all).
skip()
What if you want to skip over some of the bytes in a stream, or start reading a stream from other than its beginning? A method similar to read() does the trick:
available()
If for some reason we would like to know how many bytes are in the stream right now, we can ask the following:
mark() and reset() InputStream s = getAnInputStreamFromSomewhere(); if (s.markSupported()) { // does s support the notion? . . . // read the stream for a while s.mark(1024); . . . // read less than 1024 more bytes s.reset(); . . . // we can now re-read those bytes } else { . . . // no, perform some alternative }
When marking a stream, we specify the maximum number of bytes you intend to allow to pass before resetting it. This allows the stream to limit the size of its byte "memory." If this number of bytes goes by and you have not yet used reset(), the mark becomes invalid, and attempting to use reset() will throw an exception.
Marking and resetting a stream is most valuable when you are attempting to identify the type of the stream (or the next part of the stream), but to do so, you must consume a significant piece of it in the process. Often, this is because you have several black-box parsers that you can hand the stream to, but they will consume some (unknown to you) number of bytes before making up their mind about whether the stream is of their type. Set a large size for the limit in mark(), and let each parser run until it either throws an error or completes a successful parse. If an error is thrown, use reset() and try the next parser.
close() InputStream s = alwaysMakesANewInputStream(); try { . . . // use s to your heart's content } finally { s.close(); }
Get used to this idiom (using finally); it's a useful way to be sure something (such as closing the stream) always gets done. Java provides many classes that make "I/O" (input and output) relatively easy and platform independent. In this lesson, we will learn how to act upon the file structure of a platform from inside a Java application. Note that Java applets are NOT permitted to access a platform's file structure for security reasons.
Encapsulates platform-independent information about a file or a directory. While all platforms use pathname strings to name files and directories, they do not agree on the format of these strings. For example, the Windows pathname string is not the same as the Unix pathname string. Regardless of platform, however, all pathnames have two components: 1. An optional system-dependent prefix string (such as the disk-drive specifier followed by "/" for the Unix root directory or "" for the Windows root directory) 2. A sequence of zero or more string names where each name, except for the last, denotes a directory. The the last name may denote either a directory or a file. A system-dependent separator ("/" for Unix or "" for Windows) is used between each name. For example, The following represents a valid Windows pathname:
Has a number of static fields. These two are the most useful:
For example, The following program can determine if it is running under Windows:
import java.io.*; public class AppFile { public static void main(String[] args) { if (File.separator.equals("")) System.out.println("Windows"); else System.out.println("Not Windows"); } }
Has several constructors. The most frequently used constructs a File object from a pathname string as shown by the following statement:
Has a number of methods, some of which WILL create, rename, and delete a disk file or a directory. They should obviously be used with caution. The most frequently used methods are:
Can be instantiated to display a modal dialog window from which the user can select a file. Because it is a modal dialog, once an application makes a FileDialog object visible, it cannot continue until the user has chosen a file. Has two static fields that indicate whether the file will be used for input or output. They are
Sample program
The following menu-driven, Windows program uses the File and FileDialog classes to display a variety of information about a file selected by the user:
public class App extends Frame implements ActionListener { // Object references. MenuBar mainBar; Menu fileMenu;
MenuItem find; MenuItem exit; TextArea fileInfo; // Processing starts here. public static void main(String[] args) { App myWindow = new App("File Analyzer"); myWindow.setSize(500, 200); myWindow.setVisible(true); } // Class constructor. public App(String title) { // Usual boilerplate for startup and shutdown. super(title); //addWindowListener(); new WindowAdapter() { public void windowClosing(WindowEvent e) { dispose(); System.exit(0); } } ); // Create the frame's menu bar. mainBar = new MenuBar(); setMenuBar(mainBar); fileMenu = new Menu("File"); find = new MenuItem("Find"); find.addActionListener(this); fileMenu.add(find); fileMenu.addSeparator(); exit = new MenuItem("Exit"); exit.addActionListener(this); fileMenu.add(exit); mainBar.add(fileMenu); // Create the file information text area. fileInfo = new TextArea(" Use the menu bar to find a file...", 10, 40, TextArea.SCROLLBARS_NONE); fileInfo.setFont(new Font("Monospaced", Font.PLAIN, 12)); fileInfo.setEditable(false); add(fileInfo); } // Required method of the ActionListener interface. public void actionPerformed(ActionEvent e) { // If the user selected "File" | "Find" from the menu, let them // choose a file to be analyzed. Then, display its information.
if (e.getSource().equals(find)) { // Create and display a modal file dialog box through which the // user can choose the file they want to analyze. FileDialog fd = new FileDialog(this, "Choose file", FileDialog.LOAD); fd.setVisible(true); // Construct a File object for the file the user selected. File f = new File(fd.getDirectory() + File.separator + fd.getFile()); // Display information about the file the user selected. fileInfo.setText(" FILE INFORMATION "); fileInfo.append(" Path: " + f.getPath()); fileInfo.append(" Directory: " + fd.getDirectory()); fileInfo.append(" File: " + f.getName()); fileInfo.append(" Last modified: " + new Date(f.lastModified()).toString()); fileInfo.append(" Byte length: " + f.length()); fileInfo.setCaretPosition(0); } // If the user selected "File" | "Exit" from the menu, terminate // the application. if (e.getSource().equals(exit)) { dispose(); System.exit(0); } } }
Obviously, sending and receiving individual bytes would be tedious and difficult for an application to manage. For that reason, several packaged classes exist that make it easy for a program to read and write larger units of data. Most programs use a "high-level" stream class object that is "chained" (connected) to a "low-level" stream class object. While the low-level stream class object handles byte I/O, the high-level stream class object will allow the program to read and write primitive data values and even objects (as shown below).
There are many stream classes, but you will only be required to know the ones that are highlighted below:
Is a low-level class that can be used to send individual, 8-bit bytes to a stream Has several constructors. The most frequently used constructs a FileOutputStream object from a File object that encapsulates the file's pathname. For example, if fd is the reference of a File object
It will construct a FileOutputStream object for sending bytes to the file. If the file already exists, its contents will be replaced (there is an overloaded constructor to specify appending). Because a checked, IOException may occur, the statement should be enclosed in a try block with an appropriate catch. Has a few useful methods. The two most used are:
Because a checked, IOException may occur, calls to these methods should be enclosed in a try block with an appropriate catch. Consult the Java API documentation for more details.
Example. The following program can be used to create a file of numbers on disk. // Open an output stream for the file.
java.io.*; public class AppFOS { public static void main(String[] args) { // Local variables and object references. char again = 'y'; File fd; FileOutputStream out; // Get the path name from the user. System.out.print("Enter the file's complete path name: "); fd = new File(Keyboard.readString()); // Try to write data to the output stream. try { //number and writes it to the // stream. The user is then asked if they want to enter another. while (again == 'Y' || again == 'y') { System.out.print("Enter a number: "); int theNumber = Keyboard.readInt(); out.write(theNumber); System.out.print("Again? (Y/N): "); again = Keyboard.readChar(); } // Close the stream. out.close(); System.out.println("Closed - " + fd.getPath()); } // Catch an IOException if one is thrown. catch (IOException e) { System.out.println(e.getMessage()); }
} }
Is a low-level class that can be used to read individual, 8-bit bytes from a stream Has several constructors. The most frequently used constructs a FileInputStream object from a File object that encapsulates the file's pathname. For example, if fd is the reference of a File object
Because a checked, IOException may occur, calls to these methods should be enclosed in a try block with an appropriate catch. Consult the Java API documentation for more details. Example. The following program can be used to read byte values from a disk file. It can be used to display the values stored by the previous sample program.
import java.io.*; public class AppFIS { public static void main(String[] args) { // Local variables and object references. File fd; FileInputStream in; // Get the path name from the user. System.out.print("Enter the file's complete path name: "); fd = new File(Keyboard.readString());
// Try to read data from the input stream. try { // Open an input stream for the file. in = new FileInputStream(fd); // This loop reads a byte from the stream and displays // its value. The loop ends when no more bytes are available. while (in.available() > 0) { System.out.println(in.read()); } // Close the stream. in.close(); System.out.println("Closed - " + fd.getPath()); } // Catch an IOException if one is thrown. catch (IOException e) { System.out.println(e.getMessage()); } } }
Is a high-level class that can be used to send primitive values and UTF ("Unicode Transformation Format") strings to a stream Has a single constructor that "chains" to an object that descends from the OutputStream class (such as a FileOutputStream object). For example, if fd is the reference of a File object
Because a checked, IOException may occur, calls to these methods should be enclosed in a try block with an appropriate catch. Consult the Java API documentation for more details. Example. The following program can be used to create a file of double values on disk.
import java.io.*; public class App { public static void main(String[] args) { // Local variables and object references. char again = 'y'; File fd; DataOutputStream out; // Get the path name from the user. System.out.print("Enter the file's complete path name: "); fd = new File(Keyboard.readString()); // Try to write data to the output stream. try { // Open an output stream for the file. out = new DataOutputStream(new FileOutputStream(fd)); // This loop asks the user to enter a number and writes it to the // stream. The user is then asked if they want to enter another. while (again == 'Y' || again == 'y') { System.out.print("Enter any real number (n.n): "); double theNumber = Keyboard.readDouble(); out.writeDouble(theNumber); System.out.print("Again? (Y/N): "); again = Keyboard.readChar(); } // Close the stream.
out.close(); System.out.println("Closed - " + fd.getPath()); } // Catch an IOException if one is thrown. catch (IOException e) { System.out.println(e.getMessage()); } } }
Because a checked, IOException may occur, calls to these methods should be enclosed in a try block with an appropriate catch. Consult the Java API documentation for more details. Example. The following program can be used to read a file of double values from disk. It can be used to display the values stored by the previous sample program.
import java.io.*; public class App { public static void main(String[] args) { // Local variables and object references.
File fd; DataInputStream in; // Get the path name from the user. System.out.print("Enter the file's complete path name: "); fd = new File(Keyboard.readString()); // Try to read data from the input stream. try { // Open an input stream for the file. in = new DataInputStream(new FileInputStream(fd)); // This loop reads a double value from the stream and displays // it. The loop ends when end of file is reached. try { while (true) { System.out.println(in.readDouble()); } } catch (EOFException e) { System.out.println(""); } // Close the stream. in.close(); System.out.println("Closed - " + fd.getPath()); } // Catch an IOException if one is thrown. catch (IOException e) { System.out.println(e.getMessage()); } } }
Is a high-level class that can be used to send primitive values and "serializable" objects to a stream. All that is needed for an object to be serializable, is that its class must implement the Serializable interface. For example, if a Customer class is to be serializable, its header may be coded
Because a checked, IOException may occur, calls to these methods should be enclosed in a try block with an appropriate catch. Consult the Java API documentation for more details. Example. The following program can be used to create a file of multiple array objects on disk.
import java.io.*; public class App { public static void main(String[] args) { // Local variables and object references. char again = 'y'; String[] array; File fd; ObjectOutputStream out; // Get the path name from the user. System.out.print("Enter the file's complete path name: ");
fd = new File(Keyboard.readString()); // Try to write data to the output stream. try { // Open an output stream for the file. out = new ObjectOutputStream(new FileOutputStream(fd)); // This loop constructs an array with values entered by the user // and writes the array to the file. The user is given the option // of repeating the loop to construct and store another array. while (again == 'Y' || again == 'y') { System.out.print("How many strings will you enter? "); array = new String[Keyboard.readInt()]; for (int i = 0; i < array.length; i++) { System.out.print("Enter a string: "); array[i] = Keyboard.readString(); } out.writeObject(array); System.out.print("Again? (Y/N) "); again = Keyboard.readChar(); } // Close the stream. out.close(); System.out.println("Closed - " + fd.getPath()); } // Catch an IOException if one is thrown. catch (IOException e) { System.out.println(e.getMessage()); } } }
Is a high-level class that can be used to read primitive values and serializable objects from a
stream Has overloaded constructors but the most useful "chains" to an object that descends from the InputStream class (such as a FileInputStream object). For example, if fd is the reference of a File object
Because a checked, IOException may occur, calls to these methods should be enclosed in a try block with an appropriate catch. Consult the Java API documentation for more details. Example. The following program can be used to read a file of array objects from disk. It can be used to display the array values stored by the previous sample program.
import java.io.*; public class App { public static void main(String[] args) { // Local variables and object references. File fd; ObjectInputStream in; // Get the path name from the user. System.out.print("Enter the file's complete path name: "); fd = new File(Keyboard.readString()); // Try to read data from the input stream. try { // Open an input stream for the file. in = new ObjectInputStream(new FileInputStream(fd));
// This loop reads a array objects from the stream and displays // their contents. The loop ends when end of file is reached. try { while (true) { String[] array = (String[]) in.readObject(); for (int i = 0; i < array.length; i++) { System.out.println(array[i]); } System.out.println("<< END OF ARRAY >>"); } } catch (EOFException e) { System.out.println("<< END OF FILE >>"); } // Close the stream. in.close(); System.out.println("Closed - " + fd.getPath()); } // Catch an IOException if one is thrown. catch (IOException e) { System.out.println(e.getMessage()); } // Catch an ClassNotFoundException if one is thrown. catch (ClassNotFoundException e) { System.out.println(e.getMessage()); } } }