1.02k likes | 1.03k Views
Learn how to handle exceptions in Java programming, including try-catch blocks, multiple catch blocks, finally blocks, throwing exceptions, exception hierarchy, checked vs unchecked exceptions, and the throws clause.
E N D
MT311 (Oct 2006)Java Application Development Exceptions Handling, Streamed I/O, Multithreading and Network Programming Tutorial 3
Tutor Information • Edmund Chiu (Group 1) • Email: gianted@netvigator.com ORt439934@ouhk.edu.hk • Please begin your email subject with [MT311] • Webpage: http://geocities.yahoo.com/gianted
PART IExceptions Handling Exception Try, catch and finally Throw statement and Throws clause
Exceptions Handling • Exceptional handling is a systematic way to separate the normal flow of a program from special handlers of abnormal conditions. • Main program handles key computing logics • When an error occurs, the control is transferred to error handler • Exceptions are an integral part of Java programming • Exceptions may be generated at runtime (e.g. divide by zero error) • Many methods also throw exceptions, especially those deal with I/O and networks
Try-Catch Blocks • The basic exception handling technique: • Enclose the code that may generate an exception with a try-block • Handle the exception(s) that you want to deal with in a catch-block try { <statements with possible errors> } catch (<ExceptionType> <exceptionVar>) { <action statements> }
Flow Control in Try-Catch Blocks • When the program executes and a statement in the try block causes an error, the control will be transferred to catch blocks • The error in try block will be matched with the exception type in the parentheses in the catch block • When the exception is matched, the corresponding handler will be executed • After the exception handler finishes its work, the control will be passed to the point immediate after the catch blocks • If no match is made, the program halts and give out error
Multiple Catch-Block • A try block can be followed by more than one catch-blocks • the exception will be checked against in sequence • whenever a match is made, the handler code is executed, the control will be passed to the point immediate after the catch blocks • In general, we place the blocks from specific exceptions to more general ones, example: try { // some errors occur here } catch (FileNotFoundException e) { // coding here } catch (IOException e) { // do something here} catch (Exception e) { // do other things here } finally { // always run these codes }
Finally Block • After handling the exception, the control will not be back to the point of original exception • This may case resource leaks, e.g. opened file handler not closed • Finally block is used to handle the situation • optional block, must appear if no catch block is defined for a try block • no matter which or none of the exception handler has been executed (even if the try block is exited through return, exit or etc.), the control will be passed to finally block
Create an Exception • Normally, exceptions are generated when the system detects errors, but you can also throw an exception by using throw. Example: throw new RuntimeException(“This is my own fault”); • The throw statement can be used in everywhere • One of the use of throwing a new exception is throwing a user-defined exception • The other use of the throw keyword is throwing an exception in the catch block. We call it re-throw of an exception. Example:catch (IOException e) { // do something throw e; } Re-throwing exception is used when there may be further error handling code needed in the following catch blocks.
Exceptions Hierarchy • Exception classes can be inherited like ordinary classes, examples: • NumberFormatException extends RuntimeException • FileNotFoundException extends IOException • Likewise, each exception class has their constructors • The user-defined exception can extend an appropriate Java exception • When an exception superclass is caught, all its subclasses will also be caught
Checked vs. Unchecked Exceptions • Exceptions in Java can be checked or unchecked • Checked exceptions must be caught in your application (e.g., all IO exceptions, SQL exceptions) • Unchecked exceptions include runtime numeric exceptions like illegal number of arguments, array index out of bound, null pointer exceptions and etc. • A class cannot be compiled if a method throws a checked exception but not caught
Throws Clause • Throws clause can be used in a method to propagate the uncaught checked exceptions to the caller • Example: void myMethod throws Exception1, Exception2 { … } • The thrown exception should be caught in the method or class using this method; otherwise, the program cannot be compiled
Pros and Cons of Exception Handling • Advantages • Separate the exceptional conditions from the normal flow of the program, allow you to construct a cleaner program • One single handler can handle the same type of errors thrown out from different points in the program • Ensure no error is ignored intentionally or unintentionally. Checked exception has to be handled and cannot be overlooked. • Disadvantages • Exceptions propagated multiple levels become hard to trace • Code with excessive error handling may not be optimized effectively.
Part IIStreamed I/O InputStream /OutputStream, Reader/Writer
What is a Stream • Most of Java’s IO interactions are implemented using streams. • A buffer that reads/writes sequentially • InputStreams are used for read-only operations • OutputStreams are used for write-only purposes • No read-write streams is available in Java • However, there are some other read/write implementation that supports read and write using the same object (e.g. RandomAccessFile) • Java streams will be blocked if • There are no data in an inputstream • The buffer in an outputstream is full
Available methods in InputStream read() reads a single byte from the stream. –1 was read if the stream has reached the end read(byte[]) reads data into an array of bytes available() returns the number of bytes can be read close() closes the stream Available methods in OutputStream write() writes a single byte to the stream write(byte[]) writes the entire byte array to the stream write(byte[], int, int) writes a portion of a byte array, from a specific position, read n bytes. flush() forces all bytes in buffer to the stream close() closes the stream InputStream and OutputStream
FileInputStream and FileOutputStream • Instead of using InputStream and OutputStream, we usually use FileInputStream and FileOutputStream • FileInputStream and FileOutputStream can open a file in an easy way: FileInputStream in = new FileInputStream(filename); FileOutputStream out = new FileOutputStream(filename); • File copying can be easily implemented by reading a byte then writing it out immediately byte b = in.read(); out.write(b);
import java.io.*; public class FileCopy { public static void main(String[] args) { if (args.length != 2) { throw (new IllegalArgumentException( "Usage: FileCopy <src><destination>")); } FileInputStream in = null; FileOutputStream out = null; try {// open the files in = new FileInputStream(args[0]); out = new FileOutputStream(args[1]); while (in.available() > 0) {out.write(in.read());} }catch (IOException e) { System.out.println(e); }finally {// close the files try { if (out != null) out.close(); if (in != null) in.close(); }catch (IOException e) {System.out.println(e);} } } }
Readers and Writers for Character Handling • Byte stream and characters are alike • Byte steams operate on bytes • Character streams operate on characters (multilingual) • The file copying program can be implemented using FileReader and FileWriter easily • The only difference from the previous example is the variables in and out is now the FileReader and FileWriter
Data Streams • Byte streams and character streams deals with one single type of data (bytes/characters) • Java can also handle primitive data types (and even Strings) such as int and double using DataInputStream and DataOutputStream • The marshalling and unmarshalling between bytes and primitive data types are hidden behind the two classes • Sample methods • readInt, readDouble, readChar, readUTF(for String) and etc.
Object Serialization • Java can also handle read/write an Object from/to a stream through ObjectInputStream and ObjectOutputStream using readObject and writeObject • However, not all object types can be read/written in a stream • Example, we can’t write a Stream into another stream • We call an object that can be read from/written to a stream serializable • Normally, a serializable object contains viewable data only • All variables in a serializable object are either serializable or of primitive data types • Object serialization is useful to save and write an entire object.
Sources and Streams • You can create different types of streams from the same source • You can create a byte stream on a file and also another character stream on the same file at the same time • You can also connected a stream to different sources, for example, a file or a network connection
Chaining Streams • For example, • FileReader provides an easy way to read characters • BufferedReader provides a readLine method to read lines • We can simply chain up the FileReader and BufferedReader so that we can read lines from a file BufferedReader input = new BufferedReader(new FileReader(filename)); • We can chain up readers/writers and streams in a very flexible way LineNumberReader lineReader = new LineNumberReader(new BufferedReader( new FileReader(filename)));
import java.io.*; public class LineNumber { public static void main(String[] args) { if (args.length != 1) throw (new IllegalArgumentException( "LineNumber: LineNumber <file>")); LineNumberReader lnReader = null; String line; try {// create a LineNumberReader from the file lnReader = new LineNumberReader( new BufferedReader(new FileReader(args[0]))); while ((line = lnReader.readLine()) != null) { System.out.println(" " + lnReader.getLineNumber() + ": " + line); } } catch (IOException e) { System.out.println("File error: " + e); } finally { try { if (lnReader!= null) lnReader.close(); } catch (IOException e) { System.out.println("File close error."); } } } }
Part THREEMultithreading Multithreading Synchronization Wait & Notify
Concept of Multithreading • Multithreading is the capability for programmers to let different parts of the program execute at the same time • In a typical application, there is usually more than one thread working • Example: Web browser • Load the HTML text • Load the embedded image • a thread listening user input (mouse and/or keyboard) • etc…
Java Threads • In Java, a thread is a point of process which has its own run-time resources support • A thread executes its instructions line-by-line • Concurrency occurs when multiple threads run together • Static method main defines the main thread of the execution • A thread is created by: • a class extending the thread class • a class implements the runnable interface
Class Thread • Class Thread is from the package java.lang • Constructor Thread(String threadName) will create a thread with the name “threadName” • Constructor Thread( ) will create a thread with the name “Thread-##” where ## is a number • A user-defined thread should extend Java’s thread class • public class MyThread extends Thread { … } • The instruction that a thread is to be accomplished is placed inside the method run, which you need to override in your own thread class
Start Running a Thread • Though the main body of a thread is the run method, you will never call it directly • To start the execution of a thread, we need to call the start method • A thread of your class is created first • Call start method to makes the method ready to runExample: new MyThread().start( ) • start method returns immediately – it will not wait till the end of the thread execution – the caller and the thread is executing concurrently • start method can only be called once, repeated call incurs IllegalThreadStateException
Simple Thread Example public class SimpleThread1 extends Thread { private String str; public SimpleThread1 (String str) {this.str = str;} public void run() { for (int i = 0; i < 5; i++) { System.out.println(i + " " + str); try {// sleep for a random interval Thread.sleep((long)(Math.random() * 500)); } catch (InterruptedException e) {} } System.out.println("God is my " + str); } public static void main(String[] args) { new SimpleThread1 ("Strength").start(); new SimpleThread1 ("Shield").start(); new SimpleThread1 ("Rock").start(); } }
Runnable Interface • As Java has no multiple inheritances, we cannot extend Thread if it has already extended other class • However, we can implements multiple interfaces • Thus, Java provides another way to implement threads – through Runnable interface • In a Runnable interface, • You need to override the run method which contains the instruction for the thread • You need to construct a thread using a runnable object Runnable a = new SimpleRunnable(); Thread t = new Thread(a); t.start();
Simple Runnable Example public class SimpleRunnable1 implements Runnable { private String str; public SimpleRunnable1(String str) {this.str = str;} public void run() { for (int i = 0; i < 5; i++) { System.out.println(i + " " + str); try {// sleep for a random interval Thread.sleep((long)(Math.random() * 500)); } catch (InterruptedException e) {} } System.out.println("God is my " + str); } public static void main(String[] args) { new Thread(new SimpleRunnable1("Strength")).start(); new Thread(new SimpleRunnable1("Shield")).start(); new Thread(new SimpleRunnable1("Rock")).start(); } }
Concurrency and Sleep • Within a thread, the instructions are executed sequentially • While multiple threads are running together, they may interleave. • You may notice that the result of the previous examples may be different each time • This may be also due to the threads “sleep” for a random period in the loops Thread.sleep((long) (Math.random() * 500)); • When a thread sleeps, other threads can still proceed • Only the current thread can be told to sleep, so it is a static method
Thread Interleaving example • If we change the run method in the previous example: public void run() { for (int i = 0; i < 10000; i++) { if (i % 100 == 0) System.out.println(str + " " + i); } System.out.println("God is my " + str); } We can see the interleaving effect of the threads is independent of the sleep method
Importance of Synchronization • In multithreading, a variable may be accessed by more than one thread simultaneously • no problem if read access only • problem occurs when modification is involved • Thread 1 reads A = 5 • Thread 2 reads A = 5 • Thread 1 increases the variable by 1, A = 6 • Thread 2 increases the variable by 1, A = 6 • Instead of increasing the variable every time when a thread is called, the second thread just updated the old version of the variable • To make an object thread safe, you need to synchronize all data that is shared by different threads
Synchronized Methods • Java provides the keyword synchronized to lock up an object so that only one thread can access that object when the method is called • Example: public synchronized void set (int data) • synchronized method enforces the exclusive access to the respective object • the thread unable to access the object will go to the “blocked” state • Synchronized keyword can also apply to lock up a specific variable within a block of codes • Example: sychronized(counter) { counter.inc(); }
Deadlock and Notification • Deadlock may occur when the threads are sharing more than one synchronized objects • Example: Thread1 has taken object A and is now waiting for object B, but Thread2 has taken object B and is now waiting for object A. Deadlock occurs. • In Java, we avoid the case by using thread notification • The thread who cannot get all synchronized objects will go into waiting status, which will temporarily release its exclusive access to the object • When the thread finishes its work on a synchronized object, it will notify other threads so that they can try to reacquire the access to the object
Wait and Notify • Both methods are instance methods of any object • When wait is called, the thread will be blocked and added into the object’s waiting list • wait gives up the lock of the object • it should be called within synchronized method, otherwise, an IllegalMonitorStateException may occur • InterruptedException may occur while the thread is waiting • Once the notify method of the object is called, one of the threads on the list will be chosen to return to the ready state again
Notify and NotifyAll • When notify method is used, only one thread of consumer can be brought to ready state • JVM implementation determines which thread to be brought • If you want to notify more than one thread that are waiting, you need to use notifyAll method on the object • all threads return to ready state and compete for the lock
Example of Thread-Safe Data Store class DataStore { private int data; private boolean ready = false; public synchronized int get() { while (! ready) { wait();// no data, wait for it } ready = false; // data ready, we consume it notifyAll();// data consumed, notify all waiting producers return data; } public synchronized void put(int v) { while (ready) { wait(); // data not consumed yet, wait } data = v; ready = true; notifyAll();// data ready, notifying all waiting consumers } }
Part IVNetwork Basic IP, DNS, TCP and UDP
IP Packet and IP • Packets are basic unit of delivery • Packet header stores the source and destination of the unit (like a letter envelop front) • Packet data is the content • IP address is used to identify a computer in the network • consists of 4 integers in the range of 0 to 255, separated by 3 dots. Example: OUHK homepage: 202.40.157.186 • 127.0.0.1 is the loop-back address to test your network application
Different types of IP address • Five classes of IP address • Class A: 0.0.0.0 – 127.255.255.255 (Leftmost bits: 0xxx) • Class B: 128.0.0.0 – 191.255.255.255 (Leftmost bits: 10xx) • Class C: 192.0.0.0 – 223.255.255.255 (Leftmost bits: 110x) • Class D: 224.0.0.0 – 239.255.255.255 (Leftmost bits: 1110) • Class E: 240.0.0.0 – 255.255.255.255 (Leftmost bits: 1111) • Private addresses range • Class A: 10.0.0.0 – 10.255.255.255 • Class B: 172.16.0.0 – 172.31.255.255 • Class C: 192.168.0.0 – 192.168.255.255
Network Address, Node Address and Subnet Mask • Each IP address is made up of two parts. • Leading part (network part) identifies a particular network • Trailing part (node/host part) determines a specific node of the network. • The network address and node address can be determine by subnet mask • Suppose the IP is 10.0.0.11 and the subnet mask is 255.255.255.252 • By bit-wise conjunction of 252 (1111 1100) with 11 (0000 1011), we obtain the last digit for the network address: 8 (0000 1000) (10.0.0.8)
IP Ports • Network ports are used to specify the service request on the host • different services (e.g. FTP and WWW) have their own port number logical entities numbered from 0 to 65535 • 0 to 1023 are reserved for common system services. E.g., FTP – port 21, WWW – port 80 • Combination of host name (or IP address) and port number can uniquely specify the host and server you want to talk to.
Uniform Resource Locators (URLs) • URL are the pointers to the resources on the WWW • A URL consists of:<protocol>://<hostname>:<port_no>/ <resources_location> • protocol: the protocol to be used to get the resources, the most common ones are http and ftp • hostname: the host which holds the resources • port number: if omitted, default number is used • resource location: resource may be a file, a directory or even a query to database • Example: http://plbpc001.ouhk.edu.hk/~mt311