Wednesday, 15 February 2012

Interface List for selenium automation learning


The List Interface

A List is an ordered Collection (sometimes called a sequence). Lists may contain duplicate elements. In addition to the operations inherited from Collection, the Listinterface includes operations for the following:
  • Positional access — manipulates elements based on their numerical position in the list
  • Search — searches for a specified object in the list and returns its numerical position
  • Iteration — extends Iterator semantics to take advantage of the list's sequential nature
  • Range-view — performs arbitrary range operations on the list.
The List interface follows.
public interface List extends Collection {
// Positional access
E get(int index);
// optional
E set(int index, E element);
// optional
boolean add(E element);
// optional
void add(int index, E element);
// optional
E remove(int index);
// optional
boolean addAll(int index,
Collection c);

// Search
int indexOf(Object o);
int lastIndexOf(Object o);

// Iteration
ListIterator listIterator();
ListIterator listIterator(int index);

// Range-view
List subList(int from, int to);
}
The Java platform contains two general-purpose List implementations. ArrayList, which is usually the better-performing implementation, and LinkedList which offers better performance under certain circumstances. Also, Vector has been retrofitted to implement List.

Comparison to Vector

If you've used Vector, you're already familiar with the general basics of List. (Of course, List is an interface, while Vector is a concrete implementation.) List fixes several minor API deficiencies in Vector. Commonly used Vector operations, such as elementAt and setElementAt, have been given much shorter names. When you consider that these two operations are the List analog of square brackets for arrays, it becomes apparent that shorter names are highly desirable. Consider the following assignment statement.
a[i] = a[j].times(a[k]);
The Vector equivalent is:
v.setElementAt(v.elementAt(j).times(v.elementAt(k)), i);
The List equivalent is:
v.set(i, v.get(j).times(v.get(k)));
You may already have noticed that the set method, which replaces the Vector method setElementAt, reverses the order of the arguments so that they match the corresponding array operation. Consider the following assignment statement.
gift[5] = "golden rings";
The Vector equivalent is:
gift.setElementAt("golden rings", 5);
The List equivalent is:
gift.set(5, "golden rings");
For consistency's sake, the method add(int, E), which replaces insertElementAt(Object, int), also reverses the order of the arguments.
The three range operations in Vector (indexOf, lastIndexOf, and setSize) have been replaced by a single range-view operation (subList), which is far more powerful and consistent.

Collection Operations

The operations inherited from Collection all do about what you'd expect them to do, assuming you're already familiar with them. If you're not familiar with them fromCollection, now would be a good time to read The Collection Interface section. The remove operation always removes the first occurrence of the specified element from the list. The add and addAll operations always append the new element(s) to the end of the list. Thus, the following idiom concatenates one list to another.
list1.addAll(list2);
Here's a nondestructive form of this idiom, which produces a third List consisting of the second list appended to the first.
List list3 = new ArrayList(list1);
list3.addAll(list2);
Note that the idiom, in its nondestructive form, takes advantage of ArrayList's standard conversion constructor.
Like the Set interface, List strengthens the requirements on the equals and hashCode methods so that two List objects can be compared for logical equality without regard to their implementation classes. Two List objects are equal if they contain the same elements in the same order.

Positional Access and Search Operations

The basic positional access operations (get, set, add and remove) behave just like their longer-named counterparts in Vector (elementAt, setElementAt,insertElementAt, and removeElementAt) with one noteworthy exception: The set and remove operations return the old value that is being overwritten or removed; theVector counterparts (setElementAt and removeElementAt) return nothing (void). The search operations indexOf and lastIndexOf behave exactly like the identically named operations in Vector.
The addAll operation inserts all the elements of the specified Collection starting at the specified position. The elements are inserted in the order they are returned by the specified Collection's iterator. This call is the positional access analog of Collection's addAll operation.
Here's a little method to swap two indexed values in a List. It should look familiar from Programming 101.
public static  void swap(List a, int i, int j) {
E tmp = a.get(i);
a.set(i, a.get(j));
a.set(j, tmp);
}
Of course, there's one big difference. This is a polymorphic algorithm: It swaps two elements in any List, regardless of its implementation type. Here's another polymorphic algorithm that uses the preceding swap method.
public static void shuffle(List list, Random rnd) {
for (int i = list.size(); i > 1;
i--)
swap(list, i - 1,
rnd.nextInt(i));
}
This algorithm, which is included in the Java platform's Collections class, randomly permutes the specified list using the specified source of randomness. It's a bit subtle: It runs up the list from the bottom, repeatedly swapping a randomly selected element into the current position. Unlike most naive attempts at shuffling, it's fair (all permutations occur with equal likelihood, assuming an unbiased source of randomness) and fast (requiring exactly list.size()-1 swaps). The following program uses this algorithm to print the words in its argument list in random order.
import java.util.*;

