Posted on Leave a comment

public Members – Access Control

public Members

Public access is the least restrictive of all the access modifiers. A public member is accessible from anywhere, both in the package containing its class and by other packages where its class is accessible.

In Example 6.8, the public instance field pubInt in an instance of the class Superclass1 is accessible by all four clients. Subclasses can access their inherited public members by their simple names, and all clients can access public members in an instance of the class Superclass1.

protected Members

A protected member is accessible in all classes in the same package, and by all subclasses of its class in any package where its class is accessible.

In other words, a protected member cannot be accessed by non-subclasses in other packages. This kind of access is more restrictive than public member access.

In Example 6.8, the protected instance field proStr in an instance of the class Superclass1 is accessible within pkg1 by Client 1 and Client 2. Also as expected, Client 4—the class NonSubclass2 in pkg2—cannot access this protected member of the class Superclass1.

However, the compiler reports an error at (7) in the method printState1() of the class Subclass2 where the protected instance field proStr in an instance of the class Superclass1 cannot be accessed by the reference obj1.

In contrast, the method printState2() at (8) in the class Subclass2 uses the reference obj2 that refers to an instance of the class Subclass2 to access the instance fields declared in the class Superclass1, and now the protected instance field proStr in the superclass is accessible, as shown at (10).

This apparent anomaly is explained by the fact that a subclass in another package can only access protected instance members in the superclass via references of its own type—that is, protected instance members that are inherited by objects of the subclass. No inheritance from the superclass is involved in a subclass in another package when an object of the superclass is used.

Note that the above anomaly would not arise if a subclass in another package were to access any protected static members in the superclass, as such members are not part of any object of the superclass.

Posted on Leave a comment

Searching for Classes on the Class Path 2 – Access Control

The compiler cannot find the class B—that is, the file B.class containing the Java bytecode for the class B. In Figure 6.4b, we can see that it is in the package pkg under the directory bin, but the compiler cannot find it. This is hardly surprising, as there is no bytecode file for the class B in the current directory, which is the default value of the class path. The following command sets the value of the class path to be /top/bin, and compilation is successful (Figure 6.4c):

Click here to view code image

>
javac -classpath /top/bin -d ../bin A.java

It is very important to understand that when we want the JDK tool to search in a named package, it is the location or the root of the package that is specified; in other words, the class path indicates the directory that contains the first component of the fully qualified package name. In Figure 6.4c, the package pkg is contained under the directory whose absolute path is /top/bin. The following command will not work, as the directory /top/bin/pkg does not contain a package with the name pkg that has a class B:

Click here to view code image

>
javac -classpath /top/bin/pkg -d ../bin A.java

Also, the compiler is not using the class path to find the source file(s) that are specified in the command line. In the preceding command, the source file has the relative pathname ./A.java. Consequently, the compiler looks for the source file in the current directory. The class path is used to find the classes used by the class A, in this case, to find class B.

Given the file hierarchy in Figure 6.3, the following -classpath option sets the class path so that all packages (wizard.pandorasbox, wizard.pandorasbox.artifacts, wizard.spells) in Figure 6.3 will be searched, as all packages are located under the specified directory:

-classpath /pgjc/work

However, the following -classpath option will not help in finding any of the packages in Figure 6.3, as none of the packages are located under the specified directory:

Click here to view code image

>
java -classpath /pgjc/work/wizard pandorasbox.Clown

This command also illustrates an important point about package names: The fully qualified package name should not be split. The package name for the class wizard.pandorasbox.Clown is wizard.pandorasbox, and must be specified fully. The following command will search all packages in Figure 6.3 for classes that are used by the class wizard.pandorasbox.Clown:

Click here to view code image

>
java -classpath /pgjc/work wizard.pandorasbox.Clown

The class path can specify several entries (i.e., several locations), and the JDK tool searches them in the order they are specified, from left to right.

Click here to view code image

-classpath /pgjc/work:/top/bin:.

We have used the path-separator character ‘:’ for Unix-based platforms to separate the entries, and also included the current directory (.) as an entry. There should be no whitespace on either side of the path-separator character. On the Windows platform, the path-separator character is a semicolon (;).

