Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1of 291

Java Definitions

•Java Program – a java program is mostly a collection of objects talking to other objects by invoking each other’s
methods. Every object is of a certain type and that type is defined by class or a interface.
•Class - is a template that describes the kinds of state and behavior that objects of its type support.
•Object – at runtime when the JVM encounters the new keyword, it will use the appropriate class to make object
which is an instance of that class. That class will have its own state and access to all of the behaviors defined by
its class.
•State(instance variables) – Each object will have its own unique set of instance variables as defined in the class.
Collectively the values assigned to an objects instance variables make the object’s state.
•Behavior(methods) - when a programmer creates a class, she creates methods for that class. Methods are
where the class logic is stored, where the algorithms get executed and data gets manipulated.
•Identifiers – the java components i.e. class, variables and methods need names. In java these names are called
identifiers. There are rules for what constitutes a legal identifier. Java programmers (and Sun) have created
conventions for naming methods variables and classes.
•Keywords – java has a set of built in key words that must not be used as identifiers.
•Inheritance – allows code defined in one class to be reused in other classes. In java you can define a general
super class and extend it with more specific sub classes. The super class knows nothing of the classes that inherit
from it but all the subclasses that inherit from the superclass must explicitly declare the inheritance relationship.
A subclass that inherits from a superclass is automatically given access to instance variables and methods
defined by the superclass. It is also free to override the superclass methods to define a more specific behavior.
•Interfaces are like a 100% abstract superclass that defines the methods a subclass must support but not how
they must be support. An interface only has the declaration of a method and does not contain any logic about
how the method is implemented. It is up to the first non abstract class implementing the interface to implement
all the methods defined in the interface.
•Cohesive classes- means that every class has a focused set of responsibilities.
Legal Identifiers
• Identifiers must start with a letter, a currency
character ($) or a connecting character (like
underscores). Identifiers cannot start with a
number
• After the first character, identifiers can contain any
combination of letters, currency characters,
connecting characters or numbers.
• There is no limit to the number of characters an
identifier can contain.
• You cannot use a java keyword as an identifier.
• Identifiers in java are case sensitive.
Sun naming standards
• Classes and Interfaces – the first letter should be
capitalized and if several words are linked together to
form a name, the first letter of the inner words should be
uppercase.
• Methods – the first letter should be lower case and then
the normal camelCase rules should be used.
• Variables – like methods camel case format should be
used, starting with a lower case letter.
• Constants – java constants are created by marking the
variables static and final. They should be named using
uppercase letters with underscore characters as
separators.
Java Beans Standards
• Java beans are java classes that have properties. Think of properties as
private instance variables.
• The method that change a property’s value are called setter methods and
the methods that retrieve a property’s value are called getter method.
• If the property is not a boolean, the getter methods prefix must be get.
• If the property is a boolean then the getter method’s prefix is either get or is.
• The setter methods prefix must be set
• To complete the name of a getter or setter method change the first letter of
the property name to uppercase and then append it to the appropriate
prefix (get,is or set).
• Setter method signature must be marked public with a void return type and
an argument that represents the property type.
• Getter method signatures must be marked public, take no arguments and
have a return type that matches the argument type of the setter method for
that property.
Source file declaration rules
• There can be only one public class per source code file.
• If there is a public class in a file, the name of the file must match the name
of the public class.
• If the class is a part of the package, the package statement must be the first
line in the source code file, before any import statements that may be
present.
• If there are import statements, they must go between the package
statement and the class declaration. If there isin’t a package statement
then the import statements must be the first line in the source code file.
• Import and package statements apply to all classes within a source code
file.
• A file can have more than one non public class.
• Files with no public classes can have a name that does not match any of
the classes in the file.
• Comments can appear at the beginning or at the end of any line in the
source code file.
Class Modifiers
• Modifiers fall into two categories
• Access modifiers (public, protected, private)
• Non access modifiers (strictfp, final, abstract)
Note: there are four access controls (levels of access) but only three access
modifiers.
• The fourth access level (default or package access) is what you get when
you don’t use any of the three access modifiers.
• A class can be declared with only public or default access.
• Default Access – a class with default access has no modifier preceding it in
the declaration. Think of default access as package level access because a
class with default access can be seen by classes within the same package.
• Public Access – a class declaration with public keyword gives all classes
from all packages access to the public class.
• Note: If a public class you are tying to use is in a different package from the
class you are writing you will need to import the public class.
Other class modifiers(final, abstract, strictfp)
• You can’t always mix nonaccess modifiers e.g. final and abstract.
• strictfp – marking a class as strictfp means that any method code in the class will
conform to IEEE 754 standard rules for floating points.
• strictfp is a keyword and can be used to modify a class or a method but never a
variable.
• final – marking a class as final means that no class can ever extend (inherit) from
a final class and attempts to do so will give a compile time error. You should mark
a class final when you need an absolute guarantee that none of the methods in
that class will ever e overridden. Marking a class final in essence means that your
class can’t ever be improvised upon or even specialized by another programmer.
• abstract class – an abstract class can never be instantiated. Its sole purpose is to
be extended (subclassed). However you can compile and execute an abstract
class. You can put non abstract methods in abstract class.
• abstract methods – methods marked abstract end in a semi colon rather than
curly braces. If the method is in a class as opposed to an interface then both the
method and the class must be marked abstract. Even if a single method is
abstract, the whole class must be declared abstract.
Interface
• An interface is a contract. When you create an interface you are defining what a class can do
without saying anything how the class will do it.
• Any concrete class that implements the interface must agree to write the for all the methods
defined in the interface.
• An interface can be implemented by any class from any inheritance tree.
• An interface can have only variables and abstract methods.
• Interfaces have very little in how the methods and variables defined in the interface are declared.
• All the methods of the interface are implicitly public and abstract. You do not need to type public
or abstract modifiers in the method declaration.
• All the variables defined in the interface must be public, static and final i.e. interfaces can only
declare constants not instance variables.
• Interface methods must not be static.
• Because interface methods are abstract they cannot be marked final, strictfp or native.
• An interface cannot extend anything but another interface.
• An interface cannot implement another interface or class.
• An interface must be declared with the keyword interface.
• typing abstract modifier for interface is redundant as interfaces are implicitly abstract. e.g. public
abstract interface Rollable
• The public modifier is required if you want the interface to have public rather than dafault
access.
Access modifiers for class members
• Methods and instance variables are collectively known as members.
• Members use all four control levels i.e. public, private, protected, default.
• There are two different access issues
a) whether method code in one class can access a member of another class
b) whether a sub class can inherit a member of its super class.
• public – when a member is declared public it means that all other classes regardless of the package they belong
to can access the member.
Note: if you see a method invoked without the dot operator it means that method or variable belongs to the class
where you see that code. It also means that the method or variable is being accessed implicitly using the this
reference.
• private – private member can’t be accessed by code in any class other than the class in which the private
member was declared. Also when a member is declared private a subclass cannot inherit it.
Note: it is always best to keep all variables private or protected.
• protected – a protected member can be accessed(through inheritance) by a subclass even if the class is in a
different package. So when you think protected think package + kids. Also protected = inheritance.
Note: while accessing the protected variable through inheritance in the child class the parent class still needs to be
imported.
Note: Once the subclass outside the package inherits the protected member that member becomes private to any
code outside the subclass with the exception of subclasses of subclass.
• default – if you don’t type an access modifier before a class or member declaration, the access control is default.
A default member can be accessed only if the class accessing the member belong to the same package. So when
you think of default access think package restriction
Note: Access modifiers cannot be applied to local variables. There is only one modifier that can be applied to local
variable which is final.
Non Access modifiers for class members
final, abstract, transient, synchronized, native, strictfp.

• Modifiers applied to methods


a) final method: the final keyword prevents a method from being overridden in a subclass and is often used to
enforce the API functionality of the method.
final argument: if an argument is declared final it cannot be modified within a method i.e. the final argument must
keep the same value that the parameter had when it was passed to the method.
b) abstract method: An abstract method is a method that has been declared but not implemented. It has no method
body. You mark a method abstract when you want to force the subclasses to provide the implementation.
It is illegal to have a single abstract method in a class that is not explicitly declared abstract.
However you can have an abstract class with no abstract methods.
Any class that extends an abstract class must implement all abstract methods of the super class, unless the class is
also abstract.
A method can never ever be marked as both abstract and final or both abstract and private.
Abstract modifier can never be combined with static modifier.
c) Synchronized method: synchronized keyword indicates that a method can be accessed by only one thread at a
time.
Synchronized keyword can only be applied to method and not to classes or variables.
Synchronized modifier can be matched with any of the four access control levels i.e. public, private, protected,
default.
d) Native method: the native modifier indicates that the method is implemented in platform dependent code.
Native keyword can only be applied to methods.
Native methods body must be a semicolon (like abstract methods) indicating that the implementation is omitted.
e) Strictfp method: the strictfp forces floating point (and any floating point operations) to adhere to the IEEE 754
standard.
You can only declare a method to be strictfp , and a variable can never be declared strictfp.
Methods with Variable Argument Lists (var-args)
• Var-arg type: when you declare a var-arg parameter you
must specify the type of arguments this parameter of your
method can receive.
• To declare a method using var-arg parameter, you follow
the type with an elipsis, a space, and then the name of the
array that will hold the parameter received.
• void doStuff(int… x){ }
• The var-arg must be the last parameter in the methods’s
signature and you can only one var-arg in a method.
• Its legal to have other parameters in a method that uses
var-args
arguments vs parameters
• arguments: the thing you specify between
parenthesis when you are invoking a method
e.g. doStuff(“a”,2);
• parameters: the things in a method signature
that indicate what the method must receive
when its invoked.
constructors
• a constructor cannot have a return type.
• they must have the same name as the class in
which they are declared.
• constructors cant be marked static.
• Constructors cant be marked final or abstract.
• e.g. class Foo{
protected Foo(){}
}
variables
variables are of two type
a) primitives: these include byte, short, int, long, float, double, boolean, char. Once a primitive has been
declared its type can never change. These can be declared as class variables(statics), instance variables,
method parameters or local variables.
b) Reference variable is used to refer (or access) an object. A reference variable is declared to be of specific
type and that type can never change. A reference variable can be used to refer to any object of the declared
type or a subtype of the declared type. Reference variables can also be declared as static variables, instance
variables, method parameters or local variables. Objects are always created on a heap.
Instance variables: are defined inside a class but outside any method and are only initialized when a class is
instantiated. These can have any of the four access levels, can be marked final, can be marked transient.
local variables: are declared and initialized within a method. Local variable must be initialized before you use it
because they don’t get default values. These variables always lie on the stack. These can only use the access
modifier final. A local variable can’t be referenced outside the method in which it is declared.
final variables: declaring a variable with the final keyword makes it impossible to reinitialize the variable once it
has been initialized with an explicit value. A reference object variable marked final cant be reassigned to
refer to a different object . The data within the object can be modified. There are no final objects only final
references.
transient variables: if you mark an instance variable as transient you are telling the JVM to skip this variable
when you attempt to serialize the object containing it. Can only be applied to instance variables.
volatile variables: the volatile modifier tells the JVM that the thread accessing the variable must always
reconcile its own private copy of the variable with the ,master copy in memory. Can only be applied to
instance variables
static variables: the static modifier is used to create variables and method that will exist independently of any
instances created for the class. All static members exist before you ever make a new instance of the class
and there will be only one copy of the static member regardless of the number of instance of the class. You
cant mark constructors, classes, interfaces, local variables as static
Enums

• Declaring an enum outside a class


enum CoffeeSize { BIG, HUGE, OVERWHELMING}
class Coffee{
CoffeeSize size;
}
public class CoffeeTest1{
public static void main(String[] args){
Coffee drink = new Coffee();
drink.size = CoffeeSize.BIG;
}
• Declaring an enum within a class
class Coffee2{
enum CoffeeSize{ BIG, HUGE, OVERWHELMING}
CoffeeSize size;
}
public class CoffeeTest2{
public static void main(String[] args){
Coffee2 drink = new Coffee2();
drink.size = Coffee2.CoffeeSize.BIG;
}
}
Enums

• We cannot declare enum in methods.


• It is optional to put a semicolon at the end of enum declaration.
• Declaring Constructors, Methods and Variables in an enum.
private int ounces;
enum CoffeeSize { BIG(8), HUGE(10), OVERWHELMING(16) }
CoffeeSize(int ounces){
this.ounces = ounces
}
public int getOunces(){
return ounces
}
class Coffee{
CoffeeSize size;
public static void main(String[] args){
Coffee drink1 = new Coffee();
drink1.size = CoffeeSize.BIG;
Coffee drink2 = new Coffee();
drink2.size = CoffeeSize.OVERWHELMING;
System.out.println(drink1.size.getOunces());
for(CoffeeSize cs; CoffeeSize.values()){
System.out.println(cs + “” + cs.getOunces());
}
• You can never invoke an enum constructor directly.
• You can define more than one argument to the constructor and you can overload the enum constructors just as you
can overload a normal class constructor.
Object Oriented aspects of java
• Inheritance - – allows code defined in one class to be reused in other classes. In java you can define a general
super class and extend it with more specific super classes. The super class knows nothing of the classes that
inherit from it but all the subclasses that inherit from the superclass must explicitly declare the inheritance
relationship. A subclass that inherits from a superclass is automatically given access to instance variables and
methods defined by the superclass. It is also free to override the superclass methods to define a more specific
behavior.
Note: two common use of inheritance are code reuse and polymorphism.
• Polymorphism - Polymorphism is the ability of an object to take on many forms. The most common use of
polymorphism in OOP occurs when a parent class reference is used to refer to a child class object. Subclasses of
a class can define their own unique behaviors and yet share some of the same functionality of the parent class.
Polymorphism is an Oops concept which advice use of common interface instead of concrete
implementation while writing code.
Any Java object that can pass more than one IS-A test is considered to be polymorphic. In Java, all Java objects
are polymorphic since any object will pass the IS-A test for their own type and for the class Object.
• Abstraction - Abstraction is the concept of exposing only the required essential characteristics and behavior
with respect to a context. Abstraction in Java is achieved by  using interface and abstract class in Java. In order
to use interface or abstract class we need to extend and implement abstract method with concrete behavior. 
One example of Abstraction is creating interface to denote common behavior without specifying any details
about how that behavior works e.g. You create an interface called Server which has start() and stop() method.
This is called abstraction of Server because every server should have way to start and stop and details may
differ.
• Encapsulation -Binding (or wrapping) code and data together into a single unit is known as encapsulation.
For example: capsule, it is wrapped with different medicines. A java class is the example of encapsulation. Java
bean is the fully encapsulated class because all the data members are private here.
instanceof
• The instanceof operator returns true if the reference variable
being tested is of the type being compared to:
• class Test{
• public static void main(){
Test t1 = new Test();
Test t2 = new Test();
if(!t1.equals(t2)){
System.out.println(“they are not equal”);
}
if(t1 instanceof Object){
System.out.println(“t1 is an Object”);
}
}
Encapsulation
• The ability to make changes in code without breaking
the code of others is the key benefit of encapsulation.
• How to make your design include encapsulation.
a) keep instance variables protected (with an access
modifier often private)
b) Make public accessor methods and force calling code to
use those methods rather than directly accessing the
instance variables.
c) For the methods use the JavaBeans naming convention
of set<someProperty> and get<someProperty>
Object Class
• Every class in java is a subclass of the Object
class except the Object class itself.
• Every class you’ll ever use or ever write will
inherit from the class Object.
•  The methods inherited from Object are,
clone(), wait(), notify(), notifyAll(), finalize(),
getClass(), hashCode(), toString() which
Inheritance
• The two most common reasons to use inheritance are:
a) To promote code reuse
b) To use polymorphism.
class GameShape{
public void displayShape(){
System.out.println(“displaying shape”);
}}
class PlayerPiece extends Gameshape{
public void movePiece(){
System.out.println(“moving game piece”);
}}
class TilePiece extends Gameshape{
public void getAdjacent(){
System.out.println(“getting adjascent tiles”);
}}
public class TestShape{
public static void main (String[] args){
PlayerPiece player = new PlayerPiece();
TilePiece tile = new TilePiece();
doshapes(player);
doshapes(tile);
}
public static void doShapes(GameShape shape){
shape.displayShape();
}}
//Output - displaying shape, displaying shape
IS-A and HAS-A
• In OO, the concept of IS-A is based on class inheritance or interface. IS-A is a way of saying “this thing is a type of that thing” e.g.
Brocolli IS-A vegetable.
• You express IS-A relationship in Java through the keywords extends (for class inheritance) and implements (for interface
implementation).
• HAS-A relationships are based on usage rather than inheritance. class A HAS-A B if code in class A has a reference to instance of
class B.
• If the below code exists then , A Horse HAS-A Halter.
• public class Animal{ }
public class Horse extends Animal {
private Halter myHalter;
}
HAS-A relationship allows you to design classes that follow good OO practises. By not using monolithic classes that do a gazillion
things. By keeping the Halter code in a specialized separate class, you have the chance to reuse the class in multiple applications.
• public class Animal{ }
public class Horse extends Animal {
private Halter myHalter = new Halter();
public void tie(LeadRope rope){
myhalter.tie(rope);
}
}
public class Halter{
public void tie(LeadRope rope){
// Do the actual tie work here
}
}
Key things to remember about references.

• A reference variable can be only of one type and once