public class Shuffle {
public static void main(String[] args) {
List list
= new ArrayList();
for (String a : args)
list.add(a);
Collections.shuffle(list,
new Random());
System.out.println(list);
}
}
In fact, this program can be made even shorter and faster. The Arrays class has a static factory method called asList, which allows an array to be viewed as a List. This method does not copy the array. Changes in the List write through to the array and vice versa. The resulting List is not a general-purpose List implementation, because it doesn't implement the (optional) add and remove operations: Arrays are not resizable. Taking advantage of Arrays.asList and calling the library version of shuffle, which uses a default source of randomness, you get the following tiny program whose behavior is identical to the previous program.
import java.util.*;

public class Shuffle {
public static void main(String[] args) {
List list = Arrays.asList(args);
Collections.shuffle(list);
System.out.println(list);
}
}

Iterators

As you'd expect, the Iterator returned by List's iterator operation returns the elements of the list in proper sequence. List also provides a richer iterator, called aListIterator, which allows you to traverse the list in either direction, modify the list during iteration, and obtain the current position of the iterator. The ListIteratorinterface follows.
public interface ListIterator extends Iterator {
boolean hasNext();
E next();
boolean hasPrevious();
E previous();
int nextIndex();
int previousIndex();
void remove(); //optional
void set(E e); //optional
void add(E e); //optional
}
The three methods that ListIterator inherits from Iterator (hasNext, next, and remove) do exactly the same thing in both interfaces. The hasPrevious and theprevious operations are exact analogues of hasNext and next. The former operations refer to the element before the (implicit) cursor, whereas the latter refer to the element after the cursor. The previous operation moves the cursor backward, whereas next moves it forward.
Here's the standard idiom for iterating backward through a list.
for (ListIterator it = list.listIterator(list.size());
it.hasPrevious(); ) {
Type t = it.previous();
...
}
Note the argument to listIterator in the preceding idiom. The List interface has two forms of the listIterator method. The form with no arguments returns aListIterator positioned at the beginning of the list; the form with an int argument returns a ListIterator positioned at the specified index. The index refers to the element that would be returned by an initial call to next. An initial call to previous would return the element whose index was index-1. In a list of length n, there are n+1 valid values for index, from 0 to n, inclusive.
Intuitively speaking, the cursor is always between two elements — the one that would be returned by a call to previous and the one that would be returned by a call to next. The n+1 valid index values correspond to the n+1 gaps between elements, from the gap before the first element to the gap after the last one. The following figure shows the five possible cursor positions in a list containing four elements.
Five arrows representing five cursor positions, from 0 to 4, with four elements, one between each arrow.
The five possible cursor positions.
Calls to next and previous can be intermixed, but you have to be a bit careful. The first call to previous returns the same element as the last call to next. Similarly, the first call to next after a sequence of calls to previous returns the same element as the last call to previous.
It should come as no surprise that the nextIndex method returns the index of the element that would be returned by a subsequent call to next, and previousIndex returns the index of the element that would be returned by a subsequent call to previous. These calls are typically used either to report the position where something was found or to record the position of the ListIterator so that another ListIterator with identical position can be created.
It should also come as no surprise that the number returned by nextIndex is always one greater than the number returned by previousIndex. This implies the behavior of the two boundary cases: (1) a call to previousIndex when the cursor is before the initial element returns -1 and (2) a call to nextIndex when the cursor is after the final element returns list.size(). To make all this concrete, the following is a possible implementation of List.indexOf.
public int indexOf(E e) {
for (ListIterator it =
listIterator(); it.hasNext(); )
if (e == null ? it.next() ==
null : e.equals(it.next()))
return it.previousIndex();
// Element not found
return -1;
}
Note that the indexOf method returns it.previousIndex() even though it is traversing the list in the forward direction. The reason is that it.nextIndex() would return the index of the element we are about to examine, and we want to return the index of the element we just examined.
The Iterator interface provides the remove operation to remove the last element returned by next from the Collection. For ListIterator, this operation removes the last element returned by next or previous. The ListIterator interface provides two additional operations to modify the list — set and add. The set method overwrites the last element returned by next or previous with the specified element. The following polymorphic algorithm uses set to replace all occurrences of one specified value with another.
public static  void replace(List list, 
E val, E newVal) {
for (ListIterator it =
list.listIterator();
it.hasNext(); )
if (val == null ? it.next()
== null : val.equals(it.next()))
it.set(newVal);
}
The only bit of trickiness in this example is the equality test between val and it.next. You need to special-case a val value of null to prevent a NullPointerException.
The add method inserts a new element into the list immediately before the current cursor position. This method is illustrated in the following polymorphic algorithm to replace all occurrences of a specified value with the sequence of values contained in the specified list.
public static  
void replace(List list, E val,
List newVals) {
for (ListIterator it =
list.listIterator();
it.hasNext(); ){
if (val == null ? it.next()
== null : val.equals(it.next())) {
it.remove();
for (E e : newVals)
it.add(e);
}
}
}