The search in the class path entries stops once the required class file is found. Therefore, the order in which entries are specified can be significant. If a class B is found in a package pkg located under the directory /ext/lib1, and also in a package pkg located under the directory /ext/lib2, the order in which the entries are specified in the two -classpath options shown below is significant. They will result in the class pkg.B being found under /ext/lib1 and /ext/lib2, respectively.

Click here to view code image

-classpath /ext/lib1:/ext/lib2
-classpath /ext/lib2:/ext/lib1

The examples so far have used absolute pathnames for class path entries. We can, of course, use relative pathnames as well. If the current directory has the absolute pathname /pgjc/work in Figure 6.3, the following command will search the packages under the current directory:

Click here to view code image

>
java -classpath . wizard.pandorasbox.Clown

If the current directory has the absolute pathname /top/src in Figure 6.4, the following command will compile the file ./A.java:

Click here to view code image

>
javac -classpath ../bin -d ../bin A.java

If the name of an entry in the class path includes whitespace, the name should be double-quoted so that it will be interpreted correctly:

-classpath “../new bin”

Table 6.1 summarizes the commands and options to compile and execute non-modular code. The tool documentation from Oracle provides more details on how to use the JDK development tools.

Table 6.1 Compiling and Executing Non-Modular Java Code

OperationCommand
Compiling non-modular code:javac –class-path classpath -d directory sourceFiles javac -classpath classpath -d directory sourceFiles javac -cp classpath -d directory sourceFiles
Executing non-modular code:java –class-path classpath qualifiedClassName java -classpath classpath qualifiedClassName java -cp classpath qualifiedClassName
Posted on Leave a comment

Deriving Permitted Direct Subtypes of a Sealed Supertype – Object-Oriented Programming

Deriving Permitted Direct Subtypes of a Sealed Supertype

The permits clause of a sealed class or interface can be omitted, if all its permitted direct subtypes are declared in the same compilation unit—that is, are in the same source file. Since only one reference type can be declared public in a compilation unit, the accessibility of the other type declarations cannot be public.

The compiler can infer the permitted direct subtypes of any sealed class or interface in a compilation unit by checking whether a type declaration fulfills the contract for declaring a permitted direct subtype; that is, it extends/implements a sealed supertype and is declared either (implicitly) sealed, non-sealed, or (implicitly) final.

Click here to view code image

// File: Book.java (compilation unit)
public abstract sealed class Book {}        // Permitted subclasses are derived.
non-sealed class PrintedBook extends Book {}
sealed interface Subscribable {}            // Permitted subtypes are derived.
final class Ebook extends Book implements Subscribable {}
final class Audiobook extends Book implements Subscribable {}
non-sealed interface VIPSubcribable extends Subscribable {}

Given the type declarations in the compilation unit Book.java, the compiler is able to infer that PrintedBook, Ebook, and Audiobook are permitted direct subclasses of the sealed superclass Book, whereas Ebook, Audiobook, and VIPSubcribable are permitted direct subtypes of the sealed superinterface Subscribable.

Using Sealed Classes and Interfaces

As we have seen, sealed classes and interfaces restrict which other classes or interfaces can extend or implement them. Apart from providing the programmer with a language feature to develop improved domain models for libraries, the compiler can also leverage the sealed types to provide better analysis of potential problems in the code at compile time.

Example 5.33 is a client that uses the sealed classes and their permitted direct subclasses defined in Example 5.32. Typically, a reference of the sealed superclass is used to process a collection of objects of its permitted subtypes. The array books is such a collection created at (2). The objects of the permitted subtypes are processed by the enhanced for(:) loop at (3). Typically, a cascading if-else statement is used in the loop body to distinguish each object in the collection and process it accordingly. Any object of a permitted subclass can be processed by the code as long as the cascading if-else statement guarantees that the checks are exhaustive—that is, all permitted subtypes are covered. The compiler cannot help to ensure that this is the case, as it cannot extract the necessary information from the cascading if-else statement for this analysis. Note that the conditionals in the cascading if-else statement use the instanceof pattern match operator to make the code at least less verbose.

Example 5.33 Using Sealed Classes

Click here to view code image