declared that type can never be changed(although the object
it references can change).
• A reference is a variable, so it can be reassigned to other
objects (unless the reference is declared final).
• A reference variable’s type determines the methods that can
be invoked on the object the variable is referencing.
• A reference variable can refer to any object of the same type
as the declared reference or it can refer to any subtype of the
declared type.
• A reference variable can be declared as a class type or an
interface type. If the variable is declared as an interface type, it
can reference any object of any class that represents the
interface.
Polymorphism
• A class cannot extend more than one class.
• Any Java Object that can pass more than one IS-A
test can be considered polymorphic.
• Other than objects of the type Object, all java
objects are considered polymorphic in that they
pass the IS-A test for their own type and for the
class Object.
• Polymorphic method invocations apply only to
instance methods. Not static methods, not
variables. Only overridden instance methods are
dynamically invoked based on real object’s type.
Hiding the implementation using an interface.
• public interface Animatable{
public void animate();
}
class PlayerPiece implements Animatable{
public void animate(){
System.out.println(“animating..”);
}}
class TilePiece implements Anitatable{
public void animate(){
System.out.println(“animating..”);
}}
public class TestShapes{
public static void main(String args[]){
PlayerPiece pp = new PlayerPiece ();
TilePiece tp = new TilePiece ();
TestShapes ts = new TestShapes();
ts.doShapes(pp);
ts.doShapes(tp);
}
public void doShapes(Animatable anmtb){
anmtd.animate();
}}
Overriding / Overloading
• Overridden methods – any time you have a class that inherits a method from a super class you have the
opportunity to override the method (unless the method is marked final).
• Method overriding
class Animal{
public void eat(){
System.out.println(“Generic animal eating Generically”);
}}
class Horse extends Animal{
public void eat(){
System.out.println(“Horse eating hay, oats, “ + “and horse treats”);
}
public void buck(){ }
public class TestAnimals{
public static void main(String[] args){
Animal a = new Animal();
Animal b = new Horse();
a.eat(); // Runs the animal version of eat()
b.eat(); // Runs the horse version of eat
Animal c = new Horse();
c.buck(); // Can’t invoke buck
//Animal class doesn’t have that method.
}
Rules for Overriding a method
Rules for Overriding a method
• arguments- must not change. The arguments list must exactly match that of
the overridden method.
• return type – can’t change except for covariant returns. The return type must
be the same as or a subtype of the return type declared in the original
overridden method in the superclass.
• exceptions – can reduce or eliminate, must not throw new or broader
checked exceptions. The overriding must not throw checked exceptions that
are new or broader than those declared by the overridden method.
• access – must not make more restrictive. The access level can’t be more
restrictive than the overridden method.
• invocation - object type (the type of actual instance on the heap) determines
which method is selected, happens at runtime.
• you cannot override a method marked final or static
• if a method can’t be inherited you cannot override it.
Invoking a superclass version of an Overridden method
super.overridden_method();
Rules for Overloading a method
• Overloaded methods MUST change the argument list.
• Overloaded methods CAN change the return type.
• Overloaded methods CAN change the access modifier.
• Overloaded methods CAN declare new or broader checked
exceptions.
• A method CAN be overloaded in the same class or in a sub
class.
• The choice of which overloaded method to call is not decided
dynamically at runtime. The reference type of the arguments
passed at compile time determines which overloaded version
is selected.
• Polymorphism doesn’t determine which overloaded version is
called.
How to use parent class reference variable to invoke a method that only child class has

• class Animal{
void makeNoise(){
System.out.println(“generic noise”);
}
class Dog extends Animal{
void makeNoise(){
System.out.println(“bark”);
}
void playDead(){
System.out.println(“roll over”);
}
class CastTest{
public static void main(String [] args){
Animal [] a = {new Animal(), new Dog(), new Animal()};
for(Animal animal : a){
if(animal instanceof Dog){
Dog d = (Dog) animal;
d.playDead();
}}}}
Upcasting

• class Animal{ }
• class Dog extends Animal{ }
• class DogTest{
public static void main(String[] args){
Dog d = new Dog();
Animal a1 = d;
Animal a2 = (Animal)d;
}
Implementing an Interface
• In order to be a legal implementation class a non abstract class
must do the following:
• Provide concrete implementations for all methods from the
declared interface.
• Follow all the rules for legal overrides.
• Declare no checked exceptions on implementation methods
other than those declared by the interface or subclasses of
those declared by the interface method.
• Maintain the signature of the interface method and maintain
the same return type. But it does not have to declare the
exceptions declared in the interface method declaration.
• If the implementation class is abstract, it can simply pass the
buck to its first concrete subclass.
Interface
• A class can implement more than one interface.
public class Ball implements Bounceable, Serializable, Runnable{ …}
• An interface can itself extend another interface, but never
implement anything.
public interface Bounceable extends Moveable{ …}
• An interface is free to extend multiple interfaces.
• If a class is marked abstract, it could choose to implement any, all,
or none of the methods from any of the interfaces thus leaving the
rest of the implementations to a concrete subclass of ball.
• an interface can’t implement an interface
• an interface can’t implement a class.
• an interface can’t extend a class.
• An interface can extend an interface
Return Types
• On overloaded method – you can declare any return type. To overload
a method you must change the argument list. The return type doesn’t
have to match the superclass version.
• On overridden method – you are allowed to change the return type in
the overriding method as long as the new return type is a subtype of
the declared return type of the overridden method.
• You can return null in a method with an object reference return type.
• Array is a perfectly legal return type.
• In a method with a primitive return type, you can return any value or
variable that can be implicitly converted to the declared return type.
• You must not return anything from a method with a void return type.
• In a method with an object reference return type, you can return any
object that can be implicitly cast to the declared return type.
Constructors
• You can’t make a new object without invoking not just the constructor of the
object’s actual class type but also the constructor of each of its super classes.
• Constructors are the code that runs when you use the keyword new.
• Every class including abstract classes must have a constructor. Abstract classes
have constructors and those constructors are always called when a concrete
class is instantiated.
• Typically constructors are used to initialize the initial variable state.
• Its very common for a class to have a no argument constructor regardless of
how many other overloaded constructor are there in a class.
• Every constructor invokes the constructor of its super class with an implicit call
to super, unless the constructor invokes an overloaded constructor of the same
class.
• Interfaces do not have constructors. Interfaces are not part of an object’s
inheritance tree.
• The only way a constructor can be invoked is from within another constructor.
Rules for constructors

• A constructor can use any access modifier including private.


• The constructor name must match the name of the class.
• Constructors must not have a return type.
• If you don’t type a constructor into your code, a default constructor will automatically
be generated by the compiler.
• The default constructor is always a no argument constructor.
• If you have typed a constructor with arguments you won’t have a no argument
constructor in your class.
• Every constructor has as its first statement, either a call to an overloaded constructor
this() or a call to the superclass constructor super(). This call can be implicitly inserted
by the compiler.
• If you type in a constructor and you do not type in the call to this, the compiler will
insert a no-arg call to super for you as the very first statement of the constructor.
• A call to super can either be a no arg call or it can include argument passed to the super
constructor.
• A no-arg constructor is not necessarily the default constructor, however the default
constructor is always a no-arg constructor.
• You cannot make a call to an instance method or access an instance variable until after
the super constructor runs.
• Only static variables and methods can be accessed as part of the call to super() or this()
Rules for constructors

• Constructors are never inherited.


• A call to this() always means a call to another
constructor in the same class.
• The first line in a constructor must be a call to
super() or a call to this(). if you neither have
those calls in your constructor, the compiler
will insert a no-arg call to super.
Default Constructor
• The default constructor has the same access modifier as
the class.
• The default constructor has no arguments.
• The default constructor includes a no-arg call to the
super constructor.
• If a class has no constructor then a default constructor
is added with an implicit call to super()
• If the default constructor does not have an implicit call
to super() then the call is inserted
• If your super() constructor has arguments you must type
in the call to super() supplying the appropriate
arguments.
Static variables and methods
• The methods behavior has no dependency on the state
(instance variable values) of an object.
• You need to have only the class available to invoke the static
method or access a static variable.
• If there are instances, a static variable of a class will be shared
by all the instances of that class.
• The static variables get the same default values, instance
variables get hence you don’t need to initialize a static
variable to zero.
• A static method can’t access a non static variable because
there is no instance.
• A static method can’t directly invoke non-static method.
• static methods cannot be overridden.
Coupling & Cohesion
• Coupling is the degree to which one class knows about
another class. The knowledge that a class A has about class B
should only be exposed through its interface and in such a
case A and B are loosely coupled. Thus coupling has to do
with how classes interact with each other.
• If class A relies on parts of class B that are not part of class
B’s interface then the coupling between the classes is tighter.
• Cohesion is used to indicate the degree to which the class
has a single well focused purpose. A key benefit of high
cohesion is that such classes are typically much easier to
maintain. Also classes with well focused purpose tend be
more reusable than other classes.
Chapter 3 – Stack and Heap
Here are few differences between stack and heap memory in Java:

1) Main difference between heap and stack is that stack memory is used to store 
local variables and function call, while heap memory is used to store objects in Java. No
matter, where object is created in code e.g. as member variable, local variable or class
variable,  they are always created inside heap space in Java.
Instance variables and objects live on heap
Local variables and fuction call are created on stack.
• 2) Each Thread in Java has there own stack which can be specified using -Xss JVM
parameter, similarly you can also specify heap size of Java program using JVM option -Xms
and -Xmx where -Xms is starting size of heap and -Xmx is maximum size of java heap. to
learn more about JVM options see my post 10 JVM option Java programmer should know.
• 3) If there is no memory left in stack for storing function call or local variable, JVM will
throw java.lang.StackOverFlowError, while if there is no more heap space for creating
object, JVM will throw java.lang.OutOfMemoryError: Java Heap Space. Read more about
how to deal with java.lang.OutOfMemoryError  in my post 2 ways to solve
OutOfMemoryError in Java.
• 4) If you are using Recursion, on which method calls itself, You can quickly fill up stack
memory. Another difference between stack and heap is that size of stack memory is lot
lesser than size of  heap memory in Java.
• 5) Variables stored in stacks are only visible to the owner Thread, while objects created in
heap are visible to all thread. In other words stack memory is kind of private memory of Java
Threads, while heap memory is shared among all threads.
Primitive size in bytes
• 1 byte = 8 bits
• 1 short = 2 bytes = 16 bits
• 1 int = 4 bytes = 32 bits
• 1 long = 8 bytes = 64 bits
• 1 float = 4 bytes = 32 bits
• 1 double = 8 bytes = 64 bits
• 1 boolean = represents 1 bit of information but its
size is not precisely defined.
• 1 char = 16 bit unicode character
Integers and int
• there are 3 ways to represent integer numbers in java language.
Decimal: they are represented with no prefix of any kind in java language
Octal: use digits from 0 to 7. Integers are represented in octal form by
putting a zero in front of the number
Hexadecimal: use digits from 0 through 15. We use alphabetic characters
to represent digits from 10 through 15. Integers are represented in octal
form by prefix 0x or the optional suffix extension L.
• A literal integer such as 7 is always implicitly an int.
• If you are assigning an int to a byte variable you would need to cast the
int e.g.
byte b = (byte)27;
• The result of an expression involving anything int-sized or smaller is
always an int.
Float and Double
• If you want to assign floating point literal to variable of
the type float you must attach the suffix F or f to the
number.
• float f = 23.46780F
• If you do not assign f or F then the number is assumed
to be a double. i.e. every floating point literal is implicitly
a double not a float.
• double d = 32.3;
float f = (float)32.3;
boolean and char
• A boolean variable can only be assigned true or false
values and nothing else.
• For a character you can also type in its unicode value.
char letterN = ‘\u004E’;
• You can use an escape code if you want to represent a
character that can’t be typed in as a literal
char c = ‘\”’; // a double quote
char d= ‘\n’; // a newline
• You can assign a number literal to a char variable assuming
that assuming that it will fit into the unsigned 16 bit range.
variables
• Variables are just bit holders with a designated type.
You can have an int holder, a double holder, a Button
holder and even a String[] holder. Within that holder
is a bunch of bits representing the value.
• A variable referring to an object is just a reference
variable. A reference variable bit holder contains bits
representing a way to get to the object.
• Instance variables are variables defined at the class
level. This means that the variable declaration is not
made within a method constructor or any other
initialization block.
Casting
• implicit cast – means that you don’t have to write code for the cast.
The conversion happens automatically. Implicit cast happens when
you are doing a widening conversion.
• explicit cast – explicit code has to be written, this happens typically
when we tried to put a larger thing into a smaller container. e.g.
float a = 100.001f
int b = (int)a;
int x = (int)3957.229;
• if a long value which is larger than 127 is being cast in a byte then the
bits to the left of lower 8 just go away. If the left most bit (the sign
bit) happens to be a 1, the primitive will have a negative value.
• To find the value of a negative integer flip all the bits and add one.
Assignment
• When you assign one primitive variable to
another primitive variable the contents of the
right hand variables are copied. Also the two
variable have no other relationship. If we
change either the contents of a or b the other
variable won’t be affected.
int a = 6;
int b = a;
Variable Scope

• Static variables have the longest scope. They are


created when the class is loaded and they survive
as long as the class stays loaded in the Java Virtual
Machine.
• Instance variables are the next most long lived.
They are created when a new instance is created
and they live until the instance is removed.
• Local variables are the next. They live as long as
their method remains on the stack.
• Block variables live as long as the code block is
executing.
Scoping Errors
• Attempting to access an instance variable from
a static context (typically from the main()
method).
• Attempting to access a local variable declared
in parent method from the nested method.
• Attempting to use the block variable after the
block has completed.
variable initializing
• Instance variables are initialized to default value each time a new instance is created.
variable type default value
Object reference - null
byte, short, int, long 0
float, double 0.0
booleanfalse
char ‘\u0000’
• local variable must be assigned a value or the compiler will complain. Java does not give local variables default
values.
• If you initialize within a logically conditional block, the compiler knows that the initialization might not happen
and can produce an error. Hence you will sometimes need to initialize your variable outside the conditional block
just to make the compiler happy.
• With instance variable object reference you can leave the object reference uninitialized as long as the code
checks to make sure that the reference is not null before using it. Instance variable references are always given
default value of null.
• Local references are not give a default values and if not initialized it does not have any value.
• Array elements are always given default values regardless of where the array is declared as an instance or a local
variable. If the array contains primitives then they will be given their respective default values. The array object
itself will not be initialized if declared locally. In other words you must explicitly initialize an array reference if its
declared and used within a method. But at the moment you construct an array object all its elements are
assigned their default values.
• If we initialize an array, object reference element will equal null if its not initialized individually with values.
• If you assign a reference variable a to a reference variable b, the bit pattern in a is copied and the new copy is
placed in b.
• If we assign an existing reference to an object to a new reference variable, the two reference variables will hold
the same bit pattern i.e. both the references refer to the same instance of the dimension object.
passing reference variables into a method

• If you are passing a primitive to a method, you are


passing a copy of the bits in the variable. The caller
method can’t change the callers variable. Refer page
216.
• When you pass an object reference variable into a
method, you are passing a copy of bits representing
the reference to an object. If the called method
modifies the object, then the object referred by the
callers original variable changes.
• A method can change the state of the object that
reference variable refers f to but it cannot make f
refer to a different object.
Arrays
• Arrays can hold primitives or object references but the array itself will always be an
object on the heap.
• Constructing an array means creating an object on the heap.
• Arrays must always be given size at the time they are constructed.
• Arrays can have only one declared type e.g. (int [], Dog [], String[])
• Primitive arrays can accept any values that can be promoted implicitly to the
declared type of the array.
• If the declared array type is a class you can put objects of any subclass of the
declared type into the array.
• If the array is declared as an interface, the array elements can refer to any instance of
any class that implements the declared type.
• Any object that passes the “IS-A” test for the declared array type can be assigned to
an element of the array
• Arrays of the type byte, short, or char cannot be assigned to int array.
• An array declared as an interface type can reference an array of any type that
implements the interface.
• When you assign an array to a previously declared array reference, the array you are
assigning must be the same dimension as the reference you are assigning it to.
Array Declaration, Construction, Initialization
• Declaring an array of primitives
int[] key;
• Declaring an array of object references
Thread[] threads;
Note: Its never legal to include the size of array in your declaration.
• Constructing one dimensional array.
int[] testScores;
testScores = new int[4];
• Constructing two dimensional array.
int [] [] myArray = new int [3] [];
Note:Only the first brackets are given size as the JVM needs to know only the size of the object
assigned to the variable myArray.
• Initializing one dimensional array
Animal [] pets = new Animal[3];
pets[0] = new Animal(); pets[1] = new Animal(); pets[2] = new Animal;
• Initializing two dimensional array
int [] [] scores = new int [3] [];
scores[0] = new int [4];
scores[1] = new int [6];
scores[2] = new int [1];
Declaring, Constructing an initializing in one line

• int [] dots = {6, 9, 8}


• Dog[] mydogs = {new Dog(“Frodo”), new Dog(“Clover”), new
Dog(“Aiko”)}
• int [] [] scores = {{5,2,4,7},{9,2},{3,4}}
• Constructing and initializing an anonymous array.
• int [] testscores;
testScores = new int []{4,7,2};
• With this new syntax you don’t even need to assign the array to
anything.
• You can use the above syntax to create a just in time array to use
for example as an argument to a method that takes an array
parameter. e.g.
Foof f = new Foof();
f.takesAnArray(new int []{4,7,2});
Rules for initialization blocks

• If a class has more than one initialization blocks then


they will run in the order in which initialization blocks
appear in the file.
• A Static initialization block run once when the class is
first loaded
• An instance initialization block runs every time a new
instance is created.
• Instance init blocks run after the constructor’s call to
super.
Note: Instance init blocks are often used as a place to put
code that all the constructors in a class would share.
Wrapper classes

• Wrapper classes provide mechanism to wrap primitive values


in an object so that the primitives can be added to Collection
or returned from a method with an object return value.
• Wrapper classes provide an assortment of utility functions for
primitives.
• Wrapper objects are immutable. Once they have been given a
value that value cannot be changed.
• All wrapper classes except character provide two
constructors. One that takes a primitive of the type being
constructed and one that takes a String representation of the
type being constructed. Character class provide only one
constructor which takes a char as an argument.e.g.
• Character c1 = new Character(‘c’);
Methods provided in wrapper classes
• valueOf():
The two static value of methods provided in most of the wrapper
classes give you another method of creating wrapper objects. The first
method takes additional argument that indicates in what base the first
argument is represented.
Integer i2 = Integer.valueOf(“101011”,2);
Float f2 = Float.valueOf(“3.14”);
• xxxValue():
The following methods are used when you need to convert the value
of a wrapped number to primitive or to a primitive of another type.
• Integer i2 = new Integer(42)
byte b = i2.byteValue();
short s = i2.shortValue();
double d = i2.doubleValue();
Methods provided in wrapper classes

• parseXxx() and valueOf()


• parseXxx() returns the named primitive e.g.
double d4 = Double.parseDouble(“3.14”);
• valueOf() returns a newly created wrapped object of
the type that invoked the method
Double d5 = Double.valueOf(“3.14”);
• Both parseXxx() and valueOf() take a String as an
argument and throw a NumberFormatException if the
String argument is not properly formed.
• These methods can also convert sString arguments
from various bases.
Methods provided in wrapper classes

• toString()
• this method allows you to get meaning
representation of the given object.
• This method returns a String with the value of
the primitive wrapped in the object e.g.
Double d = new Double(“3.14”);
System.out.println(“d= “ + d.toString() );
Autoboxing and Metadata(Annotations)

• J2SE 5 adds a powerful new facility to java


called metadata which enables you to embed
supplemental information into a source file.
This information called an annotation, does not
change the actions of a program. Thus an
annotation leaves the semantics of a program
unchanged. However this annotation can be
used by various tools during both development
and deployment. For example an annotation
might be processed by a source-code
generator.
Creating an annotation
• An annotation is created through a mechanism based on the interface.
• Here is the declaration for an annotation called MyAnno:
• @interface MyAnno {
String str();
int val();
}
• All annotations solely consist of method declarations. However you don’t provide bodies for
these methods. Instead Java implements these methods
• Moreover the methods act much like fields
• All annotation types automatically extends the Annotation interface. Thus Annotation is a
super-interface of all annotations. It is declared within the java.lang.annotation package. It
overrides hashCode(), equals(), and toString() which are defined by Object. It also specified
annotationType() which returns a Class object that represents the invoking Annatation.
• Once you have declared an annotation, you can use it to annotate a declaration.
• Any type of declaration can have an annotation associated with it e.g. classes, methods,
methods, parameters, and enum constants can be annotated. Even an annotation can be
annotated.
• Given below is an example of MyAnno being applied to a method
@MyAnno(str = “Annotation Example”, val = 100)
public static void myMeth(){
Annotation retention policies

• Thus annotation members look like fields in this context. The String “Annotation
Example ” is assigned to str member of MyAnno. Notice that no parenthesis follow str in
this assignment.
• Thus when an annotation member is given a value only its name is used.
• Annotation retention policies
• A retention policy determines at what point an annotation is discarded.
• Java defines three such policies which are encapsulated within the
java.lang.annotation.RetentionPolicy enumeration. They are SOURCE, CLASS, RUNTIME
• An annotation with a retention policy of SOURCE is retained only in the source file and
is discarded during compilation.
• An annotation with a retention policy of CLASS is stored in the .class file during
compilation however it is not available through the JVM during runtime.
• An annotation with a retention policy of RUNTIME is stored in the .class file and is
available through the JVM during the runtime.
• A retention policy is specified for an annotation using one of Java’s built in annotations
@Retention(retention-policy)
• If no retention policy is specified for an annotation then default policy of CLASS is used.
Example -Annotation retention policy

• @Retention(RetentionPolicy.RUNTIME)
@interface(MyAnno){
string str();
int val();
}
Obtaining Annotations at Run Time by the use of Reflection

• Step 1 – Obtain a Class object of the type java.lang.Class


that represents the class whose annotations you want to
obtain. This can be done using the getClass() method
defined by the Object.
final Class getClass()
• Step2 – if the annotation is defined on a method then get a
Method object that represents this method. This is done by
calling the getMethod() on that Class object specifying the
name of the method. getMethod returns a Method object
that represents the method.
• Step3 – get the specific annotation associated with that
object by calling getAnnotation()
• Step4 – finally display the values
Class Object
• First step to using reflection is to obtain a Class object that
represents the class whose annotations you want to obtain
• Class is one of java’s built in classes and is defined in java.lang
• the easiest way to obtain a class object is to call getClass()
which is a method defined by Object
• final Class getClass()
• If you want to obtain the annotations associated with a
specific item declared within a class you must first obtain an
object that represents that item.
• Class supplies the getMethod(), getField(), getConstructor()
methods which obtain information about a method, field,
constructor. these methods return objects of type Method,
Field, Constructor which are classes.
Obtaining Annotations at Run Time by the use of Reflection
• import java.lang.annotation.*;
import java.lang.reflect.*;

//an annotation type declaration


@Retention(RetentionPolicy.Runtime)
@interface MyAnno{
String str();
int val();
}

class Meta {
// Annotate a method.
@MyAnno(str = “Annotation Example”, val = 100)
public static void myMeth() {
Meta ob = new Meta();
try {
Class c = ob.getClass
Method m = c.getMethod(“myMeth”);
MyAnno anno = m.getAnnotation(MyAnno.class);
System.out.println(anno.str() + “ “ + anno.val());
}catch(NoSuchMethodException exc){
System.out.println(“Method not found”);
}
}
public static void main(String args[]){
myMeth();
}
}

NOTE: the output from this class is: Annotation Example 100
Obtaining Annotations at Run Time when myMeth() as two parameters
• import java.lang.annotation.*;
import java.lang.reflect.*;

//an annotation type declaration


@Retention(RetentionPolicy.Runtime)
@interface MyAnno{
String str();
int val();
}

class Meta {
// Annotate a method.
@MyAnno(str = “Two Parameters”, val = 19)
public static void myMeth(String str, int i ) {
Meta ob = new Meta();
try {
Class c = ob.getClass
Method m = c.getMethod(“myMeth”, String.class, int.class);
MyAnno anno = m.getAnnotation(MyAnno.class);
System.out.println(anno.str() + “ “ + anno.val());
}catch(NoSuchMethodException exc){
System.out.println(“Method not found”);
}
}
public static void main(String args[]){
myMeth(“test”, 10);
}
}
NOTE: the output from this class is: Two Parameters 19
Obtaining All Annotations
• import java.lang.annotation.*;
import java.lang.reflect.*;

//an annotation type declaration


@Retention(RetentionPolicy.Runtime)
@interface MyAnno{
String str();
int val();
}

@Retention(RetentionPolicy.Runtime)
@interface What{
String description();
}
@What(description = “An annotation test class”)
@MyAnno(str = “Meta2”, val = 99)
class Meta2 {
PTO
Obtaining All Annotations
class Meta2 {
@What(description = “An annotation test method”)
@MyAnno(str = “Testing”, val = 100)
public static void myMeth(){
Meta2 ob = new Meta2();
try{
Annotation annos[] = ob.getClass.getAnnotations();
//display all annotations for Meta2
System.out.println(“All annotations for Meta2:”);
for (Annotation a : annos)
System.out.println(a);

//display all annotations for myMeth


Method m = ob.getClass().getMethod(“myMeth”)
annos = m.getAnnotations();
System.out.println(“All annotations for myMeth:”);
for (Annotation a : annos)
System.out.println(a);
}catch(NoSuchMethodException exc){
System.out.println(“Method not found”)
}
public static void main(String arg[]){
myMeth();
}
}
AnnotatedElement Interface

• AnnotatedElement interface is defined in java.lang.reflect


• This interface supports reflection for annotations and is
implemented by the classes Method, Field, Constructor,
Class and Package
• Methods defined by AnnotatedElement interface:
a) Annotation getAnnotation()
b) Annotation[] getAnnotations()
c) Annotation[] getDeclaredAnnotations() – this method
returns all the non-inherited annotations present in the
invoking object
d) boolean isAnnotationPresent() – this emthod returns true if
the annotation specified by AnnoType is associated with the
invoking object.
Using Default Values
• You can give annotation members default
values that will be used if no value is specified
when the annotation is applied.
• A default value is specified by adding a default
clause to a member’s declaration
• It has a general form:
type member() default value
• Here value must be of a type compatible with
type
Program demonstrating default values in an annotation
• import java.lang.annotation.*;
import java.lang.reflect.*;