Range-View Operation

The range-view operation, subList(int fromIndex, int toIndex), returns a List view of the portion of this list whose indices range from fromIndex, inclusive, totoIndex, exclusive. This half-open range mirrors the typical for loop.
for (int i = fromIndex; i < toIndex; i++) {
...
}
As the term view implies, the returned List is backed up by the List on which subList was called, so changes in the former are reflected in the latter.
This method eliminates the need for explicit range operations (of the sort that commonly exist for arrays). Any operation that expects a List can be used as a range operation by passing a subList view instead of a whole List. For example, the following idiom removes a range of elements from a List.
list.subList(fromIndex, toIndex).clear();
Similar idioms can be constructed to search for an element in a range.
int i = list.subList(fromIndex, toIndex).indexOf(o);
int j = list.subList(fromIndex, toIndex).lastIndexOf(o);
Note that the preceding idioms return the index of the found element in the subList, not the index in the backing List.
Any polymorphic algorithm that operates on a List, such as the replace and shuffle examples, works with the List returned by subList.
Here's a polymorphic algorithm whose implementation uses subList to deal a hand from a deck. That is, it returns a new List (the "hand") containing the specified number of elements taken from the end of the specified List (the "deck"). The elements returned in the hand are removed from the deck.
public static  List dealHand(List deck, int n) {
int deckSize = deck.size();
List handView =
deck.subList(deckSize - n,
deckSize);
List hand =
new ArrayList(handView);
handView.clear();
return hand;
}
Note that this algorithm removes the hand from the end of the deck. For many common List implementations, such as ArrayList, the performance of removing elements from the end of the list is substantially better than that of removing elements from the beginning.
The following is a program that uses the dealHand method in combination with Collections.shuffle to generate hands from a normal 52-card deck. The program takes two command-line arguments: (1) the number of hands to deal and (2) the number of cards in each hand.
import java.util.*;

public class Deal {
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Usage: " +
"Deal hands cards");
return;
}
int numHands = Integer.parseInt(args[0]);
int cardsPerHand = Integer.parseInt(args[1]);

// Make a normal 52-card deck.
String[] suit = new String[] {
"spades", "hearts",
"diamonds", "clubs" };
String[] rank = new String[] {
"ace","2","3","4",
"5","6","7","8","9","10",
"jack","queen","king" };
List deck =
new ArrayList();
for (int i = 0; i < suit.length; i++)
for (int j = 0; j < rank.length; j++)
deck.add(rank[j] + " of "
+ suit[i]);

// Shuffle the deck.
Collections.shuffle(deck);

if (numHands * cardsPerHand > deck.size()) {
System.out.println("Not enough cards.");
return;
}

for (int i=0; i < numHands; i++)
System.out.println(dealHand(deck, cardsPerHand));
}

public static List dealHand(List deck, int n) {
int deckSize = deck.size();
List handView =
deck.subList(deckSize - n,
deckSize);
List hand =
new ArrayList(handView);
handView.clear();
return hand;
}
}
Running the program produces output like the following.
% java Deal 4 5