package signedandsealed;
public class BookAdmin {
  public static void main(String[] args) {
    // Create some books:                                                  // (1)
    PrintedBook pBook = new PrintedBook(“888-222”, 340);
    Ebook eBook = new Ebook(“999-777”, “epub”);
    Audiobook aBook = new Audiobook(“333-555”, “Fry”, 300.0);
    // Create a book array:                                                // (2)
    Book[] books = {pBook, eBook, aBook};
    // Process the books:                                                  // (3)
    for (Book book : books) {
      if (book instanceof PrintedBook pb) {                                // (4)
        System.out.printf(“Printed book: %s, %d%n”,
                           pb.getIsbn(), pb.getPageCount());
      } else if (book instanceof Ebook eb) {
        System.out.printf(“Ebook: %s, %s%n”, eb.getIsbn(), eb.getFormat());
      } else if (book instanceof Audiobook ab) {
        System.out.printf(“Audiobook: %s, %s, %.1f%n”,
                           ab.getIsbn(), ab.getNarrator(), ab.getLength());
      }
    }
  }
}

Output from the program:

Click here to view code image Printed book: 888-222, 340
Ebook: 999-777, epub
Audiobook: 333-555, Fry, 300.0

Posted on Leave a comment

Checked and Unchecked Exceptions – Exception Handling

Checked and Unchecked Exceptions

Except for RuntimeException, Error, and their subclasses, all exceptions are checked exceptions. A checked exception represents an unexpected event that is not under the control of the program—for example, a file was not found. The compiler ensures that if a method can throw a checked exception, directly or indirectly, the method must either catch the exception and take the appropriate action, or pass the exception on to its caller (p. 388).

Exceptions defined by the Error and RuntimeException classes and their subclasses are known as unchecked exceptions, meaning that a method is not obliged to deal with these kinds of exceptions (shown with gray color in Figure 7.3). Either they are irrecoverable (exemplified by the Error class), in which case the program should not attempt to deal with them, or they are programming errors (exemplified by the RuntimeException class and its subclasses) and should usually be dealt with as such, and not as exceptions.

Defining Customized Exceptions

Customized exceptions are usually defined to provide fine-grained categorization of error situations, instead of using existing exception classes with descriptive detail messages to differentiate among the various situations. New customized exceptions are usually defined by either extending the Exception class or one of its checked subclasses, thereby making the new exceptions checked, or extending the RuntimeException subclass or one of its subclasses to create new unchecked exceptions.

Customized exceptions, as any other Java classes, can declare fields, constructors, and methods, thereby providing more information as to their cause and remedy when they are thrown and caught. The super() call can be used in a constructor to set pertinent details about the exception: a detail message or the cause of the exception (p. 405), or both. Note that the exception class must be instantiated to create an exception object that can be thrown and subsequently caught and dealt with. The following code sketches a class declaration for an exception that can include all pertinent information about the exception. Typically, the new exception class provides a constructor to set the detail message.

Click here to view code image

public class EvacuateException extends Exception {
  // Fields
  private Date date;
  private Zone zone;
  private TransportMode transport;
  // Constructor
  public EvacuateException(Date d, Zone z, TransportMode t) {
    // Call the constructor of the superclass, usually passing a detail message.
    super(“Evacuation of zone ” + z);
    // …
  }
  // Methods
  // …
}

Several examples in subsequent sections illustrate exception handling.

Posted on Leave a comment

The java.lang.RuntimeException Class – Exception Handling

The java.lang.RuntimeException Class

Runtime exceptions are all subclasses of the java.lang.RuntimeException class, which is a subclass of the Exception class. As these runtime exceptions are usually caused by program bugs that should not occur in the first place, it is usually more appropriate to treat them as faults in the program design and let them be handled by the default exception handler.

Click here to view code image

java.lang.ArithmeticException

This exception represents situations where an illegal arithmetic operation is attempted, such as integer division by 0. It is typically thrown by the JVM.

Click here to view code image

java.lang.ArrayIndexOutOfBoundsException

Java provides runtime checking of the array index value, meaning out-of-bounds array indices. The subclass ArrayIndexOutOfBoundsException of the RuntimeException class represents exceptions thrown by the JVM that signal out-of-bound errors specifically for arrays—that is, an error in which an invalid index is used to access an element in the array. The index value must satisfy the relation 0 ≤ index value < length of the array (§3.9, p. 120).

Click here to view code image

java.lang.ArrayStoreException

This exception is thrown by the JVM when an attempt is made to store an object of the wrong type into an array of objects. The array store check at runtime ensures that an object being stored in the array is assignment compatible with the element type of the array (§5.7, p. 260). To make the array store check feasible at runtime, the array retains information about its declared element type at runtime.