//an annotation type declaration that includes defaults


@Retention(RetentionPolicy.Runtime)
@interface MyAnno{
String str() default “Testing”;
int val() default 9000;
}

class Meta3 {
PTO
class Meta3 continued

class Meta3 {
// Annotate a method using the default values
@MyAnno()
public static void myMeth(){
Meta3 ob = new Meta3();
//obtain the annotation for this method and display the values of the members
try{
Class c = ob.getClass();
Method m = c.getMethod(“myMeth”)
MyAnno anno = m.getAnnotation(MyAnno.class);
System.out.println(anno.str() + “ ” + anno.val());
}catch(NoSuchMethodException exc){
System.out.println(“Method not found”)
}
public static void main(String arg[]){
myMeth();
}
}
Marker Annotations

• A marker annotation is a special kind of annotation that


contains no members.
• Its sole purpose is to mark a declaration
• Thus its presence as an annotation is sufficient.
• The best way to determine if a marker annotation is
present is to use the method isAnnotationPresent().
• The method isAnnotationPresent() is defined by
AnnotatedElement interface.
• In the program that follows notice that you do not need
to follow @MyMarker with parenthesis when it is
applied. Thus @MyMarker is applied simply by using its
name.
Example that uses a marker annotation
import java.lang.annotation.*;
import java.lang.reflect.*;

// A marker annotation
@Retention(RetentionPolicy.RUNTIME);
@interface MyMarker { }

class Marker {
// Annotate a method using a marker
//notice that no { } is needed

@MyMarker
public static void myMeth(){
Marker ob = new Marker();
//obtain the annotation for this method and display the values of the members
try{
Method m = ob.getClass().getMethod(“myMeth”);
// Determine if the annotation is present
if(m.isAnnotationPresent(MyMarker.class));
System.out.println(“MyMarker is present”);
}catch(NoSuchMethodException exc){
System.out.println(“Method not found”)
}
public static void main(String arg[]){
myMeth();
}
}
Single-Member Annotations
• A single-member annotation contains only one
member.
• It works like a normal annotation except that it allows a
shorthand form of specifying the value of the member.
• When only one member is present you can simply
specify the value for that member without specifying
that name of that member.
• You can use the single value syntax when applying an
annotation that has other members but those other
members must all have default values.
• Remember when you are using a single-member
annotation, the name of that member must be value.
Built-in Annotations
• @Retention – it specifies the retention policy as described earlier in this chapter. It is
designed to be used only as an annotation to another annotation.
• @Documented – this annotation is a marker interface that tells a tool that an annotation is to
be documented. It is designed to be used as an annotation to annotation declaration.
• @Target – this annotation specifies the types of declarations to which an annotation can be
applied. @Target takes one argument which must be a constant from the ElementType
enumeration. You can specify one or more of these values in a @Target annotation. It is
designed to be used only as an annotation to another annotation e.g.
@Target({ElementType.FIELD, ElementType.LOCAL_VARIABLE})
• @Inherited – this annotation is a marker annotation and can be used only on another
annotation declaration. Further more it affects only annotations that will be used on class
declarations. @Inherited causes annotation for a superclass to be inherited by a subclass.
Therefore when a request for a specific annotation is made to a subclass, if that annotation is
not present in the subclass, then its superclass is checked. If that annotation is present in the
superclass, and if it is annotated with @Inherited, then that annotation will be returned.
• @Override - this annotation is a marker annotation that can e used only on methods. A
method annotated with @Override must override a method from a subperclass. If it doesn’t
a compole time error will result.. It is used to ensure that a superclass method is actually
overridden and not simply overloaded.
Built-in Annotations

• @Deprecated – this is a marker annotation. It


indicates that a declaration is obsolete and has
been replaced by a newer form.
• @SuppressWarnings – specifies that one or
more warnings that might be issued by the
compiler are to be suppressed. The warnings
to suppress are to be supplied by name in
string form. This annotation can be applied to
any type of declaration.
Restrictions on annotations

• no annotation can inherit another


• all methods declared by an annotation must be without
parameters
• they must return one of the following
a) a primitive type such as int or double
b) an object of type String or Class
c) an enum type
d) another annotation type
e) an array of one of the preceding types.
• Annotations cannot be generic. They cannot take type
parameters
• Annotations cannot specify a throw clause.
Single Member Annotation
import java.lang.annotation.*;
import java.lang.reflect.*;

// A marker annotation
@Retention(RetentionPolicy.RUNTIME);
@interface MySingle {
int value(); //this variable name must be value
}

class Single{
// Annotate a method using a single-member annotation
@MySingle(100)
public static void myMeth(){
Single ob = new Single();
try{
Method m = ob.getClass().getMethod(“myMeth”);
MySingle anno = m.getAnnotation(MySingle.class);
System.out.println(anno.value());
}catch(NoSuchMethodException exc){
System.out.println(“Method not found”)
}
public static void main(String arg[]){
myMeth();
}
}
Overloading
• Method Matching
• Find which overloaded method will be invoked in case of multiple overloaded
methods
When an exact match is not found, the JVM uses the method with the smallest
argument that is wider than the parameter.
• If the compiler has to choose between widening and boxing, the choice will be
widening.
• If the compiler has to choose between widening and var-arg, the choice will be
widening.
• If the compiler has to choose between Boxing and var-arg, the choice will be Boxing.
Note: var-args method is a looser and is the last option.
• Widening of a reference variable is possible if the reference variable passes ‘IS-A’ test
• Its not legal to widen from one wrapper class to another.
• You cannot widen and then box
• You can box and then widen
• You can combine var-args with widening or boxing.
• Used individually boxing and var-args are compatible with overloading.
Garbage Collection.
• Java’s garbage collection provides automatic solution to memory management.
• Its typical for the memory to be used to create a stack, a heap, in java’s case constant
pools, method areas.
• All of garbage collection revolved around making sure that the heap has as much free
space as possible.
• When garbage collector runs, its purpose is to find and delete objects that cannot be
reached.
• The JVM decides when to run the garbage collector.
• An object is eligible for garbage collection when no live thread can access it i.e.
there are no reachable references to it.
• Due to vagaries of the String constant pool this garbage collection discussion applies
to non String objects.
• When we talk of reaching an object we are talking about having a reachable reference
variable that refers to the object in question.
• If our java program has a reference variable that refers to an object and that reference
variable is available to a live thread, then that object is considered reachable.
• If you maintain too many live objects (objects reference from other live objects) the
system can run out of memory.
Garbage Collection
• ways of removing reference to an object:
1) set the reference variable that refers to an object to null e.g.
StringBuffer sb = new StringBuffer(“hello”);
sb = null;
2) reassigning the reference variable:
StringBuffer sb1 = new StringBuffer(“hello”);
StringBuffer sb 2= new StringBuffer(“goodbye”);
sb1 = sb2;
Note: the StringBuffer hello is eligible for garbage collection.
3) Isolating a reference
Island i;
Island i2 = new Island();
Island i3 = new Island();
Island i4 = new Island();
i2.i = i3;
i3.i=i4;
i4.i=i2;
i2=null;
i3=null;
i4=null;
Note: I2, i3,i4 are eligible for garbage collection
Garbage Collection

• When is a local object not eligible for garbage


collection:
Once a method has returned objects created
in the method are eligible for garbage
collection. If an object is returned from a
method and its reference might be assigned to
a reference variable in the method that called
it then the object is not eligible for GC.
• Garbage collection can be invoked using
System.gc();
Runtime class
• How to get Runtime instance
Runtime rt = Runtime.getRuntime();
• How to get total JVM memory
Total JVM Memory: + rt.totalMemory();
• How to get free memory
Free Memory: + rt.freeMemory();
• How to call garbage collection
rt.gc();
finalize()
• For any given object finalize() will be called
only once by the garbage collector.
• finalize() method runs before the object is
deleted by the GC.
• finalize() method is not guaranteed to run. So
don’t put your essential code in finalize.
• Calling finalize can actually result in saving an
object from deletion
Chapter4 - Java Operators
Java Operators
• The result of most operations is either a boolean or numeric value.
• Java operators which are overloaded are as below:
1) The plus operator can be used to add two primitives together or to perform a
concatenation operation if either operand is a String.
2) The &, |, ^ operators can be used in two different ways
a)The bitwise AND " &" operator  produces 1 if and only if both of the bits in its
operands are 1. However, if both of the bits are 0 or both of the bits are different then
this operator produces 0
b) The bitwise OR "|" operator produces 1 if either one of the bits in its operands are
1. However, if both of the bits are 0 or both bits are 1 then this operator produces 0. 
0 | 0 == 0; 1 | 0 == 1 ; 0 | 1 == 1 ; 1 | 1 == 1
c) The bitwise OR “^" operator(exclusive OR)  that provides the answer '1' if both of
the bits in its operands are different, if both of the bits are same then the XOR
operator gives the result '0'. XOR is a binary operator that is evaluated from left to
right.
0 ^ 0 == 0;1 ^ 0 == 1 ;0 ^ 1 == 1 ;1 ^ 1 == 0
Compound Assignment Operators

• Four assignment operators are commonly


used are: *=, /=, +=, -=
• * and / have higher precedence than = and –
• When using the compound assignment
operator, the expression on the right side of
the equal will always be evaluated first.
Relational Operators
• There are six relational operators as follows:
<, <=, >, >=, ==, !=
• Relational operators always result in a boolean value.
• The four relational operators can be used to compare any combination of
integers, floating-point numbers, or characters
>, >=, <, <=
• Its also legal to compare a character primitive with a number
• When comparing a character with a character java will use the unicode
value of the character a the numerical value.
• the two equality operators (==, !=)compare two similar things and return
a boolean. The four different types which can be tested are numbers,
characters, boolean primitives, object reference variables
• reference variables can be tested to see if they refer to the same object
using the == operator. If the bits in both reference variables are identical
then both refer to the same object.
Equality of Enums

• You can use either the == operator or the equals()