[8 of hearts, jack of spades, 3 of spades, 4 of spades,
king of diamonds]
[4 of diamonds, ace of clubs, 6 of clubs, jack of hearts,
queen of hearts]
[7 of spades, 5 of spades, 2 of diamonds, queen of diamonds,
9 of clubs]
[8 of spades, 6 of diamonds, ace of spades, 3 of hearts,
ace of hearts]
Although the subList operation is extremely powerful, some care must be exercised when using it. The semantics of the List returned by subList become undefined if elements are added to or removed from the backing List in any way other than via the returned List. Thus, it's highly recommended that you use the List returned bysubList only as a transient object — to perform one or a sequence of range operations on the backing List. The longer you use the subList instance, the greater the probability that you'll compromise it by modifying the backing List directly or through another subList object. Note that it is legal to modify a sublist of a sublist and to continue using the original sublist (though not concurrently).

List Algorithms

Most polymorphic algorithms in the Collections class apply specifically to List. Having all these algorithms at your disposal makes it very easy to manipulate lists. Here's a summary of these algorithms, which are described in more detail in the Algorithms section.
  • sort — sorts a List using a merge sort algorithm, which provides a fast, stable sort. (A stable sort is one that does not reorder equal elements.)
  • shuffle — randomly permutes the elements in a List.
  • reverse — reverses the order of the elements in a List.
  • rotate — rotates all the elements in a List by a specified distance.
  • swap — swaps the elements at specified positions in a List.
  • replaceAll — replaces all occurrences of one specified value with another.
  • fill — overwrites every element in a List with the specified value.
  • copy — copies the source List into the destination List.
  • binarySearch — searches for an element in an ordered List using the binary search algorithm.
  • indexOfSubList — returns the index of the first sublist of one List that is equal to another.
  • lastIndexOfSubList — returns the index of the last sublist of one List that is equal to another.

To get size of Java ArrayList use int size() method for selenium automation learning


  1. /*
  2.   Get Size of Java ArrayList and loop through elements Example
  3.   This Java Example shows how to get size or number of elements currently
  4.   stored in ArrayList. It also shows how to loop through element of it.
  5. */
  6.  
  7. import java.util.ArrayList;
  8.  
  9. public class GetSizeOfArrayListExample {
  10.  
  11.   public static void main(String[] args) {
  12.     //create an ArrayList object
  13.     ArrayList arrayList = new ArrayList();
  14.    
  15.     //Add elements to Arraylist using
  16.     arrayList.add("1");
  17.     arrayList.add("2");
  18.     arrayList.add("3");
  19.  
  20.     //To get size of Java ArrayList use int size() method
  21.     int totalElements = arrayList.size();
  22.    
  23.     System.out.println("ArrayList contains...");
  24.     //loop through it
  25.     for(int index=0; index < totalElements; index++)
  26.       System.out.println(arrayList.get(index));
  27.    
  28.   }
  29. }
  30.  
  31. /*
  32. Output would be
  33. ArrayList contains...
  34. 1
  35. 2
  36. 3
  37. */

JAVA EXCEPTIONS for selenium automation learning


JAVA EXCEPTIONS


Contents


Error Handling

Runtime errors can be divided into low-level errors that involve violating constraints, such as:
  • dereference of a null pointer
  • out-of-bounds array access
  • divide by zero
  • attempt to open a non-existent file for reading
  • bad cast (e.g., casting an Object that is actually a Boolean to Integer)
and higher-level, logical errors, such as violations of a function's precondition:
  • call to Stack's "pop" method for an empty stack
  • call to "factorial" function with a negative number
  • call to List's nextElement method when hasMoreElements is false
Logical errors can lead to low-level errors if they are not detected. Often, it is better to detect them (to provide better feedback).
Errors can arise due to:
  • User error (for example, providing a bad file name or a poorly formatted input file). A good program should be written to anticipate these situations, and should deal with them. For example, given a bad file name, an interactive program could print an error message and prompt for a new name.
  • Programmer error (i.e., a buggy program). These errors should be detected as early as possible to provide good feedback. For some programs it may be desirable to do some recovery after detecting this kind of error; for example, writing out current data.