java.lang.ClassCastException

This exception is thrown by the JVM to signal that an attempt was made to cast a reference value to a type that was not legal, such as casting the reference value of an Integer object to the Long type (§5.11, p. 269).

Click here to view code image

java.lang.IllegalArgumentException

The class IllegalArgumentException represents exceptions thrown to signal that a method was called with an illegal or inappropriate argument. For example, the ofPattern(String pattern) method in the java.time.format.DateTimeFormatter class throws an IllegalArgumentException when the letter pattern passed as an argument is invalid (§18.6, p. 1134).

Click here to view code image

java.lang.IllegalThreadStateException

The class IllegalThreadStateException is a subclass of the IllegalArgumentException class. Certain operations on a thread can only be executed when the thread is in an appropriate state (§22.4, p. 1380). This exception is thrown when this is not the case. For example, the start() method of a Thread object throws this exception if the thread has already been started (§22.3, p. 1370).

Click here to view code image

java.lang.NumberFormatException

The class NumberFormatException is a subclass of the IllegalArgumentException class that is specialized to signal problems when converting a string to a numeric value if the format of the characters in the string is not appropriate for the conversion. This exception is thrown programmatically. The numeric wrapper classes all have methods that throw this exception when conversion from a string to a numeric value is not possible (§8.3, p. 434).

Click here to view code image

java.lang.NullPointerException

This exception is typically thrown by the JVM when an attempt is made to use the null value as a reference value to refer to an object. This might involve calling an instance method using a reference that has the null value, or accessing a field using a reference that has the null value.

This programming error has made this exception one of the most frequently thrown exceptions by the JVM. The error message issued provides helpful information as to where and which reference raised the exception. However, inclusion of variables names in the message can be a potential security risk.

Click here to view code image

Exception in thread “main” java.lang.NullPointerException: Cannot invoke
“String.toLowerCase()” because “msg” is null
    at StringMethods.main(StringMethods.java:162)

Click here to view code image

java.lang.UnsupportedOperationException

This exception is thrown programmatically to indicate that an operation invoked on an object is not supported. Typically, a class implements an interface, but chooses not to provide certain operations specified in the interface. Methods in the class corresponding to these operations throw this exception to indicate that an operation is not supported by the objects of the class.

The API documentation of the java.util.Collection interface (§15.1, p. 783) in the Java Collections Framework states that certain methods are optional, meaning that a concrete collection class need not provide support for such operations, and if any such operation is not supported, then the method should throw this exception.

java.time.DateTimeException

In the Date and Time API, the class DateTimeException represents exceptions that signal problems with creating, querying, and manipulating date-time objects (§17.2, p. 1027).

Click here to view code image

java.time.format.DateTimeParseException

In the Date and Time API, the class DateTimeParseException is a subclass of the Date-TimeException class that represents an exception that signals unexpected errors when parsing date and time values (§18.6, p. 1127).

Click here to view code image

java.util.MissingResourceException

This exception is thrown programmatically, typically by the lookup methods of the java.util.ResourceBundle class (§18.3, p. 1104). Get methods on resource bundles typically throw this exception when no resource can be found for a given key. Static lookup methods in this class also throw this exception when no resource bundle can be found based on a specified base name for a resource bundle. Resource bundles are discussed in §18.3, p. 1102.

The java.lang.Error Class

The class Error and its subclasses define errors that are invariably never explicitly caught and are usually irrecoverable. Not surprisingly, most such errors are signaled by the JVM. Apart from the subclass mentioned below, other subclasses of the java.lang.Error class define different categories of errors.

The subclass VirtualMachineError represents virtual machine errors like stack overflow (StackOverflowError) and out of memory for object allocation (OutOfMemoryError). The subclass LinkageError represents class linkage errors like missing class definitions (NoClassDefFoundError). The subclass AssertionError of the Error class is used by the Java assertion facility.

Posted on Leave a comment

The catch Clause – Exception Handling

The catch Clause

Only an exit from a try block resulting from an exception can transfer control to a catch clause. A catch clause can catch the thrown exception only if the exception is assignable to the parameter in the catch clause. The code of the first such catch clause is executed, and all other catch clauses are ignored.