method to determine if the two variables are referring
to the same enum constant.
• class EnumEqual{
enum Color { RED, BLUE }
public static void main(String args[]){
if(c1==c2){System.out.println(“==“);
if(c1.equals(c2)){ System.out.println(“dot equals”)
} }
//==
//dot equals
instanceof comparison

• the instanceof operator is used for object reference variables only and you
can use to check whether an object is of a particular type.
• String s = new String(“foo”);
if(s instanceof String){
System.out.println(“s is a String”);}
• Even if object being tested is not an actual instantiation of the class type on
the right side of the operator, instanceof will still return true if the object
being compared is assignment compatible with type on the right.
• The use of instanceof operator protects the program from illegal downcast.
• An object is said to be of a particular interface type (meaning it will pass the
instanceof test) if any of the object’s superclasses implement the interface.
• It is legal to test whether the null reference is an instanceof class.
• You can’t use instanceof operator to test across two different class
hierarchies.
Arithmetic Operators
• The Remainder (%) operator – the remainder
operator divides the left operand by the right
operand and the remainder is the result.
• Expressions are evaluated from left to right by
default.
• If either operand is a String, the + operator
becomes a String concatenation operator. If
both operands are numbers the + operator is
the addition operator.
Increment and Decrement Operators
• Java has two operators that will increment or
decrement a variable exactly by one:
• ++ increment (prefix and postfix)
• -- decrement (prefix and postfix)
• postfix operator increments or decrements the
value of a variable after the variable is used in
the expression.
• prefix operator increments or decrements the
value of a variable before the variable is used
in the expression.
Conditional Operator
• x = (boolean expression) ? value to assign if
true : value to assign if false
Note: you can even nest conditional operators in
one statement e.g.
int sizeOfYard = 10;
int numOfPets = 3;
String status = (numOfPets < 4) ? “Pet Count
Ok” : (sizeOfYard > 8) ? “Pets limit on the
edge” : “too many pets”;
logic operators, bitwise operators
• There are six logical operators (&, |, ^, !, &&, ||).
• &, |, ^ can also be used as bitwise operators.
• Bitwise operators compare two variables bit by bit and return a variable whose bits have
been set based on whether the two variables being compared had respective bits that
were either both “on” (&), one or the other “on” (|),
or exactly one “on”.
• The short circuit && evaluates the left side of the operation first and if it resolves to false,
the && operator doesn’t bother looking at the right side of the expression
• The short circuit || - If the first operand in the Or operation is true the result will be true,
so the short circuit OR doesn’t waste time looking at the right side of the equasion.
• The non short circuit operators & , | - these operators evaluate both sides of the
expression always
• The logic operator ^ (exclusive – OR (XOR)): both operands must be different
• The logic operator ! (boolean invert): this operator returns the opposite of the boolean’s
current value.
Chapter 5 Flow Control, Exceptions, Assertions
The if statement
• The basic format of an if statement is as follows:
if(booleanExpression){
System.out.println(“Inside if statement”);
}
• The expression in an if statement must evaluate to a boolean true or false.
• Sun considers it a good practice to enclose blocks within curly braces, even
if there is only one statement in the block.
• You can have zero or one else for a given if and it must come after any else
ifs.
• You can have zero to many else ifs for a given if and they must come before
the optional else.
• If an else if succeeds, none of the remaining else ifs or elses will be tested.
Note: the else belongs to closest preceding if that doesn’t have an else
Note: do not assign a boolean variable when you mean to test it.
The switch statement
• The general form of the switch statement is:
switch (expression){
case constant1 : code block
case constant2 : code block
default : code block
}
• a switch expression must evaluate to a char, byte, short, int or enum
• the case constant must be of the same type as the switch expression can use.
• the case constant must be a compile time constant. You can only use a constant or a final
variable for the case constant that is assigned a literal (numeric) value e.g.
final int a=1; final int b;int x=0;
switch (x)
case a: //ok
case b: //compiler error
• The switch can only check for equality. Other relational operators such as greater than are
rendered unusable in a case.
• It is illegal to have more than one case label using the same value.
• It is legal to leverage the power of boxing in a switch expression.
• switch(new Integer(4)){
case 4: System.out.println(“boxing is OK”);
}
Break and fall-through in switch blocks
• The case statement cannot use a curly brace and the colon
cannot be omitted.
• The case constants are evaluated from the top down and the
first case constant that matches the switch’s expression is
the execution entry point.
• When the program encounters the keyword break execution
will immediately move out of the switch block to the next
statement after the switch.
• If break is omitted the program keeps executing the
remaining case blocks (all case blocks are executed)until
either break is found or the switch statement ends.
• The default case does not have to come at the end of the
switch. It works just like any other case for all through
while loops, do while loops
• while loop is good for scenarios where you don’t know how many
times a block or statement should repeat, but you want to continue
looping as long as some condition is true.
• while(expression){
//do stuff
}
• the expression must evaluate to a boolean result.
• any variables used in above expression must be declared before the
expression is evaluated.
• the key point to remember about while loop is that it might not
even run if the expression evaluates to false.
• do while is similar to while except that the expression is not
evaluated until after the do loop code is executed. Hence do loop
will always the code in the loop body at least once.
for loop
• The for loop is especially useful for flow control when you need to know how many
times you need to execute the statements in the loop’s block.
• the general form of the for loop is as below
for(/*initialization*/; /*condition*/;/*iteration */) {
//loop body
}
• if the for loop declares more than one variable for the same type then you will need to
separate then with commas.
• the scope of the variables declared in the for loop ends with the for loop.
• you can have only one test expression in the for loop.
• a variable only initialized in the for statement but declared earlier can be used beyond
the loop
• the below mention loop is an infinite for loop:
for( ; ; ){System.out.println(“inside an endless loop”);}
• in the absence of initialization and increment sections the loop acts like a while loop
int i = 0;
for(; i<10;){ i++;}
flow of control in the for loop
• first the initialization takes places
• then the conditional test executes
• then the body of the for loop executes
• after each execution of the body of the for loop, the iteration
expression executes
• then the conditional test is checked
Note: keep in mind that barring a forced exit, evaluating the
iteration expression and then evaluating the conditional
expression are the last two things that happen for a for loop
Note: all three sections of the for loop are independent of each
other. The three expression in the for statement don’t need
to operate on the same statement although they typically
do.
forced exit
• Examples of forced exits include a break, a return, a
System.exit(), or an exception
• a return causes execution to leave not just the current
iteration of the loop but the entire method, execution
jumps immediately back to the calling method.
• break – execution jumps immediately to the first
statement after the for loop.
• System.exit() – all program execution stops, the VM
shuts down
enhanced for loop
• it is a specialized for loop that simplifies looping through an
array or collection
• instead of having three components, the enhanced for has
two.
• general form of the enhanced for loop is:
for(declaration : expression)
declaration - is the newly declared block variable of a type
compatible with the elements of the array you are accessing
expression - this must evaluate to the array you want to loop
through.
• The enhanced for loop assumes that barring an early exit from
the loop, you will always loop through every element of the
array.
break and continue
• the break keyword is used to stop the entire loop
• the continue keyword is used to stop the current
iteration.
• typically if you are using a break or a continue you
will do an if test within the loop.
• remember that continue statements must be inside a
loop otherwise you will get a compiler error.
• break statements can be used inside either a loop or
switch statement. Note that this does not apply to
labeled break statements.
labeled statements
• a label statement must be placed just before the statement
being labeled and it consists of a valid identifier that ends
in a semi colon.
• the labeled varieties are needed only in situations where
you have a nested loop and you need to indicate which of
the nested loops you want to break from or from which of
the nested loops you want to continue the next iteration.
• a break statement will exit out of the labeled loop as
opposed to the innermost loop if the break keyword is
combined with a label.
• labeled continue and break statements must be inside the
loop that has the same name otherwise the code will not
compile.
handling exceptions
• exception means an exceptional conditional condition and is an occurrence that
alters the normal program flow.
• exception handler – when an exceptional event occurs in java an exception is said
to be thrown. The code that is responsible for doing something about the
exception is called an exception handler.
• exception handling - works by transferring the execution of a program to an
appropriate exception handler when an exception occurs.
• the catch blocks must all follow each other without any other statements or
blocks in between.
• also the order in which the catch blocks appear matters.
• if an exception occurs at a specific line in the try block the rest of the lines in the
try block will not be executed.
• one of the benefits of exception handling is that the code to handle any particular
exception that may occur in the governed region need to be written only once.
• it is illegal to use a try clause without either a catch clause or a finally clause. A try
clause by itself will cause an error.
• any catch clause must immediately follow the try block.
• it is legal to omit either the catch clause or the finally clause but not both
finally
• finally block encloses a code that is always executed at some point after the
try block, whether the exception was thrown or not. If there is a return
statement in the try block, the finally block executes right after the return
statement is encountered and before the return executes.
• finally is the place to close your files, release your network sockets and
perform any other cleanup your code requires.
• if the try block executes with no exception, finally block executed
immediately after the try block.
• If there was an exception thrown, the finally block executes immediately after
the proper catch block completes.
• finally always runs
• finally clauses are not required.
• Also because the compiler doesn’t even require catch clauses, sometimes
you will run across code that has try block immediately followed by finally
block.
• finally must immediately follow the last catch clause or it must immediately
follow the last try block if there is no catch.
propagating uncaught exceptions
• if a method does not provide a catch clause for a particular
exception the method is said to be ducking the exception.
• an exception that is never caught will cause your application to stop
running. A description of the exception will be displayed and the call
stack will be dumped.
• exceptions are always some subclass of java.lang.Exception.
• when an exception is thrown an object of a particular subtype is
instantiated and handed to the exception handler as an argument to
the catch clause.
• try{
//some code here
} catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace();
}
exception hierarchy
Object

Throwable

Error Exception

RuntimeException
Exception, Error

• all exception classes are subtypes of the class Exception. This


class derives from the class Throwable which derives from the
class object.
• classes that derive from Error represent unusual situations that
are not caused by program errors and indicate things that would
normally not happen during program execution.
• Generally your application won’t be able to recover from an
Error so you are normally not required to handle them.
• To get information about Exception use printStackTrace()
method provided by the throwable class. This method prints the
most recently entered method first.
• Exception, Error, RuntimeException and Throwable types can all
be thrown using the throw keyword and can all be caught.
However you will rarely catch anything other than Exception
subtypes.
Note: the throw keyword is used to throw an exception manually.
Handling an entire class hierarchy of exceptions
• You can catch more than one type of exception
in a single catch clause.
• However by specifying an exception class’s
superclass in your catch clause, you are
discarding valuable information about the
exception.
• you need to resist the temptation of handling
single catchall exception handler.
• exception handlers that trap many exceptions at
once will probably reduce the reliability of your
program because its likely that an exception will
be caught that the handler does not know how
to handle.
Exception classes
• IndexOutOfBoundsException has two subclasses namely
ArrayIndexOutOfBoundsException and
StringIndexOutOfBoundsException
• FileNotFoundException is a subclass of IOException
• EOFException is a subclass of IOException.
• NullPointerException is a subclass of RuntimeException
• NumberFormatException is a subclass of IllegalArgumentException
• handlers for the more specific exceptions must always be placed
above those for more general exceptions.
• If one exception class is not a subtype or super type of the other
then the order in which catch clauses are placed does not matter.
throws, throw,
• the exceptions that a method can throw must be declared. The throws keyword is
used as follows to list the exceptions that a method can throw.
• void myFunction() throws MyException1, MyException2 {
//code for the method here
}
• the throw keyword is used to throw an exception manually.
• Any method that might throw an exception (unless it’s a subclass of
RuntimeException) must declare the exception. That includes methods that aren’t
actually throwing it directly but are ducking (providing no catch clause)and letting
the exception pass down to the next method in the stack.
• All non-RuntimeExceptions are considered checked exceptions because the
compiler checks to see that they are handled or declared.
• Handle or declare requirement – each method must either handle all checked
exceptions by supplying a catch clause or list each unhandled checked exception
as a thrown exception.
• RuntimeException, Error and all of their subtypes are unchecked exceptions and
unchecked exceptions do not have to be handled or declared.
• All checked exceptions must be caught somewhere in your code.
creating your own exceptions
• You need to simply subclass Exception
• class MyException extends Exception{ }
• class TestEx {
void doStuff(){ throw new MyException(); } }
• Both Exception and Error share a common superclass Throwable thus both can be thrown using the
throw keyword.
• When an Error or an Error subtype is thrown it is unchecked. You are not required to catch Error
objects or Error subtypes.
• You can also throw an error yourself but you won’t.
• Since an Error is not a subtype of Exception it doesn’t need to be declared.
• You can also throw the same exception you just caught e.g.
` public void doStuff() throws IOException{
try{
// risky IO things
}catch(IOException e){
// do things then if you decide you can’t handle it
throw e;
}
• if you throw a checked exception from a catch clause, you must also declare that exception (see
above)
categories of exception
• Let us define two broad categories of exceptions and
errors
• JVM exceptions – those exceptions or errors that are
either exclusively or most logically thrown by
JVM.
• Programmatic exceptions – those exceptions that are
thrown explicitly by application and/or API
programmers.
• Note: those homemade exceptions fall into the
category of programmatically thrown exceptions
sources of exceptions
• By JVM
ArrayIndexOutOfBoundsException
ClassCastException
NullPointerException
ExceptionInInitializerError
StackOverflowError
NoClassDefFoundError
• Programmatically
IllegalArgumentException
IllegalStateException
NumberFormatException
AssertionError
Assertion Mechanism
• Assertions work quite simply. You always assert that something is true. If it is, no problem,
code keeps running. If your assertion turns out to be wrong then an AssertionError is thrown.
• Assertion come is two flavours:
1) Really Simple
private void doStuff(){
assert(y > x);
//more code assuming y>x
}
2) Simple
private void doStuff() {
assert (y>x) : “y is “ + y + “x is “ +x;
//more code assuming y>x
}
• Simple version adds a second expression separated from the first by a colon. This expression’s
String value is added to the stack trace.
• Both versions throw AssertionError if the assertion expression is false but the simple version
gives you a little more debugging help.
• The first expression must always result in a boolean value.
• The second expression used only with the simple version of assert statement can be anything
that results in a value. It can have a result of any value. You can pass it a primitive or an object
and it will convert it into a String representation.
Assertions
• assertions let you test your assumptions during development
without the expense of writing exception handlers for
exceptions that you assume will never happen once the
program is out of development and fully deployed.
• Assertions let you test your assumptions during
development but the assertion code basically evaporates
when the program is deployed leaving behind overhead or
debugging code to track down and remove.
• Assertions are typically enabled when an application is being
tested and debugged. The assertions are still in code
although ignored by JVM. So if you do have a deployed
application that starts misbehaving you can always choose to
enable assertions in the field for additional testing.
Compiling Assertion Aware Code

• Before java 1.4 assert could be used as an identifier


e.g.
int assert = getInitialValue();
• Beginning with version 1.4 assert is a
keyword/reserved word for assertion.
• You can explicitly enable assertion-awarenes at
compile time as follows:
java –source 1.4 com/TestClass.java
• If you are using an older version of java e.g. 1.3 and
you want to use assert as an identifier
java –source 1.3 OldCode.java
Enabling,Disabling Assertions
• You enable assertions in the class at runtime with:
java – ea com.geeksanonymous.TestClass
• You can disable assertions at runtime with:
java – da com.geeksanonymous.TestClass
• disable assertion in single class but keep them enabled for all others:
java – ea –da:com.geeksanonymous.Foo
• enable assertion in general but disable them in a package
(geeksanonymous)and its subpackages
java – ea –da:com.geeksanonymous…
• enable assertions in general but disable assertions in system classes
java – ea -dsa
using assertions appropriately
• Note: you are never supposed to handle an assertion failure. You shouldn’t catch AssertionError with a
catch clause and recover.
• do not use assertions to validate arguments to a public method e.g.
public void doStuff(int x){
assert(x >0);
//do things with x}
this is because public methods are part of your interface to the outside world and you are supposed to
guarantee that any constraints on the arguments will be enforced by the method itself. Since assertions
are not guaranteed to run, the enforcement won’t happen if assertions are disabled.
• do use assertions to validate arguments to private method e.g.
private void doMore(int x){
assert(x >0);
//do things with x}
• do not use assertions to validate command line arguments
• do use assertions even in public methods to check for cases that you know are never ever supposed to
happen.
• the below code causes an AssertionError to be thrown immediately if you do ever reach that code.
assert false;
• do not use assert expressions that can cause side effects.
The rule is that an assert expression should leave the program in the same state it was in before the
expression. If assertions are enabled, the only change to the way your program runs is that an
AssertionError can be thrown if one of your assertions turns out to be false.
Chapter 6 String, IO, Formatting and Parsing
String Class
• The key concept to understand is that once a String object is created, it can never be changed.
• In java each character in a String is a 16 bit unicode character.
• String object is immutable.
• The reference variable assigned to a String object can be changed.
• To make java more memory efficient JVM set aside a special area of memory called the “String
constant pool”. When the compiler encounters a String literal, it checks the pool to see if an
identical String already exists. If a match is found the reference to the new literal is directed to
the existing String and no new String literal object is created. The existing String simply has an
additional reference.
• The String class is marked final so that no one can override the String functionality.
• String s = “abc” // creates one String object and one reference variable
• String s = new String(“abc”); // creates two objects and one reference variable.
In this case because we used the new keyword, java will create a new String object i normal (non
pool) memory and s will refer to it. In addition the literal “abc” will be placed in the pool.
• length in Arrays and String
Arrays have an attribute called length.
String has a method called length()
Important methods in the String class

• charAt(int index) - returns the character located at the specified index. Also
remember that String indexes are zero based.
• concat(String s) – appends one String to the end of another. The String passed
as argument is appended at the end of the String used to invoke the method.
• equalsIgnoreCase(String s) – determines the equality of the two Strings,
ignoring case. This method returns a boolean value.
• length() – returns the number of characters in a String.
• replace(char old char new) – replaces the occurrence of a character with a new
character in the String.
• substring(int begin, int end) – returns a part of a String. The first argument is
zero based. The second argument is one based.
• toLowerCase() – returns a String with uppercase characters converted.
• toString() – returns the value of a String.
• toUpperCase() – returns a String with lowercase characters converted.
• trim() – removes whitespace from the beginning or end of a String.
StringBuffer vs StringBuilder
• StringBuilder class has exactly the same methods as the StringBuffer
class but StringBuilder is faster because its methods are not
synchronized.
• StringBuffer and StringBuilder classes should be used when you
have to make a lot of modifications to strings of characters. This is
because objects of the type StringBuffer and StringBuilder can be
modified over and over again.
• A common use for StringBuilders is file I/O when large ever changing
streams of input are being handled by the program. In these cases,
large blocks of characters are handled as units and StringBuffer
objects are the ideal way to handle a block of data, pass it on, and
then reuse the same memory to handle the next block of data.
• Unlike Strings, StringBuffer and StringBuilder objects can be
changed.
Important methods in StringBuffer and StringBuilder
• append(String s) – this method returns a StringBuffer object with the
arguments value appended to the value of the object that invoked the
method .
• delete(int start, int end) – this method updates the value of the
StringBuilder object and removes the substring from the original
object and returns the StringBuilder object.
• insert(int offset String s) – the String passed in to the second argument
is inserted into the original StringBuilder starting at the offset location
represented by the first argument (the offset is zero-based).
• reverse() – this method updates the StringBuffer object and the
characters in the StringBuffer are reversed the first character
becoming the last and so on.
• toString() – this method returns the value of the StringBuffer object
that invoked the method call as a String.
• Note: all the above methods return StringBuffer objects
chained methods
• A statement with chained methods has this general form:
result = method1().method2().method3();
• Steps for handling the chained methods:
i) determine what the leftmost method call will return
(lets call it x).
ii) Use x as a object invoking the second (from the left)
method. If there are only two chained methods, the result
of the second method call is the expression’s result.
iii) If there is a third method, the result of the second call
is used to invoke the third method. whose result is the
expression of the result.
I O classes
• File – the class file is an abstract representation of file and directory path names.
The File class isn’t used to actually read or write data. Its used to work at a higher
level, making new empty files, searching for files, deleting files, making
directories and working with paths.
• FileReader – this class is used to read character files. Its read() method allows you
to read single characters, the whole stream of characters or fixed number of
characters.
• BufferedReader – this class is used to make lower level reader classes like
FileReader more efficient and easier to use. BufferedReaders read relatively large
chunks of data from file at once and keep this data in a buffer. When you ask for
next character or line of data it is retrieved from the buffer which minimizes the
number of times that time-intensive file read operations are performed. It
provides more convenient methods like readLine() that allow you to get next line
of characters from a file.
• FileWriter – this class is used to write to character file. Its write() method allows
you to write characters or String to a file. FileWriters are usually wrapped by
higher level writer objects such as BufferedWriters or PrintWriters.
I O Classes
• Buffered Writer – this class is used to make lower level classes like
FileWriters more efficient and easier to use. FileWriter reference is passed to
BufferedWriter. Compared to FileWriters, BufferedWriters write relatively
large chunks of data to a file at once minimizing the number of times slow,
file writing operations are performed. BufferedWriter class also provides a
newLine() method to create platform specific line separators automatically.
• PrintWriter – you can used PrintWriter in places where you previously
needed a Writer to be wrapped in File
Writer and BufferedWriter. It has new methods like format(), printf(), and
append() which make PrintWriters very flexible and powerful.
• Console – this java 6 class provides methods to read input from the console
and write formatted output to the console.
Important distinction between reading and writing characters and Streams
• Stream classes are used to read and write bytes.
• Readers and writers are used to read and write characters
Creating files using the class File
• import java.io.*;
class Writer1{
public static void main(String [] args){
try{
boolean newFile = false;
File file = new File(“fileWrite1.txt”);
System.out.println(file.exists());
newFile = file.createNewFile();
System.out.println(newFile );
System.out.println(file.exists());
}catch(IOException e){
e.printStackTrace()
}
}
}
Note:
1.boolean exists() – this method returns true if it can find the actual file.
2. boolean createNewFile() - this method creates a new file if it doesn’t already exist.
Writing and Reading from a file using FileReader and FileWriter
• import java.io.*;
class Writer2 {
public static void main(String args[]){
char[] in = new char[50];
int size=0;
try{
File file = new File(“fileWrite2.txt”);
FileWriter fw = new FileWriter(file); // creates a new file
fw.write(“howdy\nfolks\n”);
fw.flush();
fw.close();
FileReader fr = new FileReader(file);
size = fr.read(in);
System.out.println(size + “ “);
for(char c : in)
System.out.println(c);
fr.close();
}catch(IOException e){
e.printStackTrace()
}
}
flush(),close(),delete(),renameTo()
• the flush() method guarantees that the last of the data you
thought you had already written gets out to the file.
• while reading a file no flush() is required.
• When you are done using a file either reading it or writing it
you should invoke the close() method which will free up the
resources.
• delete(): you can’t delete a directory if its not empty.
• renameTo(): you must give the existing file object a valid new
file object with the new name that you want.
• renameTo(): its okay to rename a directory even if isin’t
empty.
Writing and Reading from a file using BufferedReader and PrintWriter
• import java.io.*;
class Writer2 {
public static void main(String args[]){
char[] int = new char[50];
int size=0;
try{
File file = new File(“fileWrite2.txt”);
PrintWriter pw = new PrintWriter(file); // created new file
pw.println(“howdy”);
pw.println(“folks”);
pw.flush();
pw.close();
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
while(br.readLine() != null){
String data = br.readLine();
System.out.println(data);
}
fr.close
}catch(IOException e){
e.printStackTrace()
}
}
working with files and directories
• creating a directory:
File mydir = new File(“mydir”);
mydir.mkdir();
• creating file inside the above directory:
File myfile = new File(mydir, “myFile.txt”);
myfile.createNewFile();
• deleting a file:
File delDir = new File(“deldir”);
delDir.mkdir();
File delFile1 = new File(delDir, “delFile1.txt”);
delFile1.createNewFile();
File delFile2 = new File(delDir, “delFile2.txt”);
delFile2.createNewFile();
delFile1.delete();
• Rename a file:
File newName = new File(delDir, “newName.txt”);
delFile2.renameTo(nameName);
• Rename a directory
File newdir = new File(“newDir”);
delDir.renameTo(newDir);
• Get a list of all files and directories in a directory:
String[] files = new String[100];
File searchDirectory = File(“searchDirectory “);
files = searchDirectory.list();
for(String fn : files)
System.out.println(“found “ +fn);
Serialization
• Serialization is the process of saving an object
and all its instance variables unless the
variable is explicitly marked transient.
• Serialization happens with two methods:
ObjectOutputStream.writeObject()
//serialize and write
ObjectInputStream.readObject()
//read and deserialize
program that creates an object serializes it and then desterilizes it.
• import java.io.*;
class Cat implements Serializable{ }
public class SerializeCat{
public static void main(String args[]){
Cat c = new Cat();
try{
FileOutputStream fs = new FileOutputStream(“testSer.ser”);
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(c);
os.close();
}catch(Exception e){
e.printStrackTrace();
}
try{
FileInputStream fis = new FileInputStream(“testSer.ser”);
ObjectInputStream ois = new ObjectInputStream(fis);
c = (Cat) ois.readObject();
ois.close();
}catch(Exception e){
e.printStackTrace()
}
}
}
marker interface
• Marker interface – Serializable is a marker interface, it has no
methods to implement.
• writeObject() – this method performs two tasks. It serializes the
object and then writes the serialized object to a file.
• readObject() – this method de-serializes the Cat object. This method
returns an Object so we have to cast the de-serialized object back to
a Cat.
• when you serialize an object java serialization takes care of serializing
an objects entire object graph. That means a deep copy of everything
the saved object needs, needs to be restored.
• You have to make a conscious choice of objects that are serializable
by implementing the Serializable interface
• If you mark an instance variable of a class as transient then
serialization will simply skip the instance variable during
serialization .
saving the state of an instance variable marked transient
• The common reason for implementing writeObject() and readObject() is when
you have to save some part of an objects state manually. You do only a part of the
serialization/deserialization yourself and you must invoke the defaultReadObject()
and defaultWriteObject() methods to do the rest
• If you have a pair of methods mentioned below matching this exact signature
these methods will be called during serialization/deserialization. These methods
let you step into the middle of serialization and add the state of transient variable
to the object’s serialized representation.
• During the deserialization, the transient object is restored using the extra int
saved to the object stream.
• the two methods are mentioned below
• private void writeObject(ObjectOutputStream os){
//code for saving the collar variables
}
• private void readObject(ObjectInputStream is){
//code to read the collar state, create a new collar and assign it to the dog.
}
saving the state of an instance variable marked transient
• class Dog implements Serializable{
transient private Collar theCollar;
// generate the getter and setter
private int dogSize;
public Dog(Collar collar, int size){
theCollar = collar;
dogSize = size;
}
public Collar getCollar(){ return theCollar;}
private void writeObject(ObjectOutputStream os){
try{
os.defaultWriteObject(); //we are telling jvm y
os.WriteInt(theCollar.getCollarSize());
}catch(Exception e){
e.printStackTrace();
}
}
• private void readObject(ObjectInputStream is){
try{
is.defaultReadObject();
theCollar = new Collar(is.readInt());
}catch(Exception e){
e.printStackTrace();
}
saving the state of an instance variable marked transient
• When you invoke defaultWriteObject() from within writeObject()
you are telling JVM to do the normal serialization process for this
object. When implementing writeObject() you will typically request
the normal serialization process, and do some custom writing and
reading too.
• In this case we have decided to write the extra int to the stream
that’s creating the serialized Dog. You can write extra stuff before
and after you invoke the defaultWriteObject(). But when you read it
back in you have to read the extra stuff in the same order you wrote
it.
• when its time to deserialize defaultReadObject() handles the normal
deserialization you’d get if you didn’t implement the readObject()
method.
• Finally we build the new Collar object for the Dog using the collar
size that we manually serialized.
How inheritance affects serialization, serialization rules for
collection, interfaces, arrays, static variables
• There are some things in java that cannot be serialized because they are runtime specific. e.g.
streams, threads, runtime, some GUI classes.
• If you serialize a collection or an array every element must be serializable. A single
nonserializable element will cause the serialization to fail.
• While collection interfaces are non serializable, the concrete collection classes in java API are
• If a superclass is Serializable then according to normal java interface rules, all subclasses of
that class automatically implement Serialization implicitly. Hence the subclass can be saved
without having to explicitly mark the subclass as serializable.
• If a class does not explicitly extend any other class and does not implement Serializable then
you know for certain that the class is not Serializable because the class Object does not
implement Serializable.
• Objects marked transient will always be reset to null regardless of whether they were
initiated at the time of declaration in the class.
• If a super class is not marked serializable but a subclass is, the instance variables from the
subclass will be serialized and deserialized correctly but the inherited variables from the non-
serializable animal superclass will come back with their default / initially assigned values.
• Serialization applies only to objects. Static variables are never saved as part of the objects
state because they do not belong to the object. They have nothing to do with individual
instances. Static variables are purely class variables.
Dates, Numbers, and Currency
• get the current date and time
Date d = new Date();
String s = d.toString();
• get an object that lets you perform date and time
calculations in your locale:
Calendar c = Calendar.getInstance();
• Locale loc = new Locale(…);
Date d = c.getTime();
DateFormat df = DateFormat.getInstance(style,loc);
String s = df.format(d);
• NumberFormat nf = NumberFormat.getInstance(loc);
String s = nf.format(someNumber);
Date class

• the java.util.Date class provides quick and


dirty way to get the current date and time.
Date now = new Date();
• this class is used as a temporary bridge to
format Calendar object using the DateFormat
class.
• the setTime() and getTime() methods of the
Date class accepts time in milli seconds.
the Calendar class

• the calendar class is an abstract class.


• the java.util.Calendar class is designed to make the date manipulation easy.
Calendar cal = Calendar.getInstance();
c.set(2010, 11, 14); //Note: the set() method of the calendar class is used to set a date in the past
Date d2 = c.getTme();
Locale locIt = new Locale(“it”, IT);
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locIT);
String s = df.format(d2);
System.out.println(s);
• c.setTime(d1);
• c.getFirstDayOfWeek();
Note: this will give you the day of the week corresponding to the date provided.
• c.get(Calendar.DAY_OF_WEEK);
• c.add(Calendar.MONTH,1);
Note: the add method lets you add or subtract units of time appropriate for whichever Calendar field you
specify.
c.add(Calendar.HOUR, -4);
c.add(Calendar.YEAR, 2);
c.add(Calendar.DAY_OF_WEEK, -2);
c.roll(Calendar.MONTH, 9);
Note: the roll method acts like add() method except that when a part of the date gets incremented or
decremented larger parts of the date will not get incremented or decremented.
DateFormat class

• This is an abstract class


• This class is used for formatting the date in different ways;
• Date d1 = new Date();
DateFormat df1 = DateFormat.getInstance();
DateFormat df2 = DateFormat.getDateInstance();
DateFormat df2 = DateFormat.getDateInstance(DateFormat.SHORT);
DateFormat df3 =DateFormat.getDateInstance(DateFormat.MEDIUM);
DateFormat df4 = DateFormat.getDateInstance(DateFormat.LONG);
DateFormat df5 = DateFormat.getDateInstance(DateFormat.FULL);
String s1 = df1.format(d1);
System.out.println(s1);
Date d2 = df1.parse(s1);
Note:
1. the format() method is used to create Strings representing the properly formatted versions of the
date.
2. the parse method takes a String formatted in the style of DateFormat instance being used and
converts the String into a Date object. If the String is badly formatted it throws a parse exception.
3. If we wanted to retain the time along with the date we could have used the getDateTimeInstance()
method.
4. You can also use locale in the getDateInstance() method as below:
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, loc)
Locale class
• A locale is a specific geographical political or cultural region.
• The two locale constructors are:
1. Locale(String language);
2. Locale(String language, String country).
Locale locIT = new Locale(“it”, “IT”); //Italy
Locale locPT = new Locale(“pt”); //Portugal
Locale locBR = new Locale(“pt”, “BR”); //Brazil
Locale locIN= new Locale(“hi”, “IN”); //India
Locale locJA = new Locale(“ja”); //Japan
• locIT.getDisplayCountry() – represent the locale’s country
• locIT.getDisplayLanguage() – represent the country’s language in terms of
both the default locale and any other locale
• both DateFormat and NumberFormat objects can have their locales set
only at the time of instantiation. No such method exists to change the
locale of existing instance.
NumberFormat class

• NumberFormat class is abstract


• you use getInstance() or getCurrencyInstance() to create a NumberFormat object
• Locale locFr = new Locale(“fr”);
NumberFormat nf1 = NumberFormat.getInstance();
NumberFormat nf2 = NumberFormat.getInstance(locFR);
NumberFormat nf3=NumberFormat.getCurrencyInstance();
NumberFormat nf4 = NumberFormat.getInstance(locFR);
float f1 = 123.4567f;
String s = nf1.format(f1);
Note: this method rounds f1’s value
nf1.getMaximumFractionDigits();
nf1.setMaximumFractionDigits(5);
nf1.parse(“1234.567”);
Note: this method runs inside a try catch and prints the value inside the String
nf1.setParseIntegerOnly(true);
Note: this method causes subsequent calls to parse to return only the integer part of the
Strings formatted as floating point numbers
Searching and Regular Expressions - regex

• Regular expressions are a kind of language within a


language designed to help programmers with
searching tasks.
• Regex engines search through textual data using
instructions that are coded into expressions.
• A regex expression is a very short program or
script.
• when you invoke a regex engine you will pass the
chunk of textual data you want it to process and
you will pass it the expression you want it to use to
search through the data.
simple searches
• source data String – abaaaba
• index - 0123456
• expression – ab
• Sending the source data and expression to a regex engine
import java.util.regex;
class RegexSmall{
public static void main(String[] args){
Pattern p = Pattern.compile(“ab”);
Matcher m= p.matcher(“abaaaba”);
while(m.find()){
System.out.println(m.start() + “ “);
}
}
}
//this produces 0 4
simple searches

• source data String – abababa


• index - 0123456
• expression – aba
• Answer 0 and 4
Note: the character at position 2 was consumed
in the first match so it could not be used again
Rule: a regex search runs from left to right and
once a source’s character has been used in a
match it cannot be reused.
search using meta characters
• the following regex expression are used to:
• look for numeric digits: \d
• look for a white space character: \s
• look for a word character (letters digits or underscore): \w
• look for sets of characters (searches a’s or b’s or c’s: [abc]
• look for ranges of characters (searches only for a,b,c,d,e or f): [a-f]
• look for first six letters of alphabet both case: [a-fA-F]
• source data String – a 1 56 _Z”
index - 012345678
patters – \w
Answer 0,2,4,5,7 and 8
• source data String – cafeBABE
index – 01234567
patters – [a-cA-c]
Answer 0,1,4,5,6
Note: the following attributes can be applied to sets and ranges
• use “^” to negate the characters specified
• use nested brackets to create a union of sets
• use “&&” to specify the intersection of sets.
quantifiers: ‘+’

• source – “12 0x 0x12 0xf oxg”


index - 012345678901234567
expression – 0[xX][0-9a-fA-F]
Answer 6,11
• the ‘+’ quantifier represents for one or more occurrence of
specified characters.
source: “1 a12 234b”
index: 0123456789
patterns: \d+ //d+ represents one or more numeric digits
Answer
0 1
3 12
6 234
search using quantifiers

• specifying the quantifier for only part of the


expression
• source – “12 0x 0x12 0xf oxg”
index - 012345678901234567
expression – 0[xX]([0-9a-fA-F])+
Answer : 6, 11, 15
Note: the parenthesis limit the + quantifier to only
the hex digits and + specifies one or more.
• Note: its always useful to think of quantifiers as
always quantifying the part of expression that
precedes them.
other quantifiers: *,?

• the ‘*’ quantifier represents zero or more occurrence of


specified characters.
• the ‘?’ quantifier represents zero or one occurrence of
specified characters.
• task – create a list of files whose names start with proj1
from a comma delimited list of all file names in a directory
soln: proj([^,])* // ([^,]) says give me zero or more
characters that arent a comma
• task – search a text file for anything that might be a local 7
digit phone number.
• soln: \d\d\d([-\s])?\d\d\d\d // ([-\s]) says zero or one
occurrence of either a – or a space
greedy quantifiers
• When you use the *,+,? quantifiers you can fine tune them to produce
behavior that is known as greedy, reluctant, possessive.
• greedy - means looking at the entire data and then it works backwards (from
the right) until it find the rightmost match. It includes everything from earlier
in the source data upto and including the data that is part of the match.
• reluctant means – starting from the left and getting the first match
• ? is greedy, ?? is reluctant, for zero or once
• * is greedy, *? is reluctant, for zero or more
• + is greedy, +? is reluctant, for one or more
• source: “yyxxxyxx”
pattern: .*xx //find greedy sets of characters that end with xx
Ans – 0 yyxxxyxx
• source: “yyxxxyxx”
pattern: .*?xx //find reluctant sets of characters that end with xx
Ans: 0 yyxx, 4 xyxx
other meta characters

• the ‘.’ (dot) meta character in regex means any


character can server here including whitespace.
• source: ”ac abc a c”
• pattern: a.c
• answer: 3 abc,7 a c
• Note: meta characters and Strings do not mix well.
• So if you want to search for digits in a String use
the following metacharacter: String p = \\d
• If you want to use dot in your expression as a
metacharacter use : String p = “\\.”
java escape sequences

• \n = linefeed
\b= backspace
\t = tab
locating data via pattern matching
• the Pattern class is used to hold the representation of a regex expression so that it can be used and reused
by instances of the Matcher class.
• The Matcher class is used to invoke the regex engine with the intention of performing the match
operations:
import java.util.regex.*;
class Regex {
public static void main(String[] args){
Pattern p = Pattern.compile(args[0]);
Matcher m = p.matcher(args[1]); //matcher method takes source data
System.out.println(“Pattern is “ + m.pattern());
while(m.find()){
// the find() method returns true if it gets a match and remembers the start position of the match
System.out.println(m.start() + “ “ + m.group()); // start() method gives the starting position of the match
//and the group() method gets the String that represents the actual bit of source data that was matched.
}
}
}
args[0] – represents the regex expression you want to use.
args[1] – represents the source data you want to search.
java Regex “\d\w” “ab4 56_7ab”
Output
Patten is \d\w
4 56, 7 7a
replace operations using the methods of
Matcher class
• A common reason to use regex is to perform
search and replace operations. The Matcher
class provides several methods that perform
search and replace operations:
• appendReplacement();
• appendTail()
• replaceAll()
Chapter 7 Generics & collections
String toString()
• String toString() – you can call toString() on your object when you want it to read useful details about your
object. However this is only possible when you override the toString() method and return the values of
instance variables of your object as a String. Otherwise it prints unmeaningful details.
• package com;
public class BobTest {
public static void main(String[] args){
Bob f = new Bob("GoBobGo", 19);
System.out.println(f.toString());
}
}
• class Bob{
int shoeSize;
String nickName;
Bob(String nickName,int shoeSize){
this.shoeSize=shoeSize;
this.nickName=nickName;
}
public String toString(){
return("I am Bob but you can call me "+nickName+". My shoesize is"+shoeSize);
}
}
methods of the Object class

• boolean equals(Object obj) – decides whether the two objects are


meaningfully equivalent.
• void finalize() – called by garbage collector when the garbage collector
sees that the object cannot be referenced.
• int hashCode() – returns a hashcode int value of an object, so that the
object can be used in Collection classes that use hashing, including
Hashtable, HashMap, and HashSet.
• final void notify() – wakes up a thread that is waiting for this objects lock.
• final void notifyAll() – wakes up all threads that are waiting for this
object’s lock.
• final void wait() – causes the current thread to wait until another thread
calls notify() or notifyAll() on this object.
• String toString() – returns a “text representation” of the object.
Note: remember that equals(), hashCode(), and toString() methods are all
public
public boolean equals(Object 0)
• When you need to know if the two references are identical i.e. they are referring to the same Object
use ==
• When you need to know if the objects themselves (not the references) are equal use the equals
method()
• If you don’t override equals() method in a class, you won’t be able to use those objects as a key in a
Hashtable and probably you won’t get accurate Sets such that there are no conceptual duplicates.
• You must override equals() so that two different instances can be considered the same. You specify an
instance variable as a basis of comparison while overriding. That way you can use one instance when
you add it to a Collection and recreate an identical instance when you want to do a search based on
that object as key.
• String and wrapper classes work well as keys in hash tables – they override equals() method. So rather
than using actual car instance as a key into the car/owner pair, you could simply use a String that
represents a unique identifier for the car.
• Note the signature of equals method for a valid override – the agrument must be of the type Object
and the return type must be boolean. ). Remember equals, hashcode, toString methods are all
public
• Object being tested must pass the instanceof test so that you can cast the Object to the correct type.
• equals() and hashCode() are bound together by a joint contract that specifies if two objects are
considered equal using the equals method, then they must have identical hashcode values. rule of
thumb, if you override equals(), override hashCode() as well.
• HashMap is a type of Hashtable
overriding equals method
• class Moof {
private int moofValue;
Moof(int val) {
moofValue = val;
}
public int getMoofValue(){
return moofValue;
}
public boolean equals(Object o) {
if((o instanceof Moof) && (((Moof)o ).getMoofValue()) == this.moofValue)){
return true;
} else {
return false;
}
}}}
public class EqualsTest {
public static void main(String[] args){
Moof one = new Moof(8);
Moof two = new Moof(8);
if(one.equals(two){
System.out.println(“one and two are equal”);
}
}}
equals() contract
• the equals contract says
its reflexive, its
its symmetric,
its transitive,
its consistent,
For any non null reference value x, x.equals(null) should
return false
• equals() and hashCode() are bound together by a joint
contract that specifies if two objects are considered equal
using equals() method then they must have identical
hashcodes values.
• Your rule of thumb should be, if you override equals, override
hashCode() as well.
overriding hashCode()
• Note: hashCode() is not necessarily unique.
• Collections such as HashMap and HashSet use the hashcode value of an
object to determine how the object should be stored in the collection
and the hashcode is again use to locate the object in the collection.
• Hashing retrieval is a two step process:
1. Find the right bucket using hashCode()
2. Search the bucket for the right element using equals.
• When you put object in a collection that uses hashcodes, the collection
uses hashcode of the object to decide in which bucket/slot the object
should land.
• a hashCode() that returns the same value for all instances whether they
are equal or not is still a legal, even appropriate hashCode() method.
• two objects with identical hashcodes do not have to be necessarily
equal.
hashCode() contract
• whenever invoked on the same object more than once during
the execution of a java application, the hashCode() method must
consistently return the same integer provided no information
used in equals() comparison of the object is modified.
• if two objects are equal according to the equals(Object)
method, then calling the hashCode() method on each of the two
objects must produce the same integer results.
• It is not required that if the two objects are unequal according to
the equals() method then calling the hashCode() method on
each of the two objects must produce distinct integer results.
• transient variables can really mess with your equal() and
hashCode() implementations. Keep the variables non-transient
and if they must be marked transient, don’t use them to
determine hashcode or equality.
Key interfaces of Collections Framework

• Collection
• List
• Queue
• Set
• Map
• NavigableSet
• SortedSet
• SortedMap
• NavigableMap
Key classes of Collections framework
• ArrayList
• LinkedList
• Vector
• PriorityQueue
• HashSet
• LinkedHashSet
• TreeSet
• HashMap
• HashTable
• LinkedHashMap
• TreeMap
• Collections
• Arrays
Collection Interface

• None of the Map related classes extend from the


Collection interface
• collection (lowercase c) which represents any of the
data structures in which objects are stored and
iterated over.
• Collection (capital C) which is actually the
java.util.Collection interface from which Set, List and
Queue extend.
• Collections (capital C and ends with s) is the
java.util.Collections class which extends from the
Object class and holds a pile of static utility methods
for use with collections.
The collection interface
• private Collection<Vehicle> vehicle = new ArrayList<Vehicle>();
• interface Collection<E>
• you can remove an object using remove()
• to remove a group of objects call removeAll();
• to remove all elements except those of a specified group use retainAll()
• to empty a collection call clear(); it removes all elements from the invoking
collection.
• boolean add(E obj) adds obj to invoking collection. Returns true if obj was added
to the collection. Returns false if obj is already a member of the collection and
the collection does not allow duplicates.
• boolean contains(Object obj) – returns true if obj is an element of the invoking
collection. Otherwise returns false.
• boolean containsAll(Collection<?> c) – returns true if the invoking collection
contains all elments of c. Otherwise returns false.
• Q what is the difference between clear() and removeAll()
Collections class come in four basic flavors

• Lists – List of things (classes that implement


List)
• Sets – Unique things (classes that implement
Set)
• Maps – Things with unique ID (classes that
implement Map)
• Queues – Things arranged in order in which
they are to be processed.
Sorted, Ordered

• An implementation can never be sorted but unordered because sorting is a specific type of ordering.
• Iterating through a collection usually means walking through the elements one after another starting from the first
element.
• Ordered – when a collection is ordered it means you can iterate through the collection in a specific order. Some
elements keep an order referred to as natural order of elements and those collections are not just ordered but also
sorted.
• ArrayList – ordered by index position
• LinkedList - LinkedList is ordered by index position like ArrayList
• HashSet – unordered
• LinkedHashSet – ordered by insertion
• TreeSet - sorted
• Hashtable – unordered
• HashMap – unsorted, unordered.
• LinkedHashMap – maintains insertion order
• TreeMap – Sorted in ascending order
• Sorted – A sorted collection means that order in the collection is determined according to some rule or rules known as
the sort order. Sorting is done based on the properties of the object themselves. You put objects into the collection and
the collection will figure out what order to put them in based on sort order.
Note:
1. collection that keeps an order is not really considered sorted unless it sorts using some kind of sort order.
2. A sort order has nothing to do with when an object was added to the collection or when was the last time it was
accessed or what position it was added at.
3. You can define sort order for Objects using Comparable interface or comparator.
4. Sort order is not the same as ordering by insertion, access or index.
List interface

• List – a list cares about index.


• Elements can be inserted or accessed by their position in the list using a zero based index
• A List may contain duplicate elements.
• All three list implementations are ordered by index position.
• List methods include get(int index), indexOf(Object o), add(int index, Object obj).
• If you add an object without specifying its position, the object is added to the end.
• ArrayList – its an ordered collection by index but not sorted.
• It implements RandomAccess interface which is a marker interface
• It supports fast random access.
• You choose this over LinkedList when you need fast random access but aren’t as likely to
be doing a lot of insertion and deletion.
• duplicates might occur
• Vector – a vector is basically the same as ArrayList but Vector methods are synchronized
for thread safety.
• vector is the only class apart from ArrayList to implement RandomAccess.
• synchronized method add a performance hit.
Note: normally you should use ArrayList and if you need thread safety there are utility
methods in the Collections class that can help
List Interface
• LinkedList – LinkedList is ordered by index position like ArrayList
• Elements are doubly linked to one another.
• This linkage gives you new methods (beyond what you get from
List interface) for adding and removing elements from the
beginning or end and include add(“String”); addFirst(“A”);
addLast(“A”); remove(“A”); removeFirst(); removeLast();
add(1,”A”); get(2);
• LinkedList is a good choice when you need fast insertion and
deletion.
• LinkedList has been enhanced to implement the java.util.Queue
interface. It support common queue methods like peek(), poll();
offer();
• duplicates might occur.
Set interface
• Set - a Set cares about uniqueness and doesn’t allow duplicates. The equals
method determines whether two objects are identical (in which case only one
can be in the Set).
• HashSet – HashSet is unsorted and unordered set.
• HashSet creates a collection that uses a hash table for storage. A hash table
stores information using a mechanism called hashing. In hashing the
informational content of a key is used to determine a unique value called hash
code. The hash code is then used as the index at which the data associated
with the key is stored. The transformation of the key into its hash code is
performed automatically.
• Also your code cannot directly index the hash table.
• HashSet does not guarantee the order of its elements because the process of
hashing does not usually lend itself to the creation of sorted sets.
• It uses hashCode() of the object being inserted to determine in which bucket
the object should land.
• Use this class when you want no duplicates and you do not care about the
order you iterate through it.
Set interface
• LinkedHashSet – its an ordered version of HashSet. It lets you iterate through the
element in the order in which they were inserted. It allows insertion order
iteration over the set.
• It maintains a doubly linked List across all elements
• You use this class when you care about iteration order
Note: when using HashSet or LinkedHashSet,
the objects you add to them must override hashCode(). If you don’t override
hashCode() the default Object.hashCode() method will allow multiple objects that
you consider meaningfully equal to be added to your “no duplicates allowed” set.
• TreeSet – it is a sorted collection. It guarantees that the elements will be in
ascending order according to natural order.
• It creates a collection that uses a tree for storage. Because TreeSet stores its
elements in a tree they are automatically arranged in sorted order.
• Objects are stored in sorted ascending order.
• Optionally you can construct a TreeSet with a constructor that gives your
collection your own rules for what the order should be by using a comparable or a
comparator.
• TreeSet implements NavigableSet
Iterator

• To use an iterator to cycle through the contents of a


collection, follow these steps
1. Obtain an iterator to the start of the collection by calling
the collection’s iterator() method.
2. Setup a loop that makes a call to hasNext(). Have the loop
iterate as long as the hasNext() returns true
3. Within the loop, obtain each element by calling next().
• Maps don’t implement the Iterable interface. This means
that you cannot cycle through a map using a for-each style
for loop. Furthermore you cant obtain an iterator to a map.
• However you can obtain a collection-view of a map which
does allow the use of either the for loop or an iterator.
Map Interface

• Map- cares about a unique identifier.


• You map a unique key to a specific value where both the key and the value
are objects. A key is an object that you use to retrieve a value at a later date.
• Like Sets, Maps rely upon the equals() method to determine whether the two
keys are same or different.
• Map.Entry – describes an element (a key/value pair) in a map. This is an inner
class of Map.
• Maps revolve around two basic operations: get() and put(). To put a value
into a map use put(), specifying the key and the value. To obtain a value call
get() passing the key as an argument. The value is returned.
• Maps are not themselves collection because because they do not implement
the collection interface. However you can obtain collection-view of map. To
do this you can use the entrySet() method. It returns a Set that contains the
elements in the map. To obtain the collection-view of the keys use keySet().
To get a collection-view of the values use values(). Collection-views are the
means by which maps are integrated into the larger Collections Framework.
HashMap
• HashMap – gives you unsorted, unordered Map.
• It does not guarantee the order for its elements. The order in
which the elements are added to HashMap is not necessarily
the order in which they are read by the iterator.
• When you need a Map and you don’t care about the order
you iterate through it then use HashMap.
• HashMap uses hash table to store the map
• Where the keys land in the Map is based on key’s hashCode().
• HashMap allows one null key and multiple null values in the
collection.
• methods of the HashMap include put(key, value), get(key),
entrySet(), keySet(), values(),
Iterating through HashMap
• import java.util.*;
class HashMapDemo{
public static void main(String args[]){
//create a hash map
HashMap<String, Double> hm = new HashMap<String, Double>();
hm.put(“John Doe”, new Double(3434.34));
hm.put(“Tom Smith”, new Double(123.22));
hm.put(“Jane Baker”, new Double(1378.00));
hm.put(“Tod Hall”, new Double(99.22));
hm.put(“Ralph Smith”, new Double(-19.08));
}
Set<Map.Entry<String, Double>> set = hm.entrySet();
for(Map.Entry<String, Double> me : set) {
System.out.print(me.getKey() + “:”);
System.out.println(me.getValue());
}
Hashtable
• Hashtable – is a synchronized counterpart to HashMap.
• When we say that Vector and Hashtable are synchronized we mean that the key
methods of the class are synchronized.
• While HashMap let you have null values as well as one null key, a Hashtable
doesn’t let you have anything that’s null.
• HashMap is a type of Hashtable. Hashtable is similar to HashMap but is synchronized.
• Like HashMap, Hashtable stores key / value pairs in a hash table.
• A hash table can only store objects that override the hashCode() and equals()
method that are defined by Object.
• When using a Hashtable, you specify an object that is used as a key and a value that
you want linked to that key. The key is then hashed and the resulting hash code is
used as the index at which the value is stored within the table.
• like map classes HashTable does not directly support iterators. However you can
obtain set-views of hash table, which permit the use of iterators. To do so you simply
use one of the collection-view methods defined by Map, such as entrySet() or
keySet((). For example you can obtain a set-view of the keys and cycle through them
using either an iterator or an ehanced for loop.
• import java.util.*; Use iterators with Hashtable
• class HTDemo2{
public static void main(String args[]){
Hashtable<String, Double> balance = new Hashtable<String, Double>();
String str;
double bal;
balance.put(“John Doe”, 3434.34);
balance.put(“Tom Smith”, 123.22);
balance.put(“Jane Baker”, 1378.00);
balance.put(“Tod Hall”, 99.22);
balance.put(“Ralph Smith”, -19.08);
//Show all balances in hashtable
//First get a set view of the keys
Set<String> set = balance.keySet();
//Get an iterator
Iterator<String> itr = set.iterator();
while(itr.hasNext()){
str = itr.next();
System.out.println(str + “: ” + balance.get(str))
}
//Deposit 1000 into John Doe’s account
bal = balance.get(“John Doe”);
baalnce.put(“John Doe”, bal+1000);
System.out.println(“John Doe’s new balance: ” + balance.get(“John Doe”));
}
LinkedHashMap

• LinkedHashMap – maintains insertion order.


• It maintains a linked list of entries in the map, in
the order in which they were inserted. This allows
insertion order iteration over the map. That is
when iterating through a collection-view of a
LinkedHashMap, the elements will be returned in
the order in which they were inserted
• It is somewhat slower than HashMap for adding
and removing elements
• You can expect faster iteration (access
elements)with a LinkedHashMap.
TreeMap
• TreeMap – is a sorted Map, sorted by natural order of elements.
• Unlike a hash map, a tree map guarantees that its elements will be sorted in
ascending key order.
• It creates maps stored in a tree structure.
• Like TreeSet, TreeMap lets you define a custom sort order (via a comparable or
a comparator) when you construct a TreeMap that specifies how the elements
should be compared with one another when they are being ordered.
• TreeMap implements NavigableMap
• Both TreeSet and TreeMap store elements in sorted order. However it is the
comparator that defines precisely what “sorted order” means. By default these
classes store their elements by using what Java refers as natural ordering
which is usually the ordering that you would expect. If you want to order
elements in a different way then specify a Comparator when you construct the
Set orMap. Doing so gives you the ability to govern precisely how elements are
stored within collections and maps. See the implementation slide
Iterating through TreeMap
• import java.util.*;
class TreeMapDemo{
public static void main(String args[]){
//create a hash map
TreeMap<String, Double> tm = new TreeMap<String, Double>();
tm.put(“John Doe”, new Double(3434.34));
tm.put(“Tom Smith”, new Double(123.22));
tm.put(“Jane Baker”, new Double(1378.00));
tm.put(“Tod Hall”, new Double(99.22));
tm.put(“Ralph Smith”, new Double(-19.08));
}
Set<Map.Entry<String, Double>> set = tm.entrySet();
for(Map.Entry<String, Double> me : set) {
System.out.print(me.getKey() + “:”);
System.out.println(me.getValue());
}
Storing a TreeSet in reverse order using Comparator
• import java.util.*;
• class MyComp implements Comparator<String> {
public int compare(String a, String b){
String aStr, bStr;
aStr = a;
bStr = b;
// Reverse the comparison
return bStr.compareTo(aStr);
}
}
class Comp{
public static void main(String args[]){
//Create a tree set.
TreeSet<String> ts = new TreeSet<String>(new MyComp());

//add elements to tree set


ts.add(“C”);
ts.add(“A”);
ts.add(“B”);
ts.add(“E”);
ts.add(“F”);
ts.add(“D”);
//display the elements
for(String element : ts)
System.out.println(element + “”);
System.out.println();
}
}
Using Comparator to sort accounts by last name
• import java.util.*;
• class TComp implements Comparator<String>{
public int compare(String a, String b){
int i, j, k;
String aStr, bStr;
aStr=a;
bStr=b;
//find the index of beginning of last name
i= aStr.lastIndexOf(‘ ’);
j= bStr.lastIndexOf(‘ ’);
k=aStr.substring(i).compareTo(bStr.subString(j));
if(k==0)
//last names match, check entire name
return aStr.compareTo(bStr);
else
return k
}
}
class TreeMapDemo2{
public static void main(String args[]){
//create a hash map
TreeMap<String, Double> tm = new TreeMap<String, Double>(new TComp());
tm.put(“John Doe”, new Double(3434.34));
tm.put(“Tom Smith”, new Double(123.22));
tm.put(“Jane Baker”, new Double(1378.00));
tm.put(“Tod Hall”, new Double(99.22));
tm.put(“Ralph Smith”, new Double(-19.08));
}
Set<Map.Entry<String, Double>> set = tm.entrySet();
for(Map.Entry<String, Double> me : set) {
System.out.print(me.getKey() + “:”);
System.out.println(me.getValue());
}
Sorting LinkedList using Comparator
import java.util.*;
class AlgorithmsDemo{
public static void main(String args[]){
LinedList<Integer> ll = new LinkedList<Integer>();
ll.add(-8);
ll.add(20);
ll.add(-20);
ll.add(8);
// Create a reverse order comparator
Comparator<Integer> r = Collections.reverseOrder();
//Sort list by using comparator
Collection.sort(ll,r);
System.out.print(“List sorted in reverse order”);
for(int i : ll)
System.out.print(i+“ ”);
//Shuffle list – the list is randomized by calling shuffle
Collections.shuffle(ll);
System.out.println(“List shuffled: ”)
for(int i : ll)
System.out.print(i+“ ”);
System.out.println(“Minimum :” + Collections.min(ll)) ;
System.out.println(“Maximum: ” + Collections.max(ll)) ;
}
Queue Interface

• Queue – is designed to hold a list of “to-dos” or things to


be processed in some way.
• Queues are typically though of a FIFO
• Queues support all of the standard collection methods
• Queues also support methods to add and subtract
elements and review queue elements.
• Priority Queue – the basic purpose is to create a “priority-
in, priority-out” queue as opposed to a typical FIFO queue.
• Elements are ordered either by natural ordering or
according to a comparator.
• In either case elements’ ordering represents their relative
priority.
ArrayList Basics

• Advantages of ArrayList over Arrays


It can grow dynamically
It provides more powerful insertion and search
mechanism than Arrays.
• ArrayList.size()
• ArrayList.remove(“Object”);
• Note: in general collections can hold objects but
not primitives.
• In both ArrayList and Linked list duplicates might
occur
Sorting List
• Sorting ArrayList containing objects of the type String.
• import java.util.*;
class TestSort1{
public static void main(String[] args){
ArrayList<String> stuff = new ArrayList<String>();
stuff.add(“Denver”);
stuff.add(“Boulder”);
stuff.add(“Vail”);
stuff.add(“Aspen”);
stuff.add(“Telluride”);
System.out.println(“unsorted “ + stuff);
Collections.sort(stuff);
System.out.println(“sorted “ + stuff);
}
}
Rule: the Collections.sort() method takes a list argument and objects in the List must
implement an interface called Comparable
Populating ArrayList by reading data from txt file
• public class HomeAutomation {
public ArrayList<DVDInfo> populateList(ArrayList<DVDInfo> alist){
try{
String loc = “D:\dvdinfo.txt”;
File f1 = new File(loc);
FileInputStream fis = new FileInputStream(f1);
DataInputStream dis = new DataInputStream(fis);
BufferedReader br = new BufferedReader(
new InputstreamReader(dis);
String line = “ “;
while((line = br.readLine())!=null){
String[] array1 = line.split(“/”);
DVDInfo dinfo = new DVDInfo(arra1[0], array1[1], array1[2]);
alist.add(dinfo);
return alist
}
}catch(Exception e){
e.printStackTrace();
}
}
Comparable Interface
• The comparable interface is used by Collections.sort() method and
java.util.Arrays.sort() method to sort Lists and arrays of objects respectively.
• The sort() method uses compareTo() to determine how List or Object array
should be sorted.
• You can use whatever criteria (instance variables)you prefer to sort instance of
your classes
• To implement comparable, a class must implement a single method compareTo()
Here is an invocation of CompareTo()
int x = thisObject.compareTo(anotherObject);
• The compareTo() method returns an int with the following characteristics:
negative - if thisObject < anotherObject
zero - if thisObject == anotherObject
positive - if thisObject > anotherObject
• It is important to remember that when you override equals() you must take an
argument of the type Object, but when you override compare() you should take
an argument of the type you are sorting.
Sorting an ArrayList containing objects of the type DVDInfo
• class DVDInfo {
String title;
String genre;
String leadActor;
ArrayList<DVDInfo> dvdlist = new ArrayList<DVDInfo>();
DVDInfo(String t, String g, String a){
this.title = t;this.genre = g;
this.leadActor = a;}
public String toString(){
return title+ “”+genre+””+ leadActor+”\n”}
HomeAutomation ha = new HomeAutomation();
ha.populateList(dvdlist);
System.out.println(dvdlist);
Collections.sort(dvdlist);
}
Note: this gives the following error:
cannot find symbol method sort(ArrayList<DVDInfo>)
Sorting with Comparator Interface
• While sorting with comparator we use an overloaded
version of sort which takes both a List and a Comparator.
• You can use it to sort instance of any class – even classes
you can’t modify.
• The comparable interface forces you to change the
class whose instances you want to sort. While sorting
with Comparator you must build a class separate from
the one whose instances you want to sort.
• Here many sort sequences can be created.
• The Comparator interface has only one method
compare(objOne, objTwo)
Sorting an ArrayList using Comparable
• import java.util.*;
class DVDInfo implements Comparable<DVDInfo> {
String title;
String genre;
String leadActor;
DVDInfo(String t, String g, String a){
this.title = t;this.genre = g;this.leadActor = a;
}
public String toString(){
return title+ “”+genre+””+ leadActor+”\n”}
public int compareTo(DVDInfo one d){
return title.compareTo(d.gettitle());
}
public String getTitle(){
return title;
}
//other getters and setters
ArrayList<DVDInfo> dvdlist = new ArrayList<DVDInfo>();
HomeAutomation ha = new HomeAutomation();
ha.populateList(dvdlist);
Collections.sort(dvdlist);
System.out.println(dvdlist);
}
}
Sorting an ArrayList using Comparator
• import java.util.*;
• class GenreSort implements Comparator<DVDInfo>{
public int compare(DVDInfo one, DVDInfo two){
return one.getGenre.compareTo(two.getGenre());
}
}

• class DVDInfo {
String title;
String genre;
String leadActor;
DVDInfo(String t, String g, String a){
this.title = t;this.genre = g;this.leadActor = a;
}
public String toString(){
return title+ “”+genre+””+ leadActor+”\n”}
//other getters and setters
}

• public class TestDVD{


ArrayList<DVDInfo> dvdlist = new ArrayList<DVDInfo>();
public static void main(String[] args){
TestDVD test = new TestDVD();
test.go();
}
public void go(){
HomeAutomation ha = new HomeAutomation();
ha.populateList(dvdlist);
GenreSort gs = new GenreSort();
Collections.sort(dvdlist, gs);
System.out.println(dvdlist);
}
}
Sorting with Array Class
• The Arrays.sort() method is overridden in the same way the
Collections.sort() method is
• Arrays.sort(arrayToSort);
• The sort() method sorts an array so that it is arranged in ascending
order
• Arrays.sort(arrayToSort, Comparator);
• Arrays.sort() methods that sort primitives always sort based on natural
order. Do not try to sort a primitive array using a comparator.
• The sort methods for both Collections class and the Array class are
static methods and that they alter the objects they are sorting instead
of returning a different sorted object.
• Whenever you want to sort an array or a collection, the elements
inside must all be mutually comparable. Objects of different types
should not be considered mutually comparable unless specifically
stated otherwise.
Rules for searching through Arrays and Collections
• searches are performed using the binarySearch() method
• the binarySearch() method uses a binary search to find a specified value.
This method must be applied to sorted arrays.
static int binarySearch(byte array[], byte value);
Here array is the array to be search and value is the value to be located
• successful searches return the int index of the element being searched.
• unsuccessful searches return the int index that represents the insertion point.
• the insertion point is the place in the collection/array where the element would be inserted
to keep the collection properly sorted.
• if the insertion point of search is at element 2 the actual insertion point returned will be -3
• zero is a valid result for successful search.
• the collection/array being searched must be sorted before you can search it.
• if the collection/array you want to search was sorted in natural order, it must be searched in
natural order i.e. comparator should not be sent as an argument to the binarySearch()
method.
• If the collection you want to search was sorted using a comparator, it must be searched using
the same comparator which is passed as a second argument to the binary search method.
• Comparators cannot be used when searching an arrays of primitives.
sorting and searching an array through comparator
• import java.util.*;
• class SearchObjArray {
public static void main(String[] args){
String [] sa = {“one”,”two”,”three”,”four”};
Arrays.sort(sa);
for(String s : sa){
System.out.println(s + “”);}
System.out.println(“one= ” + Arrays.binarySearch(sa, “one”));
System.out.print(“now reverse sort”);
ResortComparator rs = new ResortComparator();
Arrays.sort(sa, rs);
for(String s : sa){
System.out.println(s + “”);}
System.out.println(“two= “ + Arrays.binarySearch(sa, “one”, rs);
}
static class ResortComparator implements Comparator<String>{
public int compare(String a, String b){
return b.compareTo(a);
}
}
}
Note: two common mistakes made while solving searching and sorting questions
1. searching an array or collection that hasn’t been sorted.
2. Using a comparator in either the sort or search but not both.
converting Arrays to Lists
• The Arrays class has a method called asList().
• The Arrays.asList() method copies an array into a List.
• When you use asList() method, the array and the List become joined at the hip.
When you update one of them the other gets updated automatically.
• the asList() method returns a List that is backed by a specified array. In other
words both the list and the array refer to the same location.
• String sa = {“one”, “two”, “three”, “four”}
List sList = Arrays.asList(sa);
sList.set(3, “six”); //List is zero based
sa[1] = “five”; //array is zero based
for(String s : sa)
System.out.println(s + “”);
System.out.println(“sList.get(1) =” + sList.get(1));
Ans: “one”, ”five”, ”three”, ”six”;
sList.get(1) = five
How to use some of the methods of the Arrays class

• import java.util.*;
class ArraysDemo{
public static void main(String args[]){
//allocate and initialize an array
int array[] = new int[10];
for(int i=0; i<10; i++){
array[i] = -3*i;
System.out.println(“Original Contents”);
disaply(array);
Array.sort(array);
display(array);
Arrays.fill(array, 2, 6, -11);
System.out.println(“After fill() : ”)
display(array);
Array.sort(array);
System.out.println(“After sorting again: ”);
display(array);
//Binary search for -9
System.out.println(“The value -9 is at location ”);
int index = Arrays.binarySearch(array, -9);
System.out.println(index)
}
static void display(int array[]){
for(int i : array)
System.out.println(i + “”);
}
converting List and Set to Array
• The List and Set classes have toArray() method
• The toArray() method comes in two flavours
• The first flavour does not take any arguments and returns a
new Object array.
• The second flavour takes an array as an argument and
returns the same array as the destination array.
List<Integer> iL = new ArrayList<Integer>();
for(int x=0; x<3; x++)
iL.add(x);
Object[] oa = iL.toArray();
Integer[] ia2 = new Integer[3];
ia2 = iL.toArray(ia2);
using List and Iterator

• An Itertor is an Object that is associated with a


specific collection. It lets you loop through the
collection step by step. It has two methods:
• boolean hasNext() – returns true if there is at
least one more element in the collection being
traversed. Invoking hasNext() does not move
you to the next element in the collection.
• Object next() – this method returns the next
object in the collection and moves you forward
to the element after the element just returned.
code using List and Iterator
• import java.util.*;
• class Dog {
public String name;
Dog(String n){ name=n;}
}
class ItTest{
public static void main(String args[]){
List<Dog> d = new ArrayList<Dog>();
Dog dog = new Dog(“aiko”);
d.add(dog);
d.add(new Dog(“clover”));
d.add(new Dog(“magnolia”));
Iterator<Dog> i3 = d.iterator();
while(i3.hasNext()){
Dog d2 = i3.next();
System.out.println(d2.name);
}
System.out.println(“size of ArrayList”+d.size);
System.out.println(“name of element at index 1” + d.get(1).name);
System.out.println(“remove element at index 2”+ d.remove(2));
Object[] oa = d.toArray();
for(Object o : oa){
Dog d2 = (Dog)o;
System.out.println(“oa “ + d2.name)
}
}
}
using Set
• import java.util.*;
• class SetTest {
public static void main(String args[]){
boolean[] ba = new boolean[5];
Set s = new HashSet
//Set s = new TreeSet
ba[0]=s.add(“a”);
ba[1]=s.add(new Integer(42));
ba[2]=s.add(“b”);
ba[3]=s.add(“a”);
ba[4]=s.add(new Object());
for(int x=0; x<ba.length; x++)
System.out.println(ba[x] + “”);
System.out.println(“\n”);
for(Object o : s)
System.out.println(“\o”);
}
}
Ans: check page 582
Inferences from previous programme for using Set
• HashSet do not guarantee any ordering
• you cannot insert a duplicate entry into the
set
• If you replace the HashSet declaration with a
TreeSet then you get ClassCastException error.
This is because the TreeSet is sorted and you
are trying to add an element of a dissimilar
type which is not mutually comparable.
• import java.util.*;
• class Dog{
using Maps
public String name;
public Dog(String n){ name = n;}
public boolean equals(Object o){
if((o instanceof Dog)&&(((Dog)o).name == name){
return true;
}else{
return false;
}
}
public int hashcode(){ return name.length();}
}
class Cat { }
enum Pets {Dog, CAT, HORSE}
class MapTest{
public static void main(String[] args){
Map<Object, Object> m = new HashMap<Object, Object>();
m.put(“k1” , new Dog(“aiko”));
m.put(“k2”, Pets.DOG);
m.put(PETS.CAT , “CAT key”);
Dog d1 = new Dog(“clover”);
m.put(“d1”, “Dog key”));
m.put(new Cat(), “Cat key”);
System.out.println(m.get(“k1”));
String k2 = k2;
System.out.println(m.get(“k2”));
Pets p = Pets.CAT;
System.out.println(m.get(p));
System.out.println(m.get(d1));
System.out.println(m.get(new Cat()));
System.out.println(m.size());
}}
Inferences from previous programme for using Maps
• In the previous programme we are able to successfully use an Enum
as a key. This shows that enums override equals() and hashCode()
which is the reason they do not need to do that again in a class
where we are retrieving their values from HashMap.
• If a class does not override the equals() and the hashCode() method
the get() method will not fail to find the object that was used as a
key to insert values into the Map.
• the more unique hashcodes a formula creates, the faster the
retrieval will be.
• When the object used as a key has its values changed then the
values in the map will not be found because
the program uses the hashCode() value of the object to find the
correct bucket.
the program uses the equals method to find the object in the
bucket.
searching TreeSets and TreeMaps
• import java.util.*;
• public class Ferry {
public static void main(String args){
TreeSet<Integer> times = new TreeSet<Integer>();
times.add(1205);
times.add(1505);
times.add(1545);
times.add(1830);
times.add(2010);
times.add(2100);
TreeSet<Integer> subset = new TreeSet<Integer>();
subset = (TreeSet)times.headSet(1600);
System.out.println(“J5 – last before 4 pm is:” + subset.last());
TreeSet<Integer> sub2 = new TreeSet<Integer>();
sub2= (TreeSet)times.tailSet(2000);
System.out.println(“J5 – first after 8 pm is:” + sub2.first());
System.out.println(“J6 – last before 4 pm is:” + times.lower(1600));
System.out.println(“J6 – first after 8 pm is:” + times.higher(2000));
}
}
Inferences from previous programme for using TreeSets and
TreeMaps

• lower() – returns the element less than the given element.


• floor() – returns the element less than or equal to the given element.
• higher() – returns the element greater than the given element.
• ceiling() – returns the element greater than or equal to the given
element.
• pollFirst() – returns and removes the first entry in the set.
• pollLast() - returns and removes the last entry in the set.
• TreeSet.descendingSet() – return a NavigableSet in reverse order
• TreeMap.descendingMap() return a NavigableMap in the reverse
order where NavigableSet and NavigableMap are interfaces.
Backed Collections
• TreeMap.subMap() method makes a copy of a portion of TreeMap named map and
returns an object of the type SortedMap as shown below.
• TreeMap<String, String> map = new TreeMap<String, String>();
• map.put(“a”, “ant”);
• map.put(“d”, “dog”);
• map.put(“h”,”horse”);
• SortedMap<String,String> submap = map.subMap(‘b”, “g”);
• System.out.println(map + “ “ + submap);
• map.put(“b”, “bat”);
• submap.put(“f”, “fish”);
• map.put(“r”, “racoon”);
• System.out.println(map + “ “ + submap);
• Note: when we add key –value pairs to either the original TreeMap or the partial-
copy SortedMap, the new entires were automatically added to the other collection.
• In addition we can add a new entry to the original collection, even if its outside the
range of the copy. In this case the new entry will show up only in the original. It
won’t be added to the copy because it’s outside the range of the copy.
• If you attempt to add an out of the range element to the copied collection an
exception will be thrown.
Important “Backed Collection“ methods for TreeSet and TreeMap
• headSet(e, b*) – returns a subset ending at element e and exclusive of e.
• headMap(e, b*) – returns a submap ending at key k and exclusive of key k.
Note: the above methods create a subset that starts at the beginning of the original
collection and ends at the point specified by the method’s argument
• tailSet(e, b*) – returns a subset starting at and inclusive of element e.
• tailMap(k, b*) – returns a submap starting at and inclusive of key k.
• subSet(s, b*, e, b*) – returns a subset starting at element s and ending just before
element e.
• subMap(s, b*, e, b*) – returns a submap starting at key s and ending just before key s.
• Note: subSet/subMap allow you to specify both the start and end points for the subset
collection you are creating.
Note: the b* indicates boolean arguments. These arguments are optional. If they exist it’s a
java 6 method that lets you specify whether the end point exclusive and these methods
return a navigableXxx. If these boolean argument don’t exist the method returns either a
SortedSet or a SortedMap
• Note: lets say that you have created a backed collection using either a tailXxx() or subXxx()
method.Typically in these cases the origianl and the copy collection have different first
elements. The method pollFirstXxx() will always remove the first entry from the collection
on which they are invoked, but they will remove element from the other collection only if
it has same value. It is most likely that invoking pollFirstXxx() on the copy will remove
entry from both collections but invoking pollFirstXxx on the original will remove the entry
only from the original.
PriorityQueue class
• PriorityQueue – orders its elements using a user defined priority.
Priorities can be as simple as natural ordering (in which for instance
an entry of 1 would be a higher priority than an entry of 2).
• PriorityQueue can be ordered using a comparator which lets you
define any ordering you want.
• Queues have few methods not found in other collection interfaces:
peek(), poll(), offer();
• peek() – returns the highest priority element in the queue without
removing it.
• poll() - returns the highest priority element AND removes it from the
queue.
• offer() – is used to add elements to the PriorityQueue.
program showing methods of the priority queue
• import java.util.*;
• class PQ {
static class Pqsort implements Comparator<Integer>{
public int compare(Integer one, Integer two){
return two – one;
}
public static void main(String[] args){
int[] ia {1, 5, 3, 7, 6, 9, 8}
PriorityQueue<Integer> pql = new PriorityQueue<Integer>();
for(int x: ia)
pql.offer(x);
for(int x : ia)
pql.poll();
Pqsort pqs = new Pqsort();
PriorityQueue<Integer> pq2 = new PriorityQueue<Integer>(10, pqs);
for(int x : ia)
pq2.offer(x);
System.out.println(“size” + pq2.size());
System.out.println(“peek” + pq2.peek());
System.out.println(“size” + pq2.size());
System.out.println(“poll” + pq2.poll());
System.out.println(“size” + pq2.size());
for(int x : ia)
System.out.println(“poll” + pq2.poll() + “ “);
}
}
Legacy Classes
• The legacy classes defined by java.util include:
Dictionary
Hashtable
Properties
Stack
Vector
• None of the collection classes are synchronized but all legacy classes
are synchronized.
• There is one legacy interface called Enumeration
• Enumeration is now considered obsolete for new code.
• Enumeration has two methods:
boolean hasMoreElements()
E nextElement()
Generic Types
• Arrays in java have always been type safe, an array declared as type
String can’t except Integers.
• As of java 5 we can use generics for making type safe collections.
• Generics are not just for collections.
• A non generic object can hold any type of collections i.e. anything
that is not a primitive.
• since a non generic collection could hold anything, the methods that
get objects out of the collection could have only one kind of return
type – java.lang.Object. That means getting a String back out of our
String only intended List required a cast:
String s = (String) myList.get(0);
• Generics takes care of both ends(putting in and getting out) by
enforcing a type of your collections. That means you can get rid of
the cast when you get something from the collection.
List<String> myList = new ArrayList<String>();
myList.add(“Fred”);
String s = myList.get(0);
Generic Types
• You can also declare a type parameter for a method argument which then makes the
argument a type safe reference.
void takeListOfStrings(List<String> teststring){
teststring.add(“foo”);}
• Return types can also be declared type safe as well:
public List<Dog> getDogList(){
List<Dog> dogs = new ArrayList<Dog>();
return dogs;}
• Since the compiler guarantees that only a type safe Dog List is returned, those calling the
get(int x) method won’t need a cast to take dogs from the list e.g.
public List<Dog> getDogList(){
List<Dog> dogs = new ArrayList<Dog>();
return dogs;}
Dog d = (Dog)getDogList().get(0); //cast not required
• Declaring a List with a type parameter of <Object> makes a collection that
works in almost the same way as a pre java 5 non-generic collection. You can put any object
type into the collection.
List<Object> myList = new ArrayList<Object>();
Generic Types
• To update the non generic code to make it generic, you add a type in angular brackets(<>)
immediately following the character type in both the variable declaration and the constructor
call including any place you declare a variable(so that means arguments and return types too.
• In order to support legacy code, java 5 and java 6 allows your newer type safe code to make
use of your older code.
• The compiler will generate warnings, if it sees that there is a chance your type safe collection
could be harmed by older, non type safe code.
• Why does JVM allow old code to add a wrong thing into a typed ArrayList. The typing
information does not exist at runtime. All your generic code is strictly for the compiler.
Through a process called type erasure, the compiler does all its verification on your generic
code and then strips the type information out of the class byte code.
• At runtime all collection code (both legacy and new code) looks exactly like the pre generic
version of collections.
• Generics is strictly a compile time protection. The compiler uses generic type information to
make sure that your code does not put the wrong things into the collection and that you do
not assign what you get from the collection to the wrong reference type. It also eliminates
need for cast when you get something out. None of this protection exists at runtime.
• Arrays give you both compile time and runtime protection.
• You don’t need runtime protection until you start mixing up generic and non generic code.
Generic Types
• Adding a String to an <Integer> list will not fail at runtime until you try to use that String you
think is an Integer and it does not match what you were expecting.
• The moment you turn your type safe collection over to older non type safe code your
protection vanishes.
• whenever using legacy collections – watch out for boxing problems. If you declare a non
generic collection, the get() method always returns a reference of type java.lang.Object
• Remember that unboxing cannot convert a plain old object to a primitive even if that Object
references to an Integer (or some other wrapped primitive)on the heap. Unboxing converts
only from a wrapper class reference (like an Integer or a Long) to a primitive.
• RULE: The type of the variable declaration must match the type you pass to the actual object
type. In other words polymorphism applies only to the base type and by base type we mean
the type of collection class itself.
List<Object> myList = new ArrayList<JButton>(); // Not possible
• Polymorphism does not work the same way for generics as it does with arrays. With arrays
you are allowed to do this:
Object[] myArray = new Jbutton[3]; //Yes its possible
• ArrayList<Dog> cannot be passed into a method with an argument of ArrayList<Animal>,
even though we know that this works fine with plain old arrays. You simply cannot assign the
individual ArrayLists of Animal subtypes (<Dog>, <Cat> or <Bird>) to an ArrayList of the
supertye <Animal> which is the declared type of the argument.
Generic Types
• Part of the benefit of declaring an array using a more abstract supertype is that the array
itself can hold objects of multiple subtypes of the supertype. So we are using polymorphism
not for the object that the array points to but rather what the array can actually hold. You can
do the same thing with generics.
List<Animal> animals = new ArrayList<Animal>();
animals.add(new Cat());
animals.add(new Dog());
• We can add an instance of a subtype into an array or a collection declared with a supertype.
You could pass a Dog[] into a method that takes an Animal[]
public void foo(){
Dog[] dogs = { new Dog(), new Dog() };
addAnimal(dogs);
}
public void addAnimal(Animal[] animals){
animals[0] = new Dog();
}
• Rule: the only thing we can pass to a method argument of ArrayList<Animal> is an
ArrayList<Animal>. The reason you can get away with compiling this for arrays is because
there is a runtime exception (ArrayStoreException) that will prevent you from putting the
wrong type of object into an array. There is no equivalent exception in generics because of
the type erasure.
Generic Types - <? extends Animal>
• RULE: there is a mechanism to tell the compiler that you can take any
generic subtype of the declared argument type because you wont be
putting anything into the collection.
public void addAnimal(List<? extends Animal> animals){
animals.add(new Dog());
//can’t add if we use <? extends Animal>
animals.xyz(new Dog());
}
• <? extends Dog> means List<Beagle>, List<Poodle>, or any other
subtype of Dog.
• RULE: the <? extends Animal> means that you can take any subtype of
Animal, however that subtype can be either a subclass of a class
(abstract or concrete) or a type that implements the interface after the
word extends.
• There is only one wildcard keyword that represents both interface
implementation and subclasses. And that keyword is extends.
Generic Types - <? super Dog>
• If you try to pass a List with a generic type that is of type Dog or a super type of Dog to a method, the
compiler will accept. Nothing lower in the inheritance tree can come in but anything higher than Dog is
OK.
You do this using the wildcard super as below.
public void addAnimal(List<? super Dog> animals){
aminals.add(new Dog());
}
public static void main(String[] args){
List<Animal> animals = new ArrayList<Animal>();
animals.add(new Dog());
animals.add(new Dog());
AnimalDoctorGeneric doc = new AnimalDoctorGeneric ();
doc.addAnimal(animals); // passing an animal list
}
• The syntax<? super …> tells the compiler that you can accept the type on the right hand side of super or
any of its super types. A collection declared as any supertype of Dog will be able to accept a Dog as an
Element.
• public void foo(List<?> list{}
Note: List<?> is the wildcard without the keyword extends or super so it means that any type of List can be
assigned to the arguemnt e.g. List<Dog>, List<Integer>, List<Jbutton>
And using the wildcard alone without the keyword super (followed by type) means that you cannot add
anything to the list referred to as List<?>
• List<Object> means that the method can take only a List<Object> , not a List<Dog> etc However you can
add to the List
`
Generic Types

• If you see wildcard notation (a question mark ?) it


means many possibilities.
• keep in mind that wildcard can be used only for
reference declarations (including arguments,
variables, return types and so on). They cant be
used as the type parameter when you create a
new typed collection i.e. you cannot use wildcard
notation in the object creation using new.
• How do we know that we are supposed to specify
a type for these collection classes – the API tells
you when a parameterized type is expected.
Generic Declarations
• public Interface List<E>
• boolean add(E o)
• E is the place holder for the type you pass in
• T is the place holder for things that are not
collections
• E stands for element and is used when the
template is a collection
Creating generic class
• can we make our own generic class that requires someone to pass a type in when they
declare it and instantiate it.
• import java.util.*;
public class RentalGeneric<T>{
private List<T> rentalPool;
private int maxNum;
public RentalGeneric(int mN, List<T> rP){
this. maxNum = mN;
this. rentalPool = rP;
}
public T getRental(){
return rentalPool.get(0);
}
public void returnRental (T returnedThing){
rentalPool.add(returnedThing);
}
}
putting our previously created generic class to test
• class TestRental{
public static void main(String[] args){
Car c1 = new Car();
Car c2 = new Car();
List<Car> carList = new ArrayList<Car>();
carList.add(c1);
carList.add(c2);
RentalGeneric<Car> carRental = new RentalGeneric<Car>(2, carList);
Car carToRent = carRental.getRental();
carRental.returnRental(carToRent );
}
}
Simple class using parameterized type of the class

• public class TestGenerics<T>{


T anInstance;
T[] anArrayOfTs;
TestGenerics(T anInstance){
this.anInstance = anInstance;
}
T getT(){
return anInstance;
}

}
Using more than one parameterized type in a single class definition
• public class UseTwo<t, X>{
T one,
X two;
UseTwo(T one,X two ){
this.one = one;
this.two = two;
}
T getT(){ return one;}
X getX(){ return two;}
public static void main(String[] args){
UseTwo<String, Integer> twos = new UseTwo<String, Integer> (“foo”, 42);
String theT = twos.getT();
int theX = twos.getX();
}
}
Creating Generic Methods
• create a method that takes an instance of any type, instantiates an ArrayList of that type
and adds the instance to the ArrayList
import java.util.*;
public class CreateArrayList{
public <T> void makeArrayList<T>(T t){
List<T> list = new ArrayList<T>();
list.add(t);
}
}
• Note: the strangest thing about generic method is that you must declare the type variable
before the return type of the method.
public <T> void makeArrayList<T>(T t)
the <T> before void simply defines what T is before you use it as a type in the argument.
• You are also free to put boundaries on the type you declare. If you want to restrict the
makeArrayList() to only Number or its subtypes
public <T extends Number> void makeArrayList(T t)
• Note : it is tempting forget that the method argument is not where you declare the type
parameter variable. In order to use a type variable like T, you must have declared it either
as a class parameter type or in the method before the return type. The below is not right
• public void makeList<T t){ } // type declaration not done before void
Creating Generic Constructors
• Constructors too can be declared with a generic type but
then it looks even stranger since constructors have no return
types at all
public class Radio{
public <T> Radio(T t) { }
• while the question mark works when declaring a reference
for a variable it does not work for a generic class and
method declarations Thye below code is not legal
public class NumberHolder<?>{
? anum;
}
If you replace the ? with a legal identifier, you’re good
public class NumberHolder<T> { T aNum;}
Chap 8. Inner Classes
Inner Class
• Inner class lets you define one class within another. They provide a type of scoping for your
classes since you can make one class a member of another class. Just as classes have member
variables and methods a class can also have member classes. They come in several flavors
depending on how and where you define the inner class including a special kind of inner class
known as top level nested class which is a static nested class defined within the scope of
another class.
• When to use an inner class – you find yourself designing a class when you discover you need
a behavior that belongs in a separate specialized class but also needs to be intimately tied to
the class you are designing.
• Key benefits of inner class – one of the key benefits of the inner class is the special
relationship an inner class instance shares with an instance of the outer class. This special
relationship gives code in the inner class access to all members of the outer class even those
marked private.
• Regular inner class – we use the term regular inner class to represent inner classes that are
not static, method-local, anonymous.
• class MyOuter {
private int x = 7;
class MyInner {
public void seeOuter(){
System.out.println(“Outer x is” +x);
}
}
}
Inner class
•the only way you can access the inner class is through a live instance of the outer class.
•to create an inner class you must have an instance of the outer class to tie to the inner class.
•Instantiating an inner class from within the outer class:
•class MyOuter {
private int x = 7;
public void makeInner(){
MyInner in = new MyInner();
in.seeOuter();
}
class MyInner {
public void seeOuter(){
System.out.println(“Outer x is” +x);
}
}
}
Note: the only reason why this code works is because the outer class instance method is doing
the instantiating. In other words there is already an instance of the outer class – the instance
running the makeInner() method.
Creating an object from outside the outer class instance code
• If we want to create an instance of the inner class we must have an instance of
the outer class. Without a reference to an instance of the outer class, you
cannot instantiate the inner class from a static method of the outer class
(because in a static code there is no instance).
• public static void main(String[] args){
MyOuter mo = new MyOuter();
MyOuter.MyInner inner = mo.new MyInner();
inner.seeOuter()
}
• public static void main(String[] args){
MyOuter.MyInner inner = new MyOuter.new MyInner();
inner.seeOuter()
}
• Note: the preceding code is the same regardless of whether the main() method
is within the MyOuter class or some other class.
• also there is no this if there is no instance method
the this reference
• the keyword this can be used only from within instance
code. In other words not within static code.
• The this is a reference to the currently executing object.
In other words the object whose reference was used to
invoke the currently running method.
• The this reference is the way an object can pass a
reference to itself to some other code as a method
argument:
public void myMethod(){
MyClass mc = new MyClass();
mc.doStuff(this);
}
Rules for inner class referencing itself or the outer instance from within the inner classs
• within an inner class code the this reference refers to the instance of the inner class.
• to reference the outer this (the outer class instance) from within the inner class code use
NameOfTheOuterClass.this
• Note: the inner class needs reference to the outer class if it needed to pass that reference to some other code.
• class MyOuter{
private int x = 7;
public void makeInner(){
MyInner in = new MyInner();
in.seeOuter();
}
class MyInner{
public void seeOuter(){
System.out.println(“Outer x is “ + x);
System.out.println(“Inner class ref is “ + this);
System.out.println(“Outer class ref is “ + MyOuter.this);
}
}
public static void main(String[] args){
MyOuter.MyInner inner = new MyOuter.new MyInner();
inner.seeOuter();
}

}
Member modifiers applied to inner classes

• An inner class is a member of the outer class so the


following modifiers can be applied to the inner class.
• final
• abstract
• public
• private
• protected
• static
• strictfp
Method-local inner classes
• An inner class defined within a method is called method local inner class.
class MyOuter2 {
private String x = “Outer2”;
void doStuff(){
class MyInner{
public void seeOuter(){
System.out.println(“Outer x is” +x);
}
}
MyInner mi = new MyInner();
mi.seeOuter();
}
}
• To use the method local inner class you must make an instance of the inner class somewhere
within the method but below the inner class definition
• Note: a method local inner class can be instantiated only within the method where the class is
defined.
• the method local inner class shares a special relationship with the outer class and
access its private members.
• inner class cannot use the local variables of the method the inner class is in.
• however inner class can use the local variables marked final.
Method-local inner classes

• you cannot mark a method local inner class public


private, protected, static, transient and the like.
• the only modifiers you can apply to a method local
inner class are abstract and final and default.
• a local class declared in a static method has access
to only static members of the enclosing class since
the is no associated instance of the enclosing class.
• an inner class in a static method is subject to same
restrictions as the static method. In other words
no access to instance variables.
Anonymous Inner Classes
• anonymous inner classes are classes declared without any class name at all. You can define these classes not just
within a method but even within an argument to a method.
• Plain old anonymous inner classes flavor one
class Popcorn{
public void pop() {
System.out.println(“popcorn”);
}
}
class Food {
Popcorn p = new Popcorn(){
public void pop(){
System.out.println(“anonymous popcorn”);
}
};
}
• the Popcorn reference variable p refers not to an instance of Popcorn, but to an instance of anonymous
(unnamed) subclass of Popcorn.
• This anonymous sub class Popcorn has a pop() method which is overriding the pop method of the super class
Popcorn.
• the anonymous sub class must end with a semi colon
• the whole point of making an anonymous inner class is to override one or more methods of the super class or to
implement methods of an interface.

Anonymous Inner classes – flavour 1
• You can only call methods on an anonymous inner class that are defined in the reference
variable type class.
• class Popcorn{
public void pop() {
System.out.println(“popcorn”);
}
}
class Food {
Popcorn p = new Popcorn(){
public void sizzle(){
System.out.println(“anonymous sizzling popcorn”);
}
public void pop(){
System.out.println(“anonymous popcorn”);
}
};
public void popIt(){
p.pop(); // OK
p.sizzle(); //not legal
}
Anonymous Inner Classes – flavor 2
• flavor one creates anonymous sub class of the specified types.
• flavor two creates an anonymous implementer of the specified interface type.
interface Cookable {
public void cook();
}
class Food{
Cookable c = new Cookable(){
public void cook(){
System.out.println(“anonymous cookable implementer”);
}
};
}
Note: the preceding code creates an instance of anonymous inner class but the new just in time
class is an implementer of the Cookable interface.
• Note: this is the only time where you will see the syntax:
new Cookable
where Cookable is an interface rather than a non abstract class type.
• One more thing to keep in mind about anonymous interface implementers is that they can
implement only one interface.
• an anonymous inner class cannot choose to even extend a class and implement an interface at the
same time.
• If the anonymous inner class is a subclass of a class type it automatically becomes an implementer
of any interfaces implemented by the superclass.
Argument Defined Anonymous Inner Classes

• class MyWonderfulClass {
void go() {
Bar b = new Bar();
b.doStuff(ackWeDoNotHaveAFoo);
}
}
interface foo{
void foof();
}
class Bar {
void doStuff(Foo f){
}
If you try to instantiate the Bar class and then call the doStuff() method you will
realize that you don’t have an object from a class that implements Foo and you
cant instantiate one because you don’t even have a class that implents Foo. This
can be solved by defining an inner class right inside the argument of doStuff().
Argument Defined Anonymous Inner Classes
• class MyWonderfulClass {
void go() {
Bar b = new Bar();
b.doStuff(new Foo{
public void foof(){
System.out.println(“foofy”);
}
});
}
}
interface foo{
void foof();
}
class Bar {
void doStuff(Foo f){
}
Note: if the inner classes are argument local they end like });
If they are plain old anonymous inner classes they end like };
Static Nested Classes
• a static nested class is simply a class that’s a static member of the enclosing class.
class BigOuter {
static class Nested { }
}
• the class itself is not really static as there is no such thing as a static class.
• the static modifier in this case says that the nested class is a static member of
the outer class. That means it can be accessed without having an instance of the
outer class.
• static nested class does not enjoy a special relationship with the outer class (i.e.
the instance f the two do not share a relationship as there not exist an instance
for static nested class.)
• static nested class is simply a non inner class scoped within another.
• you can use standard syntax to access static nested class from its enclosing class.
• A static nested class does not have access to instance variables and non static
methods of the outer class.
Instantiating a static nested class from a non enclosing class
• class BigOuter {
static class Nest { void go(){System.out.println(“hi”);}
}
}
class Broom{
static class B2 { void goB2(){System.out.println(“hi 2”);}
}
public static void main(String[] args){
BigOuter.Nest n = new Bigouter.Nest();
n.go();
B2 b2 = new B2();
b2.goB2();
}
}
Chapter 9 Threads
Threads

• In java threads mean two different things:


1) an instance of the class java.lang.thread
2) a thread of execution.
• An instance of a thread is just an object. Like
any other object in java, it has variables and
methods and lives and dies on the heap.
• A thread of execution is an individual process
that has its own call stack. In java there is one
thread per call stack.
main thread, User and Daemon threads
• the main method runs in one thread called the main thread. It creates it own
stack called the main call stack.
• it is the first method on the stack – the method at the bottom.
• as soon as you create a new thread a new stack materializes and methods
called from that thread run in a call stack that’s separate from the main call
stack.
• the new call stack is said to run concurrently with the main call stack.
• the JVM operated like a mini OS and schedules it own threads regardless of
the underlying operating system.
• When it comes to threads very little is guaranteed.
• Different JVMs can run threads in different ways so programs should not be
designed to be dependent on particular implementation of JVMs
• User and daemon threads – the JVM exists an application when all the user
threads are complete, the JVM doesn’t care about letting the daemon
threads complete. Once all the user threads are complete the JVM will shut
down
methods of thread class
• start()
• run() – the code that needs to be run in a
separate thread is written in the run() method.
The thread of execution always begins by
invoking the run method.
• sleep()
• yield()
first way to define and instantiate a thread:

