Chapter4_Notes java
Chapter4_Notes java
I/O programming
Java I/O (Input and Output) is used to process the input and produce the output.
In Java, Stream is a channel or a path along which data flows between source and destination.
In Java, 3 streams are created for us automatically. All these streams are attached with the
console.
1) System.out: standard output stream
2) System.in: standard input stream
3) System.err: standard error stream
There are two kinds of streams –
1. input stream: Input stream is a path through which data is read or fetched from a
source(file, memory, or a console).
2. output stream: While, output stream is a path which is used to write some data to a
destination(file, memory or a console).
Based on the type of data that we want to read, Java has two Stream classes –
1. Byte Stream Classes
2. Character Stream Classes
Byte Stream Classes
Byte Stream Classes are used to read bytes from an input stream and write bytes to an output
stream. Byte Stream Classes are in divided in two groups -
InputStream Classes - These classes are subclasses of an abstract class InputStream and
they are used to read bytes from a source (file, memory or console).
OutputStream Classes - These classes are subclasses of an abstract class, OutputStream
and they are used to write bytes to a destination (file, memory or console).
InputStream
InputStream class is a base class of all the classes that are used to read bytes from a file, memory or
console. InputStream is an abstract class and hence we can't create its object but we can use its
subclasses for reading bytes from the input stream.
OutputStream
OutputStream class is a base class of all the classes that are used to write bytes to a file, memory
or console. OutputStream is an abstract class and hence we can't create its object but we can use
its subclasses for writing bytes to the output stream.
FileInputStream(String path)
This constructor creates a FileInputStream to read a file which is accessed by
the path mentioned in the parameters of this constructor.
Example -
Both the examples of constructors have created a FileInputStream object to create an input
stream to read a file called TextBook.txt which is located in the D: drive.
Example:
import java.io.*;
class A
{
public static void main(String...ar)
{
try
{
FileInputStream fin= new FileInputStream("D:\\TextBook.txt");
int c;
catch(IOException e)
{
System.out.println(e);
}
}
}
Writing
FileOutputStream class is a subclass of OuputStream abstract class. FileOutputStream is used
create an output stream, which is used to write byte/bytes to a file.
Constructors:
1) FileOutputStream(File file)
This constructor creates a FileOutputStream object to write to a file specified by the File object,
which is passed to this constructor as a parameter.
Example:
2) FileOutputStream(String path)
This constructor creates a FileOutputStream to write to a file which is accessed by the path
mentioned in the parameters of this constructor.
Example:
Character Stream
Character Stream Classes are used to read characters from the source and write characters to
destination.
There are two kinds of Character Stream classes - Reader classes and Writer classes.
1. Reader Classes - These classes are subclasses of an abstract class, Reader and they are
used to read characters from a source (file, memory or console).
2. Writer Classes - These classes are subclasses of an abstract class, Writer and they used to
write characters to a destination (file, memory or console).
Reader
Reader class and its subclasses are used to read characters from source.
Reader class is a base class of all the classes that are used to read characters from a file, memory
or console. Reader is an abstract class and hence we can't instantiate it but we can use its
subclasses for reading characters from the input stream.
Methods Description
int read() This method reads a characters from the input stream.
This method reads a chunk of characters from the input stream and store them
int read(char[] ch)
in its char array, ch.
This method closes this output stream and also frees any system resources
close()
connected with it.
Writer
Writer class and its subclasses are used to write characters to a file, memory or console. Writer is
an abstract class and hence we can't create its object but we can use its subclasses for writing
characters to the output stream.
FileReader
FileReader class is a subclass of Reader abstract class and it is used to read a character/characters
from a local file.
import java.io.*;
class A
{
public static void main(String... ar)
{
try
{
File file= new File("D:\\TextBook.txt");
FileReader fr= new FileReader(file);
int c;
//Reading one character a time from a file until -1 is returned
while( (c=fr.read())!=-1)
{
System.out.print((char)c);
}
fr.close();
}
catch(IOException e)
{
System.out.println(e);
}
}
}
FileWriter
FileWriter class is a subclass of Writer abstract class and it is used to write a character, character
array or a String to a file.
import java.io.*;
class A
{
public static void main(String... ar)
{
char[] arr= {'H', 'e', 'l' , 'l' , 'o', '-'};
String str="How are you today?";
try
{
File file= new File("D:\\TextBook.txt");
FileWriter fw= new FileWriter(file); // This will
create the file and we don't need to call createNewFile();
}
catch(IOException e)
{
System.out.println(e);
}
}
}
Multithreading in java
Multi-Threaded Programming
Terminologies
Process: A program under execution is called as process.
Thread: A smallest component of a process that can be executed independently.
OR
A thread is an independent path of execution within a single program.
As shown in the above figure, a thread is executed inside the process. There can be multiple
processes inside the OS, and one process can have multiple threads.
Difference between Process and Thread
Process Thread
Program under execution is called as process Component or part of a program that can be
executed independently is called as thread
Each process has unique address space Threads shares same address space
Inter process communication is expensive and Inter thread communication is easier and
limited inexpensive
Processes are heavy weight Threads are light weight
Java cannot handle process based multi- Java can handle thread based multi-tasking
tasking
Multitasking
Multitasking is a process of executing multiple tasks simultaneously. We use multitasking to
utilize the CPU. Multitasking can be achieved in two ways:
1. Process-based Multitasking (Multiprocessing)
2. Thread-based Multitasking (Multithreading)
1) Process-based Multitasking (Multiprocessing)
Each process has an address in memory. In other words, each process allocates a separate
memory area.
A process is heavyweight.
Cost of communication between the process is high.
Switching from one process to another requires some time for saving and loading
registers, memory maps, updating lists, etc.
2) Thread-based Multitasking (Multithreading)
Threads share the same address space.
A thread is lightweight.
Cost of communication between the thread is low.
Multithreading in Java is a process of executing multiple threads simultaneously.
We use multithreading than multiprocessing because threads use a shared memory area. They
don't allocate separate memory area so saves memory, and context-switching between the
threads takes less time than process.
Life cycle of a Thread (Thread States)
There are five states a thread can possess in its life time, namely
1. New: Whenever a new thread is created, it is always in the new state or Thread is in new state,
when an instance (object) of thread class is created and before calling start( ) method.
2. Runnable: When a thread invokes the start() method, it moves from the new state to the
runnable state , but the thread scheduler has not selected it to be the running thread.
3. Running: The thread is in running state if the thread scheduler has scheduled it or when the
start method internally calls the run( ) method then it will move to running state.
4. Non-Runnable (Blocked): Whenever a thread is inactive for a span of time (not permanently)
then, either the thread is in the blocked state or is in the waiting state.
5. Terminated: A thread is in terminated or dead state when its run( ) method exits.
How to create Thread in Java
There are two ways to create threads in Java, namely
1. By extending Thread class
2. By implementing Runnable interface
1. Creating Thread by extending Thread class
Thread class provide constructors and methods to create and perform operations on a thread.
Thread Class
The Thread class contains following constructors and methods.
Constructors
Thread( )
Thread(String Name)
Thread(Runnable R)
Thread(Runnable R, String Name)
Methods:
S.N. Modifier Method Description
and Type
1 void start() It is used to start the execution of the thread.
2 void run() It is used to do an action for a thread.
3 static void sleep(long It sleeps a thread for the specified amount of time.
milliSecs)
4 static currentThread() It returns a reference to the currently executing thread
Thread object.
5 void join() It waits for a thread to die.
6 int getPriority() It returns the priority of the thread.
7 void setPriority() It changes the priority of the thread.
8 String getName() It returns the name of the thread.
9 void setName() It changes the name of the thread.
10 long getId() It returns the id of the thread.
11 boolean isAlive() It tests if the thread is alive.
12 static void yield() It causes the currently executing thread object to pause
and allow other threads to execute temporarily.
13 void suspend() It is used to suspend the thread.
14 void resume() It is used to resume the suspended thread.
15 void stop() It is used to stop the thread.
16 void interrupt() It interrupts the thread.
17 void notify() It is used to give the notification for only one thread
which is waiting for a particular object.
18 void notifyAll() It is used to give the notification to all waiting threads
of a particular object.
System.out.println("Thread is running......");
}
public static void main(String args[])
{
MyThread m=new MyThread();
MyThread m1=new MyThread();
m.start();
m1.start();
}
}
Below program demonstrates various method of Thread class.
class ThrExample extends Thread
{
ThrExample(String thName)
{
super(thName);
}
public void run()
{
System.out.println("---- New Thread ----");
System.out.println("Current Thread : " + getName());
System.out.println("Thread Priority: "+getPriority());
System.out.println("Thread Status : " +isAlive());
System.out.println("Thread Id : " +getId());
}
}
public class ThreadDemo
{
public static void main(String [] args)
{
ThrExample t1 = new ThrExample("ONE");
ThrExample t2 = new ThrExample("TWO");
System.out.println("Current Thread : "
+Thread.currentThread());
t1.start();
t2.start();
}
}
Output:
Current Thread: Thread[main,5,main]
---- New Thread ----
Current Thread: TWO
Thread Priority: 5
Thread Status: true
Thread Id: 9
---- New Thread ----
Thread Priority
Each thread has a priority. Priorities are represented by a number between 1 and 10. In most
cases, the thread scheduler schedules the threads according to their priority (known as
preemptive scheduling).
Methods Associated with Thread Priorities
public final int getPriority(): This method returns the priority of the given thread.
public final void setPriority(int newPriority): This method updates or assign the priority
of the thread to newPriority. The method throws IllegalArgumentException if the value
newPriority goes out of the range, which is 1 (minimum) to 10 (maximum).
Thread class contains 3 constants
1. public static int MIN_PRIORITY
2. public static int NORM_PRIORITY
3. public static int MAX_PRIORITY
Default priority of a thread is 5 (NORM_PRIORITY). The value of MIN_PRIORITY is 1 and
the value of MAX_PRIORITY is 10.
Example:
class A extends Thread
{
public void run()
{
for(int i=1;i<=5;i++)
{
System.out.println("i="+i);
}
}
}
class B extends Thread
{
public void run()
{
for(int j=1;j<=5;j++)
{
System.out.println("j="+j);
}
}
}
class C extends Thread
{
public void run()
{
for(int k=1;k<=5;k++)
{
System.out.println("k="+k);
}
}
}
class ThreadPrior
{
public static void main(String arg[])
{
A a=new A();
B b=new B();
C c=new C();
a.setPriority(9);//(Thread.MAX_PRIORITY);
b.setPriority(2);//(Thread.MIN_PRIORITY);
c.setPriority(4);//(Thread.NORM_PRIORITY);
a.start();
b.start();
c.start();
//System.out.println("End of main");
}
}
Thread Exception
Exception involving with the concept of multithreading are
IllegalArgumentException is thrown when the parametric value is negative
InterruptedException is thrown if any thread has interrupted the current thread.
IllegalThreadStateException: This exception is thrown whenever we attempt to invoke a
method that a thread cannot handle in the given state
class MyThread extends Thread
{
public void run()
{
try
{
for(int i=0;i<=5;i++)
{
Thread.sleep(500);
System.out.println("Thread is running......"+i);
}
}
catch(InterruptedException e)
{
System.out.println(e.getMessage());
}
}
public static void main(String args[])
{
MyThread m=new MyThread();
MyThread m1=new MyThread();
m.start();
m1.start();
}
}
Prototype:
public final void notifyAll( )
Synchronization
When two or more threads needs to access shared data, then data inconsistency problem arises.
Imagine a scenario,
Thread T1 is writing data into a file numbers.txt.
Thread T2 is reading data from a file numbers.txt.
In this scenario, when T1 is writing, if T2 reads the file concurrently, data may not be correct. Hence,
when one thread is using shared resource, other threads should not be allowed to use until first thread
completes the task.
In Java, synchronization is achieved using monitor or lock.
Each object has unique lock associated with them.
A thread that needs to access shared resource, first acquires the lock, as soon as completes the
execution, thread automatically releases the lock.
To synchronize the method, prefix the keyword synchronized in method definition
Synchronized Methods
/* ThreadSyncOne.java (Without Synchronization)*/
class Table
{
void printTable(int n)
{//method not synchronized
for(int i=1;i<=5;i++)
{
System.out.println(n*i);
try{
Thread.sleep(400);
}catch(Exception e){System.out.println(e);}
}
}
}
}
class MyThread2 extends Thread
{
Table t;
MyThread2(Table t)
{
this.t=t;
}
public void run()
{
t.printTable(100);
}
}
class ThreadSyncOne {
public static void main(String args[])
{
Table obj = new Table();//only one object
MyThread1 t1=new MyThread1(obj);
MyThread2 t2=new MyThread2(obj);
t1.start();
t2.start();
}
}
}
}
}
class MyThread2 extends Thread
{
Table t;
MyThread2(Table t)
{
this.t=t;
}
public void run()
{
t.printTable(100);
}
}
class ThreadSyncOne {
public static void main(String args[])
{
Table obj = new Table();//only one object
MyThread1 t1=new MyThread1(obj);
MyThread2 t2=new MyThread2(obj);
t1.start();
t2.start();
}
}
Collections in Java
Collection object or a container object is an object which can store a group of other objects.
OR
Collection represents a single unit of objects i.e. a group.
Collection framework Represents a unified architecture for storing and manipulating
group of objects. It has: All collections frameworks contain the following:
Interfaces: Like List, Set, Queue and Maps. These are abstract data types that represent
collections. Interfaces allow collections to be manipulated independently of the details of
their representation.
Implementations, i.e., Classes: ArrayList, LinkedList, TreeSet, HashSet, HashMap etc.
These are the concrete implementations of the collection interfaces. They are reusable
data structures.
interface Collection<E>
Methods Description
Object get( int index ) Returns object stored at the specified index
int indexOf( Object obj ) Returns index of first occurrence of obj in the collection
int lastIndexOf( Object obj ) Returns index of last occurrence of obj in the collection
Class Description
ArrayList class:
Simple arrays have fixed size i.e it can store fixed number of elements. But, sometimes you may
not know beforehand about the number of elements that you are going to store in your array.
In such situations, we can use an ArrayList, which is an array whose size can increase or
decrease dynamically.
ArrayList class extends AbstractList class and implements the List interface.
ArrayList supports dynamic array that can grow as needed.
ArrayList has three constructors
1. ArrayList() //It creates an empty ArrayList
2. ArrayList( Collection C ) //It creates an ArrayList that is
3. ArrayList( int capacity ) //It creates an ArrayList that has the specified initial capacity
ArrayLists are created with an initial size. When this size is exceeded, the size of the
ArrayList increases automatically.
It can contain Duplicate elements and it also maintains the insertion order.
Manipulation is slow because a lot of shifting needs to be occurred if any element is
removed from the array list.
ArrayList allows random access because it works on the index basis
Example:
import java.util.*
class Test
{
public static void main(String[] args)
{
ArrayList< String> al = new ArrayList< String>();
al.add("ab");
al.add("bc");
al.add("cd"); system.out.println(al);
}
}
Output :
[ab,bc,cd]
LinkedList class
LinkedList class extends AbstractSequentialList and implements List,Deque
and Queue inteface.
LinkedList has two constructors.
LinkedList() //It creates an empty LinkedList
LinkedList( Collection C ) //It creates a LinkedList that is initialized with elements of
the Collection c
It can be used as List, stack or Queue as it implements all the related interfaces.
They are dynamic in nature i.e it allocates memory when required. Therefore insertion
and deletion operations can be easily implemented.
It can contain duplicate elements and it is not synchronized.
Reverse Traversing is difficult in linked list.
In LinkedList, manipulation is fast because no shifting needs to be occurred
Example:
public class LinkedListPgm
{
public static void main(String[] args)
Both the classes are used to store the elements in the list, but the major difference
between both the classes is that ArrayList allows random access to the elements in the list
as it operates on an index-based data structure.
On the other hand, the LinkedList does not allow random access as it does not have
indexes to access elements directly, it has to traverse the list to retrieve or access an
element from the list.
ArrayList extends AbstarctList class whereas LinkedList extends AbstractSequentialList.
AbstractList implements List interface, thus it can behave as a list only whereas
LinkedList implements List, Deque and Queue interface, thus it can behave as a Queue
and List both.
In a list, access to elements is faster in ArrayList as random access is also possible.
Access to LinkedList elements is slower as it follows sequential access only.
In a list, manipulation of elements is slower in ArrayList whereas it is faster in
LinkedList.
Accessing elements from collection via an iterator
In Java, Iterator is an interface available in Collection framework in java.util package. It is a Java
Cursor used to iterate a collection of objects.
It is used to traverse a collection object elements one by one.
It is available since Java 1.2 Collection Framework.
It is applicable for all Collection classes. So it is also known as Universal Java Cursor.
It supports both READ and REMOVE Operations.
Methods::
boolean hasNext(): Returns true if the iteration has more elements.
E next(): Returns the next element in the iteration.
default void remove(): Removes from the underlying collection the last element returned
by this iterator.
Java ListIterator Interface
ListIterator Interface is used to traverse the element in backward and forward direction.
Example::
import java.util.*;
public class TestCollection8{
public static void main(String args[]){
ArrayList<String> al=new ArrayList<String>();
al.add("Amit");
al.add("Vijay");
al.add("Kumar");
al.add(1,"Sachin");
System.out.println("element at 2nd position: "+al.get(2));
ListIterator<String> itr=al.listIterator();
System.out.println("traversing elements in forward direction...");
while(itr.hasNext()){
System.out.println(itr.next());
}
System.out.println("traversing elements in backward direction...");
while(itr.hasPrevious()){
System.out.println(itr.previous());
}
}
}
JavaBeans:
JavaBeans is a portable, platform-independent model written in Java Programming Language. Its
components are referred to as beans.
In simple terms, JavaBeans are classes which encapsulate several objects into a single object. It
helps in accessing these object from multiple places. JavaBeans contains several elements like
Constructors, Getter/Setter Methods and much more.
JavaBeans has several conventions that should be followed:
Beans should have a default constructor (no arguments)
Beans should provide getter and setter methods
A getter method is used to read the value of a readable property
To update the value, a setter method should be called
Beans should implement java.io.serializable, as it allows to save, store and restore the
state of a JavaBean you are working on
Example:
public class Employee implements java.io.Serializable
{
private int id;
private String name;
public Employee()
{
}
public void setId(int id)
{
this.id = id;
}
public int getId()
{
return id;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
public class Employee1 {
public static void main(String args[])
{
Employee s = new Employee();
s.setName(“ABC");
System.out.println(s.getName());
}
}