On exit from a catch clause, normal execution continues unless there is any uncaught exception that has been thrown and not handled. If this is the case, the method is aborted after the execution of any finally clause and the exception propagated up the JVM stack.

It is important to note that after a catch clause has been executed, control is always transferred to the finally clause if one is specified. This is true as long as there is a finally clause, regardless of whether the catch clause itself throws an exception.

In Example 7.2, the method printAverage() calls the method computeAverage() in a try-catch construct at (4). The catch clause is declared to catch exceptions of type ArithmeticException. The catch clause handles the exception by printing the stack trace and some additional information at (7) and (8), respectively. Normal execution of the program is illustrated in Figure 7.5, which shows that the try block is executed but no exceptions are thrown, with normal execution continuing after the try-catch construct. This corresponds to Scenario 1 in Figure 7.4.

Figure 7.5 Exception Handling (Scenario 1)

Example 7.2 The try-catch Construct

Click here to view code image

public class Average2 {
  public static void main(String[] args) {
    printAverage(100, 20);                                         // (1)
    System.out.println(“Exit main().”);                            // (2)
  }
  public static void printAverage(int totalSum, int totalCount) {
    try {                                                          // (3)
      int average = computeAverage(totalSum, totalCount);          // (4)
      System.out.println(“Average = ” +                            // (5)
          totalSum + ” / ” + totalCount + ” = ” + average);
    } catch (ArithmeticException ae) {                             // (6)
      ae.printStackTrace();                                        // (7)
      System.out.println(“Exception handled in printAverage().”);  // (8)
    }
    System.out.println(“Exit printAverage().”);                    // (9)
  }
public static int computeAverage(int sum, int count) {
    System.out.println(“Computing average.”);                      // (10)
    return sum/count;                                              // (11)
  }
}

Output from the program, with call printAverage(100, 20) at (1):

Computing average.
Average = 100 / 20 = 5
Exit printAverage().
Exit main().

Output from the program, with call printAverage(100, 0) at (1):

Click here to view code image

Computing average.
java.lang.ArithmeticException: / by zero
        at Average2.computeAverage(Average2.java:23)
        at Average2.printAverage(Average2.java:11)
        at Average2.main(Average2.java:5)
Exception handled in printAverage().
Exit printAverage().
Exit main().

However, if we run the program in Example 7.2 with the following call at (1):

printAverage(100, 0)

an ArithmeticException is thrown by the integer division operator in the method computeAverage(). In Figure 7.6 we see that the execution of the method compute-Average() is stopped and the exception propagated to method printAverage(), where it is handled by the catch clause at (6). Normal execution of the method continues at (9) after the try-catch construct, as witnessed by the output from the statements at (9) and (2). This corresponds to Scenario 2 in Figure 7.4.

In Example 7.3, the main() method calls the printAverage() method in a try-catch construct at (1). The catch clause at (3) is declared to catch exceptions of type ArithmeticException. The printAverage() method calls the computeAverage() method in a try-catch construct at (7), but here the catch clause is declared to catch exceptions of type IllegalArgumentException. Execution of the program is illustrated in Figure 7.7, which shows that the ArithmeticException is first propagated to the catch clause in the printAverage() method. Because this catch clause cannot handle this exception, it is propagated further to the catch clause in the main() method, where it is caught and handled. Normal execution continues at (6) after the exception is handled.

In Example 7.3, the execution of the try block at (7) in the printAverage() method is never completed: The statement at (9) is never executed. The catch clause at (10) is skipped. The execution of the printAverage() method is aborted: The statement at (13) is never executed, and the exception is propagated. This corresponds to Scenario 3 in Figure 7.4.

Figure 7.6 Exception Handling (Scenario 2)

Example 7.3 Exception Propagation

Click here to view code image

public class Average3 {
  public static void main(String[] args) {
    try {                                                          // (1)
      printAverage(100, 0);                                        // (2)
    } catch (ArithmeticException ae) {                             // (3)
      ae.printStackTrace();                                        // (4)
      System.out.println(“Exception handled in main().”);          // (5)
    }
    System.out.println(“Exit main().”);                            // (6)
  }
  public static void printAverage(int totalSum, int totalCount) {
    try {                                                          // (7)
      int average = computeAverage(totalSum, totalCount);          // (8)
      System.out.println(“Average = ” +                            // (9)
totalSum + ” / ” + totalCount + ” = ” + average);
    } catch (IllegalArgumentException iae) {                       // (10)
      iae.printStackTrace();                                       // (11)
      System.out.println(“Exception handled in printAverage().”);  // (12)
    }
    System.out.println(“Exit printAverage().”);                    // (13)
  }
  public static int computeAverage(int sum, int count) {
    System.out.println(“Computing average.”);                      // (14)
    return sum/count;                                              // (15)
  }
}