• extend the java.lang.Thread class and override the run() method


• If you create the thread using the no-arg constructor the thread will call its own run()
method when its time to start working. That’s exacly what you want when you extend
a thread.

class MyThread extends Thread {


public void run() {
System.out.println(“Important job running in MyThread”);
}
}
public class TestThreads{
public static void main(String[] args){
MyThread t = new MyThread();
t.start();
}

• Note: if you extend thread you cannot extend anything else.


second way to define and instantiate a thread

• implement the Runnable interface.


• when you implement the Runnable interface you need to tell the new thread to use your
run() method rather than its own.
class FooRunnable implements Runnable{
public void run(){
for(int x = 1; x < 6; x++){
System.out.println(“Runnable running”);
}
}
}
public class TestThreads{
public static void main (String args[]){
FooRunnable r = new FooRunnable;
Thread t = new Thread(r);
t.start();
}
}
• the Runnable you pass to the thread is called the target or target Runnable.
• giving the same target to multiple threads means that several threads of execution will be
running the very same job and that the very same job will be done multiple times.
Overloading the run() method in your thread subclass
• class Mythread extends Thread{
public void run(){
System.out.println(“Important job running in MyThread”);
}
public void run(String s){
System.out.println(“String in run id “ + s);
}
}
Note:
1. The overloaded run(String s) method will be ignored by the Thread class
unless you call it yourself.
2. Thread class expects a run method with no arguments and will execute this
method for you in separate call stack after the thread has been started.
3. The Thread class will not call the run(String s) method for you.
4. If you call this method yourself, execution will not happen in a new thread of
execution with separate call stack.
useful thread methods

• isAlive() – this method is the best way to determine if a


thread has been started but has not yet completed its run()
method.
• getState() – this method is useful for debugging.
• Thread.currentThread() – returns reference to the currently
executing thread.
• Thread.currentThread().getName() – prints the name of the
thread that is currently that Runnable object’s run method.
• Thread.setName()
• Thread.getId() – this method returns a positive unique long
number and that number will be threads only ID number for
the threads entire life
methods from the java.lang.Thread class
• public static void sleep(long millis) throws InterruptedException – the argument of this method
should be in millisec. You use it in your code to slow a thread down by forcing it into sleep mode
before coming back to runnable. You wrap calls to sleep in try – catch. When a thread encounters
sleep call it must go to sleep for at least the specified number of milliseconds. If a thread in sleep
state is interrupted before wakeup time it throws InterruptedException. Sleep time is not a
guarantee that the thread will start running again as soon as the time expires and the thread
wakes up. Sleep() method puts the currently running thread to sleep.
• public static void yield() – this method makes the currently running thread head back to
runnable to allow other threads of the same priority to get their turn. The yield method isn’t
guaranteed to do what it claims and even if yield does cause a thread to step out of running and
back to runnable there is no guarantee that the yielding thread won’t be chosen again over all
others. A yield wont ever cause a thread to go to the waiting/sleeping/blocking state.
• public final void join() throws InterruptedException – this causes current thread to stop
executing until the thread it joins with (in other words the thread which calls t.join()) completes.
The thread its trying to join with is not alive, the current thread won’t need to ack out.
Thread t = new Thread();
t.start();
t.join();
the above code takes the currently running thread and joins it to the end of thread referenced by
t. This blocks the current thread from becoming alive until after the thread referenced by t is no
longer alive.
• public final void setPriority(int newPriority) – used for setting priority of a thread.
starting and running multiple threads
• class NameRunnable implements Runnable{
public void run(){
for(int x=1; x<=3; x++){
System.out.println(“Run by “ +Thread.currentThread().getName() + “, x is “ +x);
}
}
}
public class ManyNames {
public static void main(String[] args){
MakeRunnable nr = new MakeRunnable();
Thread one = new Thread(nr);
Thread two = new Thread(nr);
Thread three = new Thread(nr);

one.setName(“Fred”);
two.setName(“Lucy”);
three.setName(“Ricky”);
one.start();
two.start();
three.start();
}
}
Key point on threads
• just because a series of threads are started in a particular order it does
not mean that they will run in that order.
• order is not guaranteed by the scheduler and duration is not guaranteed.
• when a thread completes it execution its still a thread object just not a
thread of execution. You can call methods on the thread instance.
• you can’t call start() again on existing thread.
• if you call start() again it will throw IllegalThreadStateException.
• at any given time the currently running thread usually will not have a
priority that is lower than any of the threads in the pool. In most cases
the running thread will be of equal or greater priority than the highest
priority thread in the pool.
• Note: calling a run() method directly just means that you are invoking a
method from whatever thread is currently executing and the run()
method goes into the current call stack rather than beginning a new call
stack.
Thread Scheduler

• the thread scheduler is the part of the JVM that


decides which thread of all the eligible threads (in the
runnable state)will actually run and also takes threads
out of the run state.
• if a thread is not in a runnable state then it cannot be
chosen to be the currently running thread.
• the order in which runnable threads are chosen is not
guaranteed.
• queue behaviour means that when a thread is finished
with its turn, it moves to the end of the runnable pool
and waits until it get to the front of the line where it
can be chosen again.
Thread States
• new – this is the state the thread is in after the Thread instance has been created but the start()
method has not been invoked on the thread. At this point the thread is considered not alive.
• runnable – once the start() method is called the thread is considered to be alive even though
run() method may not have actually started executing yet. It is eligible to run but the scheduler
has not selected it for running. Thread moves from the new state to the runnable state. A new
thread of execution starts (with a new call stack). A thread can also return to the runnable state
after either running or coming back from a blocked, waiting or sleeping state.
• running – this is the state the thread is in when the thread scheduler selects it (from the
runnable pool) to be the currently executing process. when a thread gets a chance to execute
its target run() method will run. There is only one way to get to the running state when the
scheduler chooses a thread from the runnable pool.
• waiting/blocked/sleeping – this is the state the thread is in when it is not eligible to run. The
thread may return to a runnable state later if a particular event occurs.
A thread may be blocked waiting for a resource (like I/O or an objects lock). A thread in the
blocked state is considered to be alive.
A thread may be sleeping because the thread’s run code tells it to sleep for some period of
time.
A thread may be waiting because the threads run code causes it to wait.
• dead – when the run() method completes the thread ceases to be a thread of execution. The
stack for that thread dissolves and the thread is considered dead. It is still a Thread object. You
cant call start() method again on that object.
Setting a Thread’s Priority
• public class TestThreads {
public static void main(String args[]) {
Mythread t = new MyThread();
t.setPriority(8);
t.start();
}
}
• public class TestThreads {
public static void main(String args[]) {
FooRunnable r = new FooRunnable();
Thread t = new Thread(r);
t.setPriority(8);
t.start();
}
}
Note:
1. Priorities are set using a positive interger usually between 1 and 10 and the JVM will never change a thread’s
priority.
2. The default priority is 5.
3. The Thread class has three following constants (static final variables) that define range of thread priorities:
Thread.MIN_PRIORITY(1);
Thread.NORM_PRIORITY(5);
Thread.MAX_PRIORITY(10);
scenarios in which a thread might leave the running state

• The thread’s run method completes.


• A call to wait on an object, we don’t call wait()
on a thread.
• A thread can’t acquire lock on the object
whose method code its trying to run.
• The thread scheduler can decide to move the
current thread from running to runnable in
order to give another thread a chance to run.
race condition and prevention
• this problem is known as race condition where multiple threads can access the
same resource (typically an object’s instance variables) and can produce
corrupted data if one thread races too quickly before an operation that should
be atomic is completed.
• the solution for the race condition is quite simple, we must guarantee that the
various steps of the operation which should be atomic are never split apart.
• Or we need to guarantee that even if the thread running the atomic operation
moves in and out of the running state no other thread will be able to act on
the data.
• methods for protecting the data
a) mark the variables private
b) synchronize the code that modifies the variables.
Remember you protect the variables in the normal way – using access control
modifier. It is the method code you must protect, so that only one thread at a
time can be executing that code.
You do this with by placing the synchronized keyword before the method
return type.
synchronization and locks
• every object in java has a built in lock that only comes into
play when the object has synchronized method code.
• when we enter a synchronized non static method we
automatically acquire the lock associated with the current
instance of the class whose code we are executing.
• since there is only one lock per object, if one thread has
picked up the lock, no other thread can pickup the lock
until the first thread releases the lock. This means that no
other thread can enter the synchronized code until the
lock has been released.
• releasing the lock means that the thread holding the lock
exists the synchronized method.
key points about synchronization
• only methods (or blocks)can be synchronized not variables or classes.
• each object has just one lock.
• not all methods in a class need to be synchronized. A class can have both synchronized and
non-synchronized methods.
• once a thread acquires the lock on an object, no other thread can enter any of the
synchronized methods in that class (for that object).
• If you have methods that don’t access the data you are trying to protect then you don’t need
to synchronize them.
• If a class has both synchronized and non synchronized methods multiple threads can still
access the class’s non synchronized methods.
• Synchronization can cause a hit in some cases so you should not overuse it.
• if a thread goes to sleep it holds the locks it has and does not release them.
• a thread can acquire more than one lock by invoking the synchronized methods on different
objects. As the stack unwinds the locks are released again.
• a thread is free to call other synchronized methods on the same object using the lock the
thread already has.
• You can also synchronize a block of code
• When you synchronize a method, the object used to invoke the method is the object whose
lock must be acquired.
synchronized block
• if the scope of the method is more than needed you can reduce the scope of
the synchronized part to something less than a full method – to just a block. A
sunchronized block looks as follows:
class SyncTest {
public void doStuff(){
System.out.println(“not synchronized”);
synchronized(this){
System.out.println(“synchronized”);
}
}
}
• when you synchronize a block of code, you specify which object’s lock you
want to use as a lock you could for example use some third party object as a
lock for this piece of code.
• Or you can synchronize on the current instance this as in the code above. This
is the same instance that synchronized method locks on.
synchronizing static methods
• there is only one copy of static data you are trying to protect, so you need only one lock per class to
synchronize static methods.
• every class loaded in java has a corresponding instance of java.lang.Class representing that class. Its that
java.lang.Class instance whose lock is used to protect the static methods of the class(if the static method is
synchronized.)
• public static synchronized int getCount(){
return count;
}
• this could again be replaced with code that uses a synchronized block. If the getCount() method is defined
in a class called MyClass, the equivalent code is as follows:
public static int getCount(){
synchronized(MyClass.class){
return count;
}
}
Note: its quick and easy to use a class literal. Just write the name of the class and .class at the end.
• You can also do this with the following code:
• public static void classMethod(){
Class c1 = Class.forName(“MyClass”);
synchronized(c1){
// do stuff
}
}
rules for blocking
• Threads calling non-static synchronized methods in the same class will only
block each other if they are invoked using the same instance. That’s because
they lock on this instance.
• if the threads are called using two different instances, they get two locks which
do not interfere with each other.
• threads calling static synchronized methods in the same class will always block
each other because they lock on the same Class instance.
• a static synchronized method and a non static synchronized method will not
block each other because static method blocks on Class instance while the non
static method locks on this instance.
• for synchronized blocks you will have to look at exactly what object has been
used for locking. Threads that synchronize on the same object will block each
other.
• wait() method gives up the locks
• join(), sleep(), yield() – these methods keep locks
• notify() – this method also keeps locks, although the thread will exit the
synchronized code shortly after this call and thus give up the locks.
when do I need to synchronize
• generally any time more than one thread is accessing mutable(changeable) data
you synchronize to protect that data to make sure two threads are not changing it
at the same time.
• you need to worry about static and non static fields if they contain data that can be
changed.
• for changeable data in a non-static field you usually use a non static method to
access it. By synchronizing that method you will ensure that any threads trying to
run that method using the same instance will be prevented from simultaneous
access.
• for changeable data in a static field you usually use a static method to access it.
Again by synchronizing the method you will ensure that any two threads trying to
access the data will be prevented from simultaneous access.
• access to static fields should be done from static synchronized methods and access
to non static fields should be done from non static synchronized methods
• just because a class is described thread-safe it doesn’t mean it is always thread
safe. If individual methods a synchronized, they may or may not be enough you
may be better off by putting synchronization at the higher level i.e. put it in the
block or method that calls other methods.
deadlock
• deadlock occurs when two threads are
blocked with each waiting for the other’s lock.
Neither can run until the other gives up its
lock, so they will sit there forever.
• there are design approaches that can help
avoid deadlock, including strategies for always
acquiring locks in a predetermined manner.
thread interaction – wait(), notify(), notifyAll()
• the Object class has three methods wait(), notify(), notifyAll() that help threads
communicate about the status of events that threads care about.
• using wait() and notify() lets one thread put itself into a “waiting room” until some
other thread notifies it that there is a reason to come back out.
• wait(), notify() and notifyAll() must be called from within a synchronized context.
A thread cannot invoke a wait or notify method on an object unless it owns that
object’s lock. We are calling wait() and notify() on this instance so we need to
synchronize in order to avoid an IllegalThreadStateException.
• there is a try – catch block around wait() method. A waiting thread can be
interrupted in the same way as a sleeping thread, so you have to take care of the
exception.
• if the thread calling wait() does not own the lock, it will throw an
IllegalMonitorStateException. This exception is not a checked exception so you
don’t have to catch it explicitly.
• there is a second form of wait() that accepts number of milliseconds as a
maximum time to wait. If the thread is not interrupted, it will continue normally
when it is notified or the specified time has elapsed.
synchronized(a){
a.wait(2000);
}
thread interaction – wait(), notify(), notifyAll()
• when the wait() method is invokes on an object the thread executing that
code gives up its lock on the object immediately. However when notify() is
called, that doesn’t mean the thread gives up its lock at that moment. If
the thread is still completing synchronized code, the lock is not released
until the thread moves out of the synchronized code. So just because
notify() is called doesn’t mean the lock becomes available at that moment.
• in most scenarios it is preferable to notify all of the threads that are waiting
on a particular object. If so you can use notifyAll() on the object to let all
the threads rush out of the waiting area and back to runnable. This is
especially important if you have several threads waiting on one object and
you want to be sure that the right thread gets notified.
• To prevent the scenario of thread executing notify() or notifyAll() before
another thread starts executing the wait() method i.e. the threads need to
check that the event they are waiting for has already happened. The best
way to solve this is to put some sort of a loop that checks on some sort of
conditional expressions, and only waits if the thing you are waiting for has
not yet happened.
example demonstrating notifyAll()
• class Reader extends Thread {
Calculator c;
public Reader(Calculator calc){
this.c = calc;
}
public void run(){
synchronized(c) {
try{
System.out.println(“waiting for calcualtion”);
c.wait();
}catch(InterruptedException e){ }
System.out.println(“Total is:” + c.total);
}
}
public static void main(String[] args) {
Calculator calculator = new Calculator();
new Reader(calculator).start();
new Reader(calculator).start();
new Reader(calculator).start();
calculator.start();
}
}
class Calculator extends Thread{
int total;
public void run() {
sybchronized (this) {
for(int i=0; i<100; i++){
total += i;
}
notifyAll();
}
}
}
thread interaction – wait(), notify(), notifyAll()
• Also a thread may wake up even though no code has called notify() or
notifyAll(). By putting wait method in a while loop and rechecking the
condition that represents what we are waiting for, we ensure that
whatever the reason we woke up, we will reenter() if and only if the
thing we are waiting for has not yet happened.
• the moral here is that when you use a wait(), notify(), notifyAll() you
should almost always have a while loop around wait() that checks a
condition and forces continued waiting until the condition is met.
• You should also make use of the required synchronization for the
wait() and notify() calls to also protect whatever data you are sharing
between threads.
• note: only run() method is defined in Runnable interface
• wait(), notify(), notifyAll() are defined in Object class
• sleep(), yield(), join(), setPriority(), start() are defined in Thread class.
Chapter 10 - Development
• options you can specify with the javac command

