Techniques of Java Programming: Java Basics: Manuel Oriol April 18, 2006
Techniques of Java Programming: Java Basics: Manuel Oriol April 18, 2006
Techniques of Java Programming: Java Basics: Manuel Oriol April 18, 2006
Manuel Oriol
April 18, 2006
1 Introduction
Java is the Object-Oriented language of choice for most developers. It is a
type-safe, Object-Oriented, multiplatform programming lanuguage Its main ad-
vertisement has been for years: ”compile once, run everywhere”. This is true for
programs that are meant to run on multiple platforms. Nevertheless, multiple
versions of the Java Virtual Machine (JVM) and of the Standard Development
Kit (SDK) do not guarantee that anymore. This is the price to pay for wide
acceptance.
In this course, we intend to give an overview of the language to computer
scientists that are already proficient in at least one object-oriented language.
Thus we will go through the language and its general mechanisms at a fast pace
in the first few lessons and then we will present more advanced features.
Readers not only get a basic understanding, that allows them to build Java
programs, but also get a deeper understanding of the language internal mecha-
nisms. These mechanisms will be illustrated through experiments that flirt with
research. This tutorial explains the language developed in Java 2 version 5.0 as
it is the current release. If we consider any other specific version at any point,
it will be clearly stated in the text.
2 Java Development
2.1 Big Picture
Developing in Java implies understanding a set of basic principles. Figure 1
shows the main steps and tools that are commonly used during Java development
and compilation.
The source code of Java programs is composed of files that have the .java
extension. Java being class-based, each file contains at least one class that has
the same name as the file (without the extension).
The Application Programming Interface (API) documentation can be ex-
tracted automatically from the Java source code by using the javadoc com-
mand. The generated documentation consists of a website in HTML.
The compilation of Java source code, using the javac command, generates
one file per class of the source code. Each of these files begins by the name
of the file where the class was defined and has the extension .class. The
content of such class files is byte code: an intermediate representation that
resembles assembly code and is understood by any Java execution platform.
1
"
!
Such execution platforms are called Java Virtual Machines (JVM) and are most
often called java.
javac
-g Generate all debugging information
(to be used with a debugger)
-nowarn No warnings
-verbose Output messages while compiling to show
the effected operations
-classpath path, Adds the path to the CLASSPATH value
-cp path for this execution
-d path Generated classes will be put to path
-version Gives the current version
-help Print help
-X Print non-standard options
e.g. -Xstdout file e.g. redirects standard out to a file.
2
The Java compiler takes a set of classes as arguments and generates the byte
code. As shown in Table 1 the classpath can be extended by using the option
-cp, warnings can be ignored... and other options can be set.
Each class has its own class file. In the case a source code file C.java contain-
ing more than one class, the main class (that has the same name as the source
file without extension) is compiled into a file C.class. Other named classes are
compile into classes that have the name C$NameOfTheClass.class. Anony-
mous classes are compiled into classes that have the name C$number .class
where number is a unique identifier for anonymous classes within the file.
Example of Java compilation:
javac *.java
java
-classpath path, Adds the path to the CLASSPATH value
-cp path for this execution
-verbose [:class—gc—jni] Output messages on classes/garbage
collection/java native interface to
show the effected operations
-version Gives the current version and exits
-help, -? Print help
-X Print non-standard options
e.g. -Xmssize e.g. Set the initial heap size.
e.g. -Xsssize e.g. Set the thread stack size.
The Java Virtual Machines (JVM) are the execution environments for Java
programs (see Table 2). A JVM is intended to act as an interpreter for the byte
code. Thus the byte code is itself portable from one platform to another. Java
virtual machines have to be ported and installed on the respective platforms
prior to program execution.
By default, the argument class name will be loaded and the main method
within this class will be called as a starting point. The JVM takes care of
memory allocation and deallocation. In particular, the JVM manages automatic
garbage collection of instances and code when not used any more .
While interpretation is slow in general, a JVM has lots of facilities to speed
up execution. The most important one is Just-In-Time (JIT) compiling which
compiles the byte-code to native code when it is loaded, thus giving near native
performance on the use of a class once it has been executed at least once. Of
course this initial translation yields a performance penalty at first execution of
given method.
If MyMain is the class containing the bootstrap code, the program can be
launched as follows:
java MyMain
3
2.5 Java Dynamic Loading
As each class has its own file, class loading can be delayed until the class is
actually needed. The default behavior for the Java class loading mechanism
is on-demand class loading. A class is actually loaded at the moment its first
instance is created. This is often called lazy class loading.
This mechanism has the clear advantage of reducing startup time, especially
in the case of just-in-time compilation but slows down the execution while a
complete set of classes has not been loaded in memory. Please note that this
constitutes only a mere introduction to JVM class loading. We will study it in
more details later on.
javadoc
-classpath path, Adds the path to the CLASSPATH value
-cp path for this execution
-verbose Output messages on what javadoc is doing
-quiet Do not output messages on classes/garbage
-version Gives the current version and exits
-help Print help
-d path Generated documentation will be put to path
Java Development Kits (JDK) include the javadoc utility (see Table 3 for de-
tails on the options) that automatically generates the documentation in HTML
format.
In Java, comments can be inserted in the code in two ways: using // to
comment the following characters in the line or use /* to begin a comment and
*/ to finish it.
Each comment written using the /** and ending by */ just immediately
before an element that can be commented ensures that the comment will be put
into the documentation. Asterisks at the beginning of a line are ignored.
It is also possible to include tags that lead to the creation of specific cate-
gories and links automatically. Including HTML tags is also allowed and will
be included as is in generated pages.
As an example, the javadoc documentation presents the example from Fig-
ure 2 that describes the package tojp:
/**
* This package is an example for the course Technique of Java Programming at ETHZ
*
* @since 0.1
* @see java.lang
* @author Manuel Oriol
*/
package ch.ethz.tojp;
Tags usable in the Java documentation are of two kinds: tags that can be
used within the text of the documentation itself and tags that define categories
and need to be used at the end of the descriptions. In Table 4, we show the
4
Figure 2: Generated documentation
first category of tags between braces ({ }) and explain all tags with an informal
description. A complete documentation for javadoc and tags can be found in
the JDK documentation.1
5
Table 5: Java Archive main options
jar
c Create
t List content
x Extract
u Update
v Verbose mode
f First argument is archive file name
0 No ZIP compression
has a clear advantage in terms of size as the classes are compressed using the
ZIP algorithm. It is also possible to specify a startup class and thus have the
jar file being an executable program.
Its use (see Table 5 for details on the options, for a good tutorial, please
visit SUN’s website2 ) is similar to the tar utility:
2.9 Exercises
1. Compile HelloWorld.java.
2. Generate complete documentation for HelloWorld.java.
3. Unzip a jar file using unzip.
2 http://java.sun.com/docs/books/tutorial/deployment/jar/
3 http://java.sun.com/j2se/1.3/docs/tooldocs/solaris/jdb.html for more details
6
4. Debug HelloWorld using gdb.
3 Packages
3.1 Naming Convention
By using packages you can set unique names for classes. To assign a file to a
package, it is needed to put at the beginning of the file package adherance:
package package.name;
Package names are sequences of characters separated by dots. The hierarchy
that is intended goes from the more general to the more particular. In our
previous example, we defined the package ch.ethz.tojp it means that the
convention is to prefix all packages from ETHZ by ch.ethz. In the file system
this is translated by having a tree-like structure where each folder includes the
rest of the package.
Classes from the package ch.ethz.tojp would all be contained in a directory
named tojp, itself contained in a directory named ethz, itself contained in a
directory named ch. By convention, package names are in lower case, while
class names begin with an upper case character, only contain letters and have
upper cases at the beginning of each new word in the class name.
import ch.ethz.tojp.*;
import ch.ethz.tojp.Tojp;
7
Table 6: Java Primitive Types
Type Represents Default Size Min Example Max
boolean true or f alse false 1 bit true
char unicode chars \u000 16 bits \u0000 ’c’ \uFFFF
byte signed int 0 8 bits −128 50B 127
short signed int 0 16 bits −32768 500S 32767
int signed int 0 32 bits −2147483648 250 2147483647
long signed int 0 64 bits −263 4587L 263 − 1
float IEEE 754 0.0 32 bits ±3.4E + 38 34.545F ±1.4E − 45
double IEEE 754 0.0 64 bits ±1.7E + 308 23.54e5 ±4.9E − 324
3.4 Exercises
1. Define your own package name for HelloWorld.
2. Reference HelloWorld in a class outside the package.
4 Types
4.1 Primitive Types
The first kind of types that exists in Java is primitive types, the other one
being reference types. Primitive types (see Table 6 for details) are not classes.
Contrary to other types, non-local variables of these types are automatically
initialized to valid values. It is also possible to use standard arithmetic operators
(+, -, *, /) with numbers as well as comparison operators (<, >, ==, >=, <=, !=).
There is an automatic conversion policy for numbers when used in formulae and
if there is no loss of precision during the conversion. Contrary to the C language
from which it borrows the types names, there is no possibility to assign a number
to a char and vice-versa.
Primitive types have equivalent classes: boolean’s equivalent is Boolean,
char’s equivalent is Character, int’s equivalent is Integer, byte’s equivalent
is Byte, short’s equivalent is Short, float’s equivalent is Float, and double’s
equivalent is Double. Note that in the most recent version of Java, SUN has
introduced automatic boxing in the language. This allows to use int variables
and Integer in an interchangeable manner while calculating arithmetic formu-
lae and making assignments.
4.3 Classes
Named classes begin with a visibility modifier as described in Figure 7 the
keyword class, a name, an opening brace ({). It ends with a closing brace (}).
8
By default, a class is only accessible from within its own package.
The following modifiers can be applied to a classes definitions: abstract is
for saying that the class cannot be instantiated and must be subclassed to be
used, final means that the class cannot be subclassed, public means that the
class is accessible from other packages.
As we already wrote in Subsection 3.1, class names begin by convention
with an upper case character, they only contain letters and have upper case
characters at each beginning of a new word in the class name. This is often
referred to as CamelCase.4
As an example, the class HelloWorld could be declared as follows:
4.4 Interfaces
Interfaces are equivalent to abstract classes because they cannot be used for
creating instances. Interfaces do not contain any implementation, only signature
of methods (see Subsection 6.2 ). Interfaces begin with the keyword interface,
a name, an opening brace ({). It ends with a closing brace (}). By default,
interfaces are only accessible within their package. A public interface means
that the interface is accessible from other packages.
Most interfaces are called somethingable because they act as an enabler for
a property.
As an example, the toy interface Wavable could be declared as follows:
4.5 Inheritance
Java has single inheritance, which means that a class can have one parent class
only. Methods are directly inherited in children classes. Their name do not
change and they can be used as is if the client code respects the given visibility
for the methods. At the top of the inheritance tree, the class Object defines
the set of common methods.
A class specifies that it inherits from another one by writing extends Oth-
erClass between its name and the opening brace. As an example:
9
4.6 Implementation
A class may implement an interface. This means that it gives an actual im-
plementation for each of the method signatures from the interface. Note that
instances of a class implementing an interface are also of the type of the inter-
face. Thus they can be treated as variables of that type. This constitutes the
main use of interfaces: getting rid of multiple inheritance and still being able to
automate treatments over classes from several branches of the inheritance tree.
The class HelloWorld implementing Wavable, it could be declared as follows:
public class HelloWorld implements Wavable {
...
}
// method declaration
public void wave(){
class Hello2 extends HelloWorld{
};
...
}
Inner classes can also be anonymous. Please remember that they are non-
abstract and final in addition of being non-static. It is then made on-the-
fly when calling a constructor by opening a brace ({) immediately after the call
(before the ;) and beginning to define/redefine methods before closing the brace.
This kind of declaration is very useful when willing to redefine a class for only
one variable as it happens very often for graphical user interfaces. Example:
10
The last possibility for describing inner classes is to include a class definition
at the same level as the class’s methods. In that case, the scope of the class is
the inner class itself. Example:
};
// method declaration
public void wave(){
...
}
}
Declaring a generic type that uses more than one parameter is done through
using of commas between generic parameters. As an example, this is the decla-
ration of a generic type that uses two types internally, given by the two generic
parameters:
4.9 Arrays
Arrays are declared similarly to C/C++: by adding [ ] after the type of which
we are considering the array. When actually instanciating the array itself a new
type is defined. As an example:
11
// defines an array of HelloWorld called hellos
HelloWorld[] hellos;
4.10 Exercises
1. Why would one use interfaces?
2. What is the difference between interfaces and abstract classes?
3. Why use inner classes?
4. What is the difference between primitive types and reference types?
5 Variables
5.1 Declaring Variables
Variables are declared using C-style declaration: first the type of the variable
and then the name of the variable.
int a;
String c;
Each declaration ends with a semicolon (;) and several variable names shar-
ing the same type can be declared at once by separating variable names with a
comma (,).
int a,b;
String c;
12
int a;
int []b={3,4,5,6};
...
a=b[2];
// a is now equal to 5
Another way of using variables is to test their value. By default, the usual
comparison operators (==, !=, <, >, =<, >=) apply naturally on number types.
Equality/inequality can also be tested on variables of reference types, denoting
respectively then reference equality and reference inequality.
5.4 this
Within instances methods, it is possible to reference the current object by using
this. This can be usefull when another declaration shadows a variable or to
use the current object as a parameter of another method. As an example:
int a;
...
public void add(int a){
this.a=this.a+a;
System.out.println(this);
}
private
default
public
Qualifier
Not in package/Not in a subclass yes no no no
In subclass yes yes no no
Within package yes yes yes no
13
public class HelloWorld {
public String message = "Hello World!";
...
System.out.println(this.message);
...
System.out.println(message);
...
}
Instance variables can also have the following modifiers: final, transient,
volatile. Fields that are final can only be assigned once and must be as-
signed in any constructor. Fields that are transient do not participate to the
persistent state of the object (they will not be serialized). volatile fields may
be accessed by threads safely (we will come back to this notion in later lectures).
The qualifiers volatile and final are incompatible.
Possibly HelloWorld could declare the field message as final:
public class HelloWorld {
public final String message = "Hello World!";
...
}
5.7 Exercises
1. Why is it incompatible to have a final and volatile field?
2. Would you use a static qualifier for a multithreaded application? Would
you use another qualifier?
3. Is a local variable accessible from outside the class?
4. Is a local variable accessible from outside the code in which it is defined?
14
5. How would you declare a String that should be visible outside the package,
shared by all instances and may be accessed concurrently?
6 Methods
6.1 Constructors
A constructor is a creation procedure. Constructors have the same visibility
modifiers as the ones described in Table 7. Constructors in Java have the same
name as the class for which they build instances. Constructors do not have
return types (implicitely they return a fresh instance of their class). Construc-
tors are not inherited by child classes. Constructors must contain a call to a
constructor of the parent class (using super instead of the constructor name), if
they fail to do that, a call to the default constructor with no argument is added
by the compiler. If this still fails, there is a compile-time error. Example:
/*
* Class to wave at the world.
**/
public class HelloWorld {
/*
* The message that will be displayed
**/
public String message="Hello World!";
/*
* Constructor that changes the message displayed
**/
public HelloWorld(String s){
super();
message=s;
}
}
Calling a constructor in a client class is done by adding the keyword new in
front of the class name and then adding the arguments separated by commas
between parentheses. Suppose the example for HelloWorld:
HelloWorld world=new HelloWorld("Hello my dearest World!!!");
A constructor for generic classes has to indicate the bindings of the generic
types in its signature:
/*
* Class to wave at the world.
**/
public class HelloWorld <E>{
/*
* Constructor that changes the message displayed
**/
15
public HelloWorld<E>(String s){
super();
}
}
A call to a constructor of a generic class must also include the generic pa-
rameter:
6.2 Declaration
A method is declared through writing:
16
public abstract Void wave();
String s0=args[0];
}
Interestingly enough subtyping may become unsafe when using generics. As
an example, if one assigns a list of drivers to a list of persons, then the system
may allow to add persons that are not drivers and then corrupt the list of drivers
without breaking subtyping.
To solve this problem, the specification for the generics follow a policy that
is based on the use of wildcards when trying to use their types. Then the super
type of all Lists is:
In this case we make no assumption on the actual type of the generic type
of l. It is however useful to use methods from a certain type sometimes. As an
example, the method printList can be defined as follows:
The same thing is possible using the keyword super instead of extends and
to combine several conditions using &. The excellent tutorial from Gilad Bracha
”Generics in the Java Programming Language”5 explains these constructs in
more details.
out2=out.clone();
out2.println("Hello World!");
If a method returns a result, calls may be chained and applied with a default
left side parentheses. It can also be combined with fields accesses.
System.out.println("Hello World!");
5 http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf
17
6.4 Method Conformance
A method m2 conforms to another method m1 if:
• they have the same name.
• they have the same number of formal parameters and each parameter has
the same type in each method.
• the return type of m2 is the same or a subtype of the one of m1 .
6.7 Visibility
Visibility modifiers for methods are the same as the ones described in Table 7.
Launching the application can be made by calling java on the class contain-
ing the definition of the main method. Example:
java HelloWorld
18
6.9 Exercises
1. Why does the following code not compile?
19
4. And here?
7 Expressions
7.1 Instructions
A statement can be:
• An empty statement (e.g. ;).
• A labeled statement to be used in conjunction with break or continue.6
• An expression statement that is calculated. Note that it covers method
invocations and calculations.
• A control structure that is affecting the execution.
• An assert statement that tries to verify a condition if assertions are on.7
• A return statement that terminates the methods invocation and possibly
returns a value.
• A throw statement that generates a new exception.
6 http://java.sun.com/docs/books/jls/third edition/html/statements.html#14.7
7 http://java.sun.com/docs/books/jls/third edition/html/statements.html#14.10
20
• A try statement that catches an exception.
At the end of each non-block statement, a ; is needed.
7.3 instanceof
The operator instanceof is a primitive of the language that allows programmers
to verify that an instance is an instance of a given class. In particular it also
considers that instances of subclasses are instances of the parent classes. The
expression variableName instanceof ClassName returns a boolean that is true
if the variable is an instance of the class, false otherwise. This expression can
also be used on an expression returning a reference type variable instead of
variableName.
7.4 Casting
A cast is a way of having an instance conform to the type of a variable by trying
to change its declared type. It is made by prefixing the reference to be cast by
(TypeName). This used to be extremely useful before the existence of generic
types in Java because any object being put in a container would loose its type
indication when retrieved. Example of use:
String s;
Object o;
...
s=(String)o;
7.5 Blocks
A block is an instruction terminated by a semi-colon (;) or a group of instruc-
tions packed by { and }. Executing a block means that each instruction is
executed one after the other. Blocks are instructions.
7.6 if
If statements have two different forms:
if (test )block
if (test ) block1 else block2
The first expression executes block only if the evaluation of the test returns
true.
The second expression executes block1 only if the evaluation of the test re-
turns true, otherwise it executes block2 . Example:
21
if (a>0)
a=a+1;
else
a=a-1;
7.7 switch
Switch statements have the following form:
switch (expression ){
case constant1 : block1
case constant2 : blockn
...
default: blockf inal
}
As in C or C++, the execution of a switch statement is as follows: if
the value of the expression (that must be of type char, byte, int, short,
Character, Byte, Integer or Short) is equal to one of the constants, then
all the blocks following this constant will be executed. When there is a break
instruction, the code continues execution after the end of the switch statement.
In the case the expression does not evaluate to any constant, the final block is
executed.
Example of use:
int a;
switch (a){
case 1:
System.out.println(1);
break;
case 2:
System.out.println(2);
break;
default:
System.out.println("N/A");
}
7.8 while
While statements have the following form:
while (test ) block ;
While the test is true, the block is executed. Example:
while(true){
i=i+1;
}
7.9 do...while
Do...while statements have the following form:
do block while( expression );
Execute the block and do it again until the expression is false. Example:
22
do{
i=i+1;
}while(i<10);
7.10 for
For statements have the following form:
for(initInstruction;test ;loopInstruction)block
The semantics of the statement is that initInstruction is executed, then the
test is verified, if it returns false the next statement is executed. While the
test is verified block is executed, then loopInstruction is executed and then test
verified. Example:
int sum(int[] a) {
int sum = 0;
for (int i : a)
sum += i;
return sum;
}
while(true){
i=i+1;
if (i>10) break;
}
8 Example from http://java.sun.com/docs/books/jls/third edition/html/statements.html#14.14.2
23
A less known way of using break and continue is to use them with labels.
It is possible to use labels as follows:
label : block
Actually when used as break label ; within a block the execution interrupts
the block that has the same label and continues execution.
In the case the label is defined on a loop statement, it is also possible to use
continue label ; to effect a continue on this loop rather than on the innermost
loop. Example:
test:{
System.out.println("beginning test");
while (true){
if (i<5) {
break test;
} else i++;
System.out.println("end test");
}
}
test2:while (true) {
System.out.println("beginning test2");
if (i<5) {
break test2;
} else {
i++;
continue test2;
}
}
7.13 Exercises
1. Look up in the documentation9 for the documentation on assert.
2. What does the following program do:
while (true) {
System.out.println("beginning test2");
if (i<5) {
break ;
} else {
i++;
continue ;
}
}
int i;
test:for (;true;) {
9 http://java.sun.com/docs/books/jls/third edition/html/statements.html
24
while(true){
System.out.println("beginning test2");
if (i<5) {
break test;
} else {
i++;
continue ;
}
}
}
4. Find a good question for this section and exchange them with your most
direct neighbor.
25
a=getCount();
} catch (Error e){
System.out.println("Too many elements!!!");
}
...
8.2 Error
Error mostly consist of problems that cannot be resolved like LinkageError,
ThreadDeath, VirtualMachineError. It is not needed to declare that a method
may throw an Error as it generally cannot be foreseen.
8.3 Exceptions
There are plenty of exceptions, we can however cite common ones like: ClassNotFoundException,
IOException, ArrayIndexOutOfBoundsException...
A method that may raise an exception needs to declare that it throws an
exception. Thus programmers cannot be surprised by exceptions that they did
not foresee. This indication is added just before the body of the method. As
an example:
8.4 Exercise
1. To treat errors happening on sockets, would you define exceptions or er-
rors?
2. When willing to use a persistence framework if the main storage is not
accessible, would you use an exception or an error to report it?
3. Are exceptions gotos? Give some other point of view than the one used
in Java.
4. what does the following code do?
26
public int pong() throws PongException {
System.out.println("Pong")
throw new PongException();
}
...
boolean b;
while (true)
try{
if (b)
ping();
else
pong();
} catch (PingException pi){
b=false;
}catch (PongException po){
b=true;
}
9 Standard Classes
9.1 Object
The class Object has a limited set of methods. They are all inherited by any
class. The main ones are:
clone(): returns a copy of the object (not a deep copy though).
equals(Object obj): returns true if the current Object is equal to the argu-
ment (according to the method) returns false otherwise.
finalize(): method called by the garbage collector when the object is removed
from the heap.
getClass(): the method returns the actual class of the object.
hashCode(): method that returns a hash code for the current object. Note
that for objects that are equals regarding to equals should have the same
hashCode.
toString(): returns a String that represents the current object.
The other methods of Object are used for concurrent accesses.
9.2 String
The class String is a class that is immutable in Java. This means that the value
of the instances of this class cannot change once created. Some of the methods
of the class String are:
charAt(int index): returns the char at the position specified.
concat(String str): returns a String that is a concatenation of the current
String and the argument.
27
equals(Object anObject): returns true if the argument is a String with the
same value.
length(): returns the size of the current String.
matches(String regex): returns true if the current String matches the reg-
ular expression passed as an argument.
Please note also the existence of a whole set of static methods called
valueOf and that returns the String representations of values from a primi-
tive type.
9.3 System
The System is a class that intends to provide a library for useful functionalities
(static methods) related to the interactions with the system. In particular:
exit(int status): quits the program and sends the return code status to the
system.
getenv(): returns a Map of environment variables and values.
nanoTime(): returns a long containing the most precise available time.
Moreover, the three fields err to output on the error channel, in to read
users inputs, out to output on standar outpout.
9.4 Vector
The class Vector is a generic class that allows to store in an array-like structure
values of a given type. The methods of the class Vector:
add(element): appends the element to the current Vector.
clear(): removes all the elements of the current Vector.
elementAt(int index): returns the element at position index.
remove(Object o): removes o from the current Vector.
size(): returns an int giving the size of the current Vector.
9.5 Exercises
1. Inspect the class Array.
2. Inspect the interface Iterable.
3. Inspet the class OutputStream.
28
10 Basic Examples
10.1 Hello World
The most simple version of Helloworld is:
/**
* Class to startup students
*
*@author Manuel Oriol
*/
public class HelloWorld {
public static void main(String[] args){
System.out.println("Hello World!");
}
}
/**
* Reader from the keyboard
*/
public static BufferedReader standard;
/**
* Stream to write in the file
*/
public static FileOutputStream out;
/**
* This program taks the first argument as a file name,
* it opens it and write what user write into it
*/
public static void main(String[] args){
String s;
29
// users have to leave by using Control-C
while(true){
try {
// read and write
s=standard.readLine();
out.write(s.getBytes());
out.write("\n".getBytes());
} catch (IOException e){
System.out.println("I/O error");
System.exit(0);
}
/**
* Private class for the Elements of the stack.
*/
private class Element <E>{
public Element<E> next;
public Element<E> previous;
public E value;
public Element(E value){
this.value=value;
}
public E getValue(){
return value;
}
};
/**
* First element of the stack.
*/
private Element<E> first;
30
/**
* Constructor for the stack.
*/
public MySmallStack(){
first=null;
}
/**
* Method that adds a value to the stack.
*
*@param value the value to add
*/
public void add(E value){
Element<E> e;
e= new Element<E>(value);
e.next=this.first;
this.first=e;
}
/**
* Method that removes a value from the stack.
*
*@return the removed value
*/
public E remove(){
E retValue;
if (this.first!=null){
retValue=this.first.getValue();
this.first=this.first.next;
if (this.first!=null) this.first.previous=null;
return retValue;
}
return null;
}
/**
* Test for the stack. The expected result is 3 2 1
*/
public static void main(String[] args){
MySmallStack<Integer> myStack = new MySmallStack<Integer>();
myStack.add(1);
myStack.add(2);
myStack.add(3);
System.out.println(myStack.remove());
System.out.println(myStack.remove());
System.out.println(myStack.remove());
}
31