Output from the program:

Click here to view code image

Computing average.
java.lang.ArithmeticException: / by zero
        at Average3.computeAverage(Average3.java:28)
        at Average3.printAverage(Average3.java:16)
        at Average3.main(Average3.java:6)
Exception handled in main().
Exit main().

The scope of the exception parameter name in the catch clause is the body of the catch clause—that is, it is a local variable in the body of the catch clause. As mentioned earlier, the type of the exception object must be assignable to the type of the argument in the catch clause. In the body of the catch clause, the exception object can be queried like any other object by using the parameter name.

The javac compiler complains if a catch clause for a superclass exception shadows the catch clause for a subclass exception, as the catch clause of the subclass exception will never be executed (a situation known as unreachable code). The following example shows incorrect order of the catch clauses at (1) and (2), which will result in a compile-time error at (2): The superclass Exception will shadow the subclass ArithmeticException.

Click here to view code image

try {
  // …
} catch (Exception e) {              // (1) Superclass shadows subclass
  System.out.println(e);
} catch (ArithmeticException e) {    // (2) Compile-time error: Unreachable code
  System.out.println(e);
}

The compiler will also flag an error if the parameter of the catch clause has a checked exception type that cannot be thrown by the try block, as this would result in unreachable code.

Click here to view code image

try {
  throw new ArithmeticException();      // IOException never thrown in try block
} catch (IOException e) {               // Compile-time error: Unreachable code
  System.out.println(e);
}

Figure 7.7 Exception Handling (Scenario 3)

Posted on Leave a comment

Java Source File Structure – Access Control

6.2 Java Source File Structure

The structure of a skeletal Java source file is depicted in Figure 6.1. A Java source file can have the following elements that, if present, must be specified in the following order:

  1. An optional package declaration to specify a package name. Packages are discussed in §6.3, p. 326.
  2. Zero or more import declarations. Since import declarations introduce type or static member names in the source code, they must be placed before any type declarations. Both type and static import declarations are discussed in §6.3, p. 329.
  3. Any number of top-level type declarations. Class, enum, and interface declarations are collectively known as type declarations. Since these declarations belong to the same package, they are said to be defined at the top level, which is the package level.

The type declarations can be defined in any order. Technically, a source file need not have any such declarations, but that is hardly useful.

The JDK imposes the restriction that at most one public class declaration per source file can be defined. If a public class is defined, the file name must match this public class. For example, if the public class name is NewApp, the file name must be NewApp.java.

Classes are discussed in §3.1, p. 99; interfaces are discussed in §5.6, p. 237; and enums are discussed in §5.13, p. 287.

Modules introduce another Java source file that contains a single module declaration (§19.3, p. 1168).

Note that except for the package and the import statements, all code is encapsulated in classes, interfaces, enums, and records. No such restriction applies to comments and whitespace.

Figure 6.1 Java Source File Structure

6.3 Packages

A package in Java is an encapsulation mechanism that can be used to group related classes, interfaces, enums, and records.

Figure 6.2 shows an example of a package hierarchy comprising a package called wizard that contains two other packages: pandorasbox and spells. The package pandorasbox has a class called Clown that implements an interface called Magic, also found in the same package. In addition, the package pandorasbox has a class called LovePotion and a subpackage called artifacts containing a class called Ailment. The package spells has two classes: Baldness and LovePotion. The class Baldness is a subclass of class Ailment found in the subpackage artifacts in the package pandorasbox.

The dot (.) notation is used to uniquely identify package members in the package hierarchy. The class wizard.pandorasbox.LovePotion, for example, is different from the class wizard.spells.LovePotion. The Ailment class can be easily identified by the name wizard.pandorasbox.artifacts.Ailment, which is known as the fully qualified name of the type. Note that the fully qualified name of the type in a named package comprises the fully qualified name of the package and the simple name of the type. The simple type name Ailment and the fully qualified package name wizard.pandorasbox.artifacts together define the fully qualified type name wizard.pandorasbox.artifacts.Ailment.