Note that recovery is often not possible at the point of the error (because the error may occur inside some utility function that doesn't know anything about the overall program or what error recovery should involve). Therefore, it is desirable to "pass the error up" to a level that can deal with it.
There are several possible ways to handle errors:
  • Write an error message and quit. This doesn't provide any recovery.
  • Return a special value to indicate that an error occurred. This is the usual approach for C functions (which often return 0 or -1 to signal an error). However:
    • It doesn't work if the function also returns a value on normal completion and all values are possible (i.e., there is no special value that can be used to signal an error).
    • It requires that calling code check for an error. This can reduce the efficiency of the code, and is often omitted by programmers out of laziness or carelessness.
    • It can sometimes make the code more clumsy. For example, if function g might return an error code, one would have to write something like:
                 ret = g(x);
      if (ret == ERROR_CODE) { ... }
      else f(ret);
      instead of just:
          f(g(x));
  • Use a reference parameter or a global variable to hold an error code. This solves the first problem of the previous approach, but not the second or third ones.
  • Use exceptions. This seems to be the method of choice for modern programming languages.

Exceptions

Idea:
  • When an error is detected, an exception is thrown. That is, the code that caused the error stops executing immediately, and control is transferred to the catch clause for that exception of the first enclosing try blockthat has such a clause. The try block might be in the current function (the one that caused the error), or it might be in some function that called the current function (i.e., if the current function is not prepared to handle the exception, it is "passed up" the call chain). If no currently active function is prepared to catch the exception, an error message is printed and the program stops.
Exceptions can be built-in (actually, defined in one of Java's standard libraries) or user-defined. Here are some examples of built-in exceptions with links to their documentation:

How to Catch Exceptions

Catch exceptions using try blocks:
    try {
// statements that might cause exceptions
// possibly including function calls
} catch ( exception-1 id-1 ) {
// statements to handle this exception
} catch ( exception-2 id-2 ) {
// statements to handle this exception
.
.
.
} finally {
// statements to execute every time this try block executes
}
Notes:
  1. Each catch clause specifies the type of one exception, and provides a name for it (similar to the way a function header specifies the type and name of a parameter). Java exceptions are objects, so the statements in a catch clause can refer to the thrown exception object using the specified name.
  2. The finally clause is optional.
  3. In general, there can be one or more catch clauses. If there is a finally clause, there can be zero catch clauses.
Example (a program that tries to open a file named by the first command-line argument for reading)
    public static void main(String[] args)
    {
    InputStream istream;
    File inputFile;

    try {
    inputFile = new File(args[0]);
    istream = new InputStream(inputFile); // may throw FileNotFoundException
    } catch (FileNotFoundException ex) {
    System.out.println("file " + args[0] + " not found");
    }
    }
Notes:
  1. The program really should make sure there is a command-line argument before attempting to use args[0].
  2. Also, it probably makes more sense to put the try block in a loop, so that if the file is not found the user can be asked to enter a new file name, and a new attempt to open the file can be made.
  3. As is, if the user runs the program with a bad file name foo, the message "file foo not found" will be printed, and the program will halt.
  4. If there were no try block and the program were run with a bad file name foo, a more complicated message, something like this:
        java.io.FilenotFoundException: foo
      at java.io.FileInputStream ...
      at ...
      at Test.main ...
    would be printed. (Actually, if there were no try/catch for the FileNotFoundException, the program wouldn't compile because it fails to list that exception as one that might be thrown. We'll come back to that issue later...)

More About the Finally Clause

  • A finally clause is usually included to make sure that some clean-up (e.g., closing opened files) is done.
  • A finally clause always executes when its try block executes (whether or not there is an exception). Furthermore, if the finally clause includes a transfer of control statement (return, break, continue, throw) then that statement overrides any transfer of control initiated in the try or in a catch clause. First, let's assume that the finally clause does not include any transfer of control. Here are the situations that can arise:
    1. No exception occurs during execution of the try, and no transfer of control is executed in the try.
      => The finally clause executes, then the statement following the try block.
    2. No exception occurs during execution of the try, but it does execute a transfer of control.
      => The finally clause executes, then the transfer of control takes place.
    3. An exception does occur during execution of the try, and there is no catch clause for that exception.
      => The finally clause executes, then the uncaught exception is "passed up" to the next enclosing try block, possibly in a calling function.
    4. An exception does occur during execution of the try, and there is a catch clause for that exception. The catch clause does not execute a transfer of control.
      => The catch clause executes, then the finally clause, then the statement following the try block.
    5. An exception does occur during execution of the try, there is a catch clause for that exception, and the catch clause does execute a transfer of control.
      => The catch clause executes, then the finally clause, then the transfer of control takes place.
    If the finally block does include a transfer of control, then that takes precedence over any transfer of control executed in the try or in an executed catch clause. So for all of the cases listed above, the finally clause would execute, then its transfer of control would take place. Here's one example:
          try {
      return 0;
      } finally {
      return 2;
      }
    The result of executing this code is that 2 is returned.Note that this is rather confusing! The moral is that you probably do not want to include transfer-of-control statements in both the try statements and the finally clause, or in both a catch clause and the finally clause.

Checked and Unchecked Exceptions

Every exception is either a checked exception or an unchecked exception. If a method includes code that could cause a checked exception to be thrown, then:
  • the exception must be declared in the method header, using a throws clause, or
  • the code that might cause the exception to be thrown must be inside a try block with a catch clause for that exception.
So in general, you must always include some code that acknowledges the possibility of a checked exception being thrown. If you don't, you will get an error when you try to compile your code.

Exception Hierarchy

                    +--------+
| Object |
+--------+
|
|
+-----------+
| Throwable |
+-----------+
/ \
/ \
+-------+ +-----------+
| Error | | Exception |
+-------+ +-----------+
/ | \ / | \
\________/ \______/ \
+------------------+
unchecked checked | RuntimeException |
+------------------+
/ | | \
\_________________/

unchecked
  • most of the built-in exceptions (e.g., NullPointerException, IndexOutOfBoundsException) are unchecked.
  • IOExceptions (e.g., FileNotFoundException) are checked
  • user-defined exceptions should usually be checked, so they should be subclasses of Exception.

Choices when calling a function that may throw an exception

  1. Catch and handle the exception.
  2. Catch the exception, then re-throw it or throw another exception.
  3. Ignore the exception (let it "pass up" the call chain).
Note that if your code might cause a checked exception to be thrown; i.e.,:
  • your code throws a checked exception, or
  • your code ignores a checked exception that might be thrown by a called function
then your function must include a throws clause listing all such exceptions. For example:
    public static void main(String[] args) throws FileNotFoundException, EOFException
{ // an uncaught FileNotFoundException or EOFException may be thrown here }
Only uncaught checked exceptions need to be listed in a function's throws clause. Unchecked exceptions can be caught in a try block, but if not, they need not be listed in the function's throws clause.

TEST YOURSELF #1
Consider the following program (assume that comments are replaced with actual code that works as specified):
    class TestExceptions {

    static void e() {
    // might cause any of the following unchecked exceptions to be thrown:
    // Ex1, Ex2, Ex3, Ex4
    }

    static void d() {
    try {
    e();
    } catch (Ex1 ex) {
    System.out.println("d caught Ex1");
    }
    }

    static void c() {
    try {
    d();
    } catch (Ex2 ex) {
    System.out.println("c caught Ex2");
    // now cause exception Ex1 to be thrown
    }
    }

    static void b() {
    try {
    c();
    } catch (Ex1 ex) {
    System.out.println("b caught Ex1");
    } catch (Ex3 ex) {
    System.out.println("b caught Ex3");
    }
    }

    static void a() {
    try {
    b();
    } catch (Ex1 ex) {
    System.out.println("a caught Ex1");
    } catch (Ex4 ex) {
    System.out.println("a caught Ex4");
    // now cause exception Ex1 to be thrown
    }
    }

    public static void main(String[] args) {
    a();
    }
    }
Assume that this program is run four times. The first time, function e throws exception Ex1, the second time, it throws exception Ex2, etc. Foe each of the four runs, say what is printed; if an uncaught exception is thrown, say what happens.

How to Define and Throw Exceptions

  • Java exceptions are objects.
  • Define an exception by defining a class, for example:
      public class EmptyStackException extends Exception { }
    Note: New exceptions must be subclasses of Throwable; as discussed above, they are usually subclasses of Exception (so that they are checked). The exceptions you define do not have to be public classes; however, remember that if you do not make them public, then they can only used in the package in which they are defined.
  • Throw an exception using a throw statement:
      public class Stack {
        ...
        public Object Pop() throws EmptyStackException {
          if (Empty()) throw new EmptyStackException();
          ...
        }
      }
    Note:
    • Exceptions are objects, so you cannot simply throw "EmptyStackException" -- you must use "new" to create an exception object.
    • Since the Pop method might throw the (checked) exception EmptyStackException, that must be included in Pop's throws clause.

TEST YOURSELF #2
Question 1: Assume that function f might throw exceptions Ex1, Ex2, or Ex3. Complete function g, outlined below, so that:
  • If the call to f causes Ex1 to be thrown, g will catch that exception and print "Ex1 caught".
  • If the call to f causes Ex2 to be thrown, g will catch that exception, print "Ex2 caught", and then will throw an Ex1 exception.
        static void g() throws ... {
    try {
    f();
    } catch ( ... ) {
    ...
    } ...
    }
Question 2: Consider the following function.
    static void f(int k, int[] A, String S) {
    int j = 1 / k;
    int len = A.length + 1;
    char c;

    try {
    c = S.charAt(0);
    if (k == 10) j = A[3];
    } catch (ArrayIndexOutOfBoundsException ex) {
    System.out.println("array error");
    throw new InternalError();
    } catch (ArithmeticException ex) {
    System.out.println("arithmetic error");
    } catch (NullPointerException ex) {
    System.out.println("null ptr");
    } finally {
    System.out.println("in finally clause");
    }
    System.out.println("after try block");
    }
Part A.
    Assume that variable X is an array of int that has been initialized to be of length 3. For each of the following calls to function f, say what (if anything) is printed by f, and what, if any, uncaught exceptions are thrown by f.A. f(0, X, "hi");
    B. f(10, X, "");
    C. f(10, X, "bye");
    D. f(10, X, null);
Part B.
    Why doesn't f need to have a throws clause that lists the uncaught exceptions that it might throw?

Summary

  • Code that detects errors often does not know how to handle them.
  • Therefore, we need a way to "pass errors up".
  • The best approach is to use exceptions.
  • Java provides both built-in and user-defined exceptions.
  • Exceptions are caught using a try block:
      try {
        // statements (including function calls) that might cause an exception
      } catch ( exception-1 id1 ) {
        // code to handle the first kind of exception
      } catch ( exception-2 id2 ) {
        // code to handle the second kind of exception
      } ...
      } finally {
        // code that will execute whenever this try block does
      }
  • Exceptions are thrown using a throw statement.
  • If an exception is thrown in code that is not inside a try block, or is in a try block with no catch clause for the thrown exception, the exception is "passed up" the call stack.
  • Some exceptions are checked and some are unchecked. If a function might throw one or more checked exceptions, they must be listed in the function's throws clause.
  • Exceptions are objects; they are defined as classes (the class name is the name of the exception) that extend the Exception class.

Solutions to Self-Study Questions

Test Yourself #1

    What is printed for each of the four runs?

    1. d caught Ex1
    2. c caught Ex2
    b caught Ex1
    3. b caught Ex3
    4. a caught Ex4
    execution stops due to uncaught exception Ex1 thrown in main

Test Yourself #2

    Question 1: 

    static void g() throws Ex1, Ex3 {
    try {
    f();
    } catch (Ex1 ex1) {
    System.out.println("Ex1 caught");
    } catch (Ex2 ex2) {
    System.out.println("Ex2 caught");
    throw new Ex1();
    }
    }

    Question 2:
    Part A.

    A. f(0, X, "hi");
    nothing printed
    throws ArithmeticException
    B. f(10, X, "");
    prints "in finally clause"
    throws StringIndexOutOfBoundsException
    C. f(10, X, "bye");
    prints "array error", "in finally clause"
    throws InternalError
    D. f(10, X, null);
    prints "null ptr", "in finally clause", "after try block"


    Part B.

    Function f doesn't need to have a throws clause that lists the
    uncaught exceptions that it might throw because only uncaught CHECKED
    exceptions need to be listed in a function's throws clause. The
    uncaught exceptions that f might throw are all UNCHECKED exceptions.

Exception Hierarchy for selenium automation learning


Exception Hierarchy

                    +--------+
| Object |
+--------+
|
|
+-----------+
| Throwable |
+-----------+
/ \
/ \
+-------+ +-----------+
| Error | | Exception |
+-------+ +-----------+
/ | \ / | \
\________/ \______/ \
+------------------+
unchecked checked | RuntimeException |
+------------------+
/ | | \
\_________________/

unchecked
  • most of the built-in exceptions (e.g., NullPointerException, IndexOutOfBoundsException) are unchecked.
  • IOExceptions (e.g., FileNotFoundException) are checked
  • user-defined exceptions should usually be checked, so they should be subclasses of Exception.