myproject
- source – MyClass.java
-classes - MyClass.class

• javac –source
• javac –classpath
the –d option lets you tell the compiler in which directory to put the .class files it
generates (d is for destination). The following command issued from the
myProject directory, compiles MyClass.java and puts MyClass.class file in the
classes directory. This assume that MyClass does not have a package statement.
cd myProject
javac –d classes source/MyClass.java
java command
myproject
- source - com – wickedlysmart – MyClass.java
-classes – com – wickedlysmart - MyClass.class

if you were in the source directory, you would compile MyClass.java and put
the resulting MyClass.class file into the classes/com/wickedlysmart directory
by invoking the below cmd
javac –d ../classes com/wickedlysmart/MyCLass.java

note: if the directories com and wickedlysmart are not present they will be
built. However if the classes directory is not present you will get a compiler
error.

• javac –help// this command brings a summary of valid options


using System properties
• java has a class called java.util.Properties that can be used to access a system’s persistent
information, such as the current version of the OS, the java compiler and the java virtual
machine. In addition to providing such default information, you can also add and retrieve
your own properties.
• import java.util.*;
public class TestProps{
public static void main(String args[]) {
Properties p = System.getProperties();
p.setProperty(“myProp”,”myValue”);
p.list(System.out);
}
}
you can compile it using
java –DcmdProp=cmdVal TestProps
Note: two name=value properties were added to system’s properties
myProp=myvalue and cmdProp=cmdVal
• the order of main’s modifiers can be altered a little, the String array doesn’t have to be
named args and as of java 5 it can be declared using var-args syntax
• static public void main(String[] args)
• public static void main(String . . .x)
• static public void main(String bang_a_gong[])
searching for other classes