Java programming environments usually map the fully qualified name of packages to the underlying (hierarchical) file system. For example, on a Unix system, the class file LovePotion.class corresponding to the fully qualified name wizard.pandorasbox.LovePotion would be found under the directory wizard/pandorasbox.

Figure 6.2 Package Structure

Conventionally, the reverse DNS (Domain Name System) notation based on the Internet domain names is used to uniquely identify packages. If the package wizard was implemented by a company called Sorcerers Limited that owns the domain sorcerersltd.com, its fully qualified name would be

com.sorcerersltd.wizard

Because domain names are unique, packages with this naming scheme are globally identifiable. It is not advisable to use the top-level package names java and sun, as these are reserved for the Java designers.

Note that each component of a package name must be a legal Java identifier. The following package would be illegal:

org.covid-19.2022.vaccine

The package name below is legal:

org.covid_19._2022.vaccine

A subpackage would be located in a subdirectory of the directory corresponding to its parent package. Apart from this locational relationship, a subpackage is an independent package with no other relation to its parent package. The subpackage wizard.pandorasbox.artifacts could easily have been placed elsewhere, as long as it was uniquely identified. Subpackages in a package do not affect the accessibility of the other package members. For all intents and purposes, subpackages are more an organizational feature than a language feature. Accessibility of members defined in type declarations is discussed in §6.5, p. 345.

Posted on Leave a comment

The java.lang.Exception Class – Exception Handling

The java.lang.Exception Class

The class Exception represents exceptions that a program would normally want to catch. Its subclass java.lang.RuntimeException represents many common programming errors that can manifest at runtime (see the next subsection). Other subclasses of the Exception class, excluding the RuntimeException class, define what are known as checked exceptions (p. 374) that particularly aid in building robust programs. Some common checked exceptions are presented below.

Click here to view code image

java.lang.ClassNotFoundException

The class ClassNotFoundException is a subclass of the Exception class that signals that the JVM tried to load a class by its string name, but the class could not be found. A typical example of this situation is when the class name is misspelled while starting program execution with the java command. The source in this case is the JVM throwing the exception to signal that the class cannot be found.

java.io.IOException

The class IOException is a subclass of the Exception class that represents I/O-related exceptions that are found in the java.io package (EOFException, FileNotFound-Exception, NotSerializableException). Chapter 20, p. 1231, and Chapter 21, p. 1285, provide ample examples of contexts in which I/O-related exceptions can occur.

java.io.EOFException

The class EOFException is a subclass of the IOException class that represents an exception that signals that an end of file (EOF) or end of stream was reached unexpectedly when more input was expected—that is, there is no more input available. Typically, this situation occurs when an attempt is made to read input from a file when all data from the file has already been read, often referred to as reading past EOF.

Click here to view code image

java.io.FileNotFoundException

The class FileNotFoundException is a subclass of the IOException class that represents an exception that signals an attempt to open a file by using a specific pathname failed—in other words, the file with the specified pathname does not exist. This exception can also occur when an I/O operation does not have the required permissions for accessing the file.

Click here to view code image

java.io.NotSerializableException

The class NotSerializableException is a subclass of the IOException class that represents an exception that signals that an object does not implement the Serializable interface that is required in order for the object to be serialized (§20.5, p. 1261).

java.sql.SQLException

The class SQLException is a subclass of the Exception class that represents an exception that can provide information about various database-related errors that can occur. Chapter 24 provides examples illustrating such situations.

java.text.ParseException

The class ParseException is a subclass of the Exception class that represents an exception that signals unexpected errors while parsing. Examples of parsing date, number, and currency where this exception is thrown can be found in §18.5, p. 1116.

Posted on Leave a comment

Exception Handling: try, catch, and finally – Exception Handling

7.3 Exception Handling: try, catch, and finally

The mechanism for handling exceptions is embedded in the try-catch-finally construct, which has the following basic form:

Click here to view code image

try {                                // try block
statements
} catch (
exception_type
1
parameter
1
) {      // uni-catch clause
statements

}

  catch (
exception_type
n
parameter
n
) {      // uni-catch clause
 
statements
} finally {                          // finally clause
statements

}

A few aspects about the syntax of this construct should be noted. For each try block, there can be zero or more catch clauses (i.e., it can have multiple catch clauses), but only one finally clause. The catch clauses and the finally clause must always appear in conjunction with a try block, and in the right order. A try block must be followed by at least one catch clause, or a finally clause must be specified—in contrast to the try-with-resources statement where neither a catch nor a finally clause is mandatory (p. 407). In addition to the try block, each catch clause and the finally clause specify a block, { }. The block notation is mandatory.

Exceptions thrown during execution of the try block can be caught and handled in a catch clause. Each catch clause defines an exception handler. The header of the catch clause specifies exactly one exception parameter. The exception type must be of the Throwable class or one of its subclasses; otherwise, the code will not compile. The type of the exception parameter of a catch clause is specified by a single exception type in the syntax shown earlier, and such a catch clause is called a uni-catch clause.

A finally clause is always executed, regardless of the cause of exit from the try block, or whether any catch clause was executed at all. The two exceptions to this scenario are if the JVM crashes or the System.exit() method is called. Figure 7.4 shows three typical scenarios of control flow through the try-catch-finally construct.

Figure 7.4 The try-catch-finally Construct

The try block, the catch clause, and the finally clause of a try-catch-finally construct can contain arbitrary code, which means that a try-catch-finally construct can be nested in any block of the try-catch-finally construct. However, such nesting can easily make the code difficult to read and is best avoided, if possible.

Posted on Leave a comment

The throw Statement – Exception Handling

7.4 The throw Statement

Earlier examples in this chapter have shown how an exception can be thrown implicitly by the JVM during execution. Now we look at how an application can programmatically throw an exception using the throw statement. This statement can be used in a method, a constructor, or an initializer block. The general format of the throw statement is as follows:

Click here to view code image

throw
object_reference_expression
;

The compiler ensures that the type of the object reference expression is a Throwable or one of its subclasses. This ensures that a Throwable will always be propagated. At runtime a NullPointerException is thrown by the JVM if the object reference expression evaluates to null.

A detail message is often passed to the constructor when the exception object is created.

Click here to view code image

throw new ArithmeticException(“Integer division by 0”);

Propagation of a programmatically thrown exception is no different from one thrown implicitly by the JVM. When an exception is thrown, normal execution is suspended. The JVM proceeds to find a catch clause that can handle the exception.

The search starts in the context of the current try block, propagating to any enclosing try blocks and through the JVM stack to find a handler for the exception. Any associated finally clause of a try block encountered along the search path is executed. If no handler is found, then the exception is dealt with by the default exception handler at the top level. If a handler is found, normal execution resumes after the code in its catch clause has been executed, barring any rethrowing of an exception.

In Example 7.7, an exception is thrown by the throw statement at (4) as the count value is 0. This exception is propagated to the printAverage() method, where it is caught and handled by the catch clause at (1). Note that the finally clause at (2) is executed, followed by the resumption of normal execution, as evident from the output of the print statement at (3).

Example 7.7 Throwing Exceptions Programmatically

Click here to view code image

public class Average7 {
  public static void main(String[] args) {
    printAverage(100, 0);            // Calling with 0 number of values.
  }
  public static void printAverage(int totalSum, int totalCount) {
    System.out.println(“Entering printAverage().”);
    try {
      int average = computeAverage(totalSum, totalCount);
      System.out.println(“Average = ” +
          totalSum + ” / ” + totalCount + ” = ” + average);
    } catch (ArithmeticException ae) {                             // (1)
      ae.printStackTrace();
      System.out.println(“Exception handled in printAverage().”);
    } finally {                                                    // (2)
      System.out.println(“Finally in printAverage().”);
    }
    System.out.println(“Exit printAverage().”);                    // (3)
  }
  public static int computeAverage(int sum, int count) {
    System.out.println(“Computing average.”);
    if (count == 0)
      throw new ArithmeticException(“Integer division by 0”);      // (4)
    return sum/count;
  }
}

Output from the program:

Click here to view code image

Entering printAverage().
Computing average.
java.lang.ArithmeticException: Integer division by 0
      at Average7.computeAverage(Average7.java:26)
      at Average7.printAverage(Average7.java:11)
      at Average7.main(Average7.java:5)
Exception handled in printAverage().
Finally in printAverage().
Exit printAverage().