• the java virtual machine will need to find the exactly


same supporting classes that the javac compiler
needed to find at compile time.
• the first place to look for is in the directories that
contain the classes that come standard with J2SE
• the second place they look for is in directories
defined by classpaths
• as soon as they find the class they are looking for
they stop searching for that class. In the case that
their search contains two or more files with the
same name, the first file found will be the file that is
used.
declaring classpath using command line option
• a classpath can be declared as a command line option with either java or javac.
• Classpaths declared as command line options override the classpaths declared as
an environment variable but they persist only for the length of the invocation.
• java –classpath /com/foo/acct:/com/foo
• the above command specifies two directories in which classes can be found namely
1)/com/foo/acct 2) /com/foo
• its important to remember that when you specify a subdirectory you are not
specifying the directories above it.
• for windows the directories are declared using backslashes and the separator is
semi colon
• a way to tell java or javac to search in the current directory is to add a dot (.) to the
classpath.
java –classpath /com/foo/acct:/com/foo:.
• when you are telling javac which java file to compile javac looks in the current
directory by default.
• Its important to remember that classpaths are searched from left to right.
• java allows you to abbreviate –classpath with -cp
relative and absolute paths
• (root) – dirA – dirB - dirC

• an absolute path in Unix begins with a forward slash(on windows it


will be something like c:\
• The leading slash indicates that the path is starting from the root
directory of the system.
• Because its starting from the root it doesn’t matter what the current
directory is. A directory’s absolute path is always the same.
• A relative path is the one that does not start with a slash e.g.
-cp dirB:dirB/dirC
both these paths are meaningful only if the current directory is dirA
if the current directory is root then none of the directories will be
searched.
if the current directory is dirB no directories will be searched.
JAR files
• test
- ws
- UseStuff.java
-myApp
- utils – Dates.class
- engine
rete.class
minmax.class
• jar stands for Java Archive.
• how to create a jar file
• cd ws
• jar –cvf MyJar.jar myApp
• the above command will create a jar file MyJar.jar and it will contain myApp
directory and all its entire subdirectory tree and files.
• to look at the contents of the jar file
• jar –tvf MyJar.jar
rules concerning the structure of jar files
• the jar command creates the META-INF
directory automatically
• the jar command creates the MANIFEST.MF
file automatically
• the jar command won’t place any of your files
in META-INF
• as you can see above the exact tree structure
is represented.
• java and javac will use the jar file like a normal
directory tree.
finding the jar file using classpath

• when you specify a path for a jar file you must


include the name of the Jar file at the end of
the path
• cd test
• javac –classpath ws/myapp.jar UseStuff.java
• remember when using a classpath the last
directory in the path must be the super-
directory of the root directory for the package.
• cd test
• javac –classpath ws UseStuff.java
important point for import statements
• when you use import statement you are declaring only
one package. When you say import java.util.* you are
saying use the short name for all of the classes in the
java.util package.
• Also you are not getting java.util.jar classes or
java.util.regex packages
• Those package are totally independent of each other. The
only thing they share is the same root directory but they
are not the same packages.
• As a corollary you can’t say import java.* in the hope of
importing multiple packages.
• just remember an import statement can import only one
package
using jre/lib/ext with jar files

• buried deep inside your java directory tree is a


subdirectory tree named jre/lib/ext
• if you put your JAR files into the ext
subdirectory java and javac can find them and
use the class files they contain.
• You don’t have to mention these
subdirectories in the classpath statement.
• searching this directory is a function that is
built rightinto java
static imports
• import statements save typing and make your code easier to read.
• in java 5 the import statement was enhanced to provide even
greater keystroke reduction capabilities.
• this new feature is known as static imports
• static imports can be used when you want to use the class’s static
members e.g.
• even though the feature is commonly called static import the
syntax must be import static followed by the fully qualified class
name of the static member you want to import or a wild card.
• watch out for ambiguously named static members e.g. if you do a
static import for both the integer class and the long class referring
to MAX_VALUE will cause a compiler error.
• You can do a static import on static object references,
constants(remember they are static and final) and static methods.
static imports
• public class TestStatic {
public static void main(String args[]){
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.toHexString(42));
}
}
• after static imports
import static java.lang.System.out;
import static java.lang.Integer.*;
public class TestStaticImport{
public static void main(String args[]){
out.println(MAX_VALUE);
out.println(toHexString(42));
}
}

You might also like