# Lec 04 - Exception and Wrapper Classes

Slides:

{% embed url="<https://nus-cs2030s.github.io/2425-s2/slides/cs2030s-lec04.html#1>" %}

## Wrapper Class

In the previous [lec](https://wenbo-notes.gitbook.io/cs2030s-notes/lec-rec-lab-exes/lecture/lec-03-polymorphism), we have introduced how to write general code on **reference type** by using *polymorphism*. Then, how about the **primitive type**? How do we write general code for the primitive type (a.k.a make primitive types less primitive)? Here it comes — The Wrapper class.

{% hint style="info" %}
Another reason to use *Wrapper Class* is that `int[]` **cannot** be converted to `Obj[]` automatically.
{% endhint %}

***

A *wrapper class* is a class that encapsulates a *type*. For example, the wrapper class for `int` is called `Integer`, for `double` is called `Double`, etc. The table for the wrapper class for all primitive types in Java is summarised as follows:

| Primitive | Wrapper     |
| --------- | ----------- |
| `byte`    | `Byte`      |
| `short`   | `Short`     |
| `int`     | `Integer`   |
| `long`    | `Long`      |
| `float`   | `Float`     |
| `double`  | `Double`    |
| `char`    | `Character` |
| `boolean` | `Boolean`   |

In particular, the wrapper class is considered as *reference type* and their instances can be created with `new` and stored on the **heap**.

{% hint style="info" %}
All primitive wrapper class objects are *immutable —* once you create an object, it cannot be changed. This will result that if we want to change the value of a Wrapper class object, we need to create a new object.
{% endhint %}

### Conversion between primitive types and its wrapper class

This is known as *auto-boxing* and *unboxing.*

{% stepper %}
{% step %}
**Auto-boxing**

This is used when you convert a primitive type to its wrapper class.

{% code lineNumbers="true" %}

```java
Integer i = 4;
```

{% endcode %}

Here, the primitive value of `int` 4 is converted into an *instance* of `Integer`.

{% hint style="info" %}
Auto-boxing **doesn't** work for complex types, like Array. So, Java cannot convert `int[]` to `Integer[]`.
{% endhint %}
{% endstep %}

{% step %}
**Unboxing**

This is used when you convert an *instance* of a wrapper class to its primitive type.

<pre class="language-java" data-line-numbers><code class="lang-java">Integer i = 4;
<strong>int j = i;
</strong></code></pre>

Line 2 converts an instance of `Integer` back to `int`.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
Both auto-boxing and unboxing are implemented automatically.
{% endhint %}

### Performance

For the sake of general code and polymorphism, why don't we use *wrapper class* all the time? The reason is **performance**. Using primitive types is **faster** than using its *wrapper class* since the latter needs to instantiate an object every time it is being used.

## Run-Time Class Mismatch

The main point of this part is about **when to use the explicit casting**?

***

**Explicit casting** is usually done during the *narrowing type conversion* process, this happens in **compile-time!** As the name suggests, the type must be "narrowed down". So,

> for an **explicit casting** to be successful, the two types must have a **subtype relationship**.

### Run-Time error or Compile-Time error?

When doing assignment, if the **compile-time type** of the two objects have **no** subtype relationship, then a **compile-time error** will be generated.

{% hint style="info" %}
Explicit Type casting using `()` will happen during the **compile-time**.
{% endhint %}

On the other hand, a **run-time error** will be generated when there is **no** subtype relationship between the **run-time** **type** of the two objects you are operating on.

{% hint style="info" %}
During run-time, we should **ignore** the type casting and only look at the RTT! See more [#id-03.-type-casting-and-rum-time-error](https://wenbo-notes.gitbook.io/cs2030s-notes/lec-rec-lab-exes/lecture/diagnostic-quiz#id-03.-type-casting-and-rum-time-error "mention")
{% endhint %}

## Variance

Till now, we have seen the **subtype relationship** on classes and interefaces, this is trivial. However, how about the *complex types* such as arrays? Seems that the subtype relationship is not that trivial. So, here it comes — the principle of *variance of types*:

> The *variance of types* refers to how the **subtype relationship** between *complex types* relates to the subtype relationship between [*components*](#user-content-fn-1)[^1].

### Variance of types

Let $$C(S)$$ correspond to some **complex type** based on type $$S$$, which means $$C(S)$$ is the type of the "array" and $$S$$ is the type of each element/component in the "array". We say a complex type is:

* *covariant:* which means if $$S<:T$$, then $$C(S)<:C(T)$$
* *contravariant:* which means if $$S<:T$$, then $$C(T)<:C(S)$$
* *invariant*: t is neither covariant nor contravariant

{% hint style="info" %}
Java Array is **covariant**.
{% endhint %}

## Exceptions

### `try`-`catch`-`finally` block

In Java, we use `try`-`catch`-`finally` block in our process to handle exceptions. Their usage is summarised as follows:

{% code lineNumbers="true" %}

```java
try {
  // do something
} catch (an exception parameter) {
  // handle exception
} finally {
  // clean up code
  // regardless of there is an exception or not
}
```

{% endcode %}

#### Compile-error in `catch` block

In the `catch` block, the first catch block that has an exception type compatible with the type of the thrown exception (i.e. a subtype) is selected to handle the exception. So, if there are **blocks that are unreachable,** a **compile error** will be generated! For example, the following code **will generate a compile error** (the second exception is the subclass of the first exception)

{% code lineNumbers="true" %}

```java
try {
    int result = 10 / 0; // Throws ArithmeticException
} catch (Exception e) {
    System.out.println("General exception: " + e);
} catch (ArithmeticException e) {
    System.out.println("Arithmetic error: " + e);
}
```

{% endcode %}

However, if we write the following code, it works fine,

{% code lineNumbers="true" %}

```java
try {
    // Code that might throw exceptions
    int[] arr = new int[2];
    arr[5] = 10; // ArrayIndexOutOfBoundsException
    int x = 10 / 0; // ArithmeticException
} catch (ArithmeticException e) {
    System.out.println("Arithmetic error");
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Array error");
}
```

{% endcode %}

{% hint style="warning" %}

#### Exceptions are **always** triggered at **run-time**.

For example, the following code **won't generate a compile error**, **but will generate a runtime error!**

{% code lineNumbers="true" %}

```java
int[] arr = new int[3]; // Array of size 3, valid indices: 0, 1, 2
arr[5] = 10; // Throws ArrayIndexOutOfBoundsException at runtime
```

{% endcode %}
{% endhint %}

### Throwing Exceptions

We can control our program to throw an exception when our program doesn't behave as we expect. To throw an exception, we need to:

1. use the keyword `throw` (not `throws`)
2. create a new exception object and throw it to the caller. (e.g. `IllegalArgumentException("radius cannot be negative.")`)

For example, the complete Java code should be as follows:

{% code lineNumbers="true" %}

```java
  if (r < 0) {
    throw new IllegalArgumentException("radius cannot be negative.");
  }
```

{% endcode %}

### Checked vs. Unchecked Exceptions

An *unchecked exception* is an exception caused by a programmer's errors. They should not happen if perfect code is written. `IllegalArgumentException`, `NullPointerException`, `ClassCastException` are examples of unchecked exceptions. Generally, unchecked exceptions are **not** explicitly caught or thrown. They indicate that something is wrong with the program and cause **run-time errors**.

A *checked exception* is an exception that a programmer has **no control** over. Even if the code written is perfect, such an exception might still happen. The programmer should thus actively anticipate the exception and handle them. For instance, when we open a file, we should anticipate that in some cases, the file cannot be opened. `FileNotFoundException` and `InputMismatchException` are two examples of is an example of a checked exception. A checked exception **must be** either **handled**, or else the program **will not compile**.

{% hint style="info" %}
In Java, unchecked exceptions are subclasses of the class `RuntimeException`.
{% endhint %}

#### Handle the exception

An unchecked exception, if not caught[^2], will propagate automatically down the stack until either it is caught or if it is not caught at all, resulting in an error message displayed to the user.

A checked exception, however, **must be handled**. And this is done by either handling it in the calling method, or handling it in the caller. Below is an example regarding handling the `FileNotFoundException`)

{% stepper %}
{% step %}
**Handle in the called method**

<pre class="language-java" data-line-numbers><code class="lang-java">class Main {
  static FileReader openFile(String filename) {
<strong>    try {
</strong>      return new FileReader(filename);
<strong>    } catch (FileNotFoundException e) {
</strong><strong>      System.err.println("Unable to open " + filename + " " + e);
</strong><strong>    }
</strong>  }
  public static void main(String[] args) {
    openFile();
  }
}
</code></pre>

{% hint style="info" %}
This means we will handle the exception in the method itself, thus it won't pass the exception to other methods, so we don't need to state that this method may throw an exception.
{% endhint %}
{% endstep %}

{% step %}
**Handle in the calling method**

<pre class="language-java" data-overflow="wrap" data-line-numbers><code class="lang-java">class Main {
<strong>  static FileReader openFile(String filename) throws FileNotFoundException {
</strong>    return new FileReader(filename);
  }
  public static void main(String[] args) {
<strong>    try {
</strong>      openFile();
<strong>    } catch (FileNotFoundException e) {
</strong><strong>      // warn user and pop up dialog box to select another file.
</strong><strong>    }
</strong>  }
}
</code></pre>

Line 2 is a **method declaration** which indicates that the method `openFile()` **may** throw a `FileNotFoundException`.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
*A good program always handles checked exception gracefully* and hides the details from the users.
{% endhint %}

### Control Flow of Exceptions

The use of Exceptions can affect the control flow of our program. For example, with the code following

{% code lineNumbers="true" %}

```java
try {
    m1();
} catch (E1 e) {
    :
} catch (E2 e) {
    :
} finally {
    :
}

void m1() {
    :
    m2();
    :
}

void m2() {
    :
    m3();
    :
}

void m3() {
    :
    m4();
    :
}

void m4() {
    :
    // throw new E2();
    :
}
```

{% endcode %}

Our normal control flow is as follows,

<figure><img src="https://3194032297-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fvwztj22G2t5iduk4o9yh%2Fuploads%2FGEbHwzk5FrySFMhdCkYV%2Fimage.png?alt=media&#x26;token=5f0f7402-1ded-415d-88ac-06081e211abb" alt=""><figcaption></figcaption></figure>

Then, what if we have thrown an exception `E2` inside the `m4()`? (We decomment the Line 31 in the code above). Then, our control flow will become:

<figure><img src="https://3194032297-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fvwztj22G2t5iduk4o9yh%2Fuploads%2F1NsLD6cmmQAuoNIOrggL%2Fimage.png?alt=media&#x26;token=4ad9bda1-8093-4135-9f6d-ff70540f58be" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Note that the `finally` block is always executed even when `return` or `throw` is called in a `catch` block.
{% endhint %}

### Good Practices for Exception Handling

#### Catch Exceptions to Clean Up <a href="#catch-exceptions-to-clean-up" id="catch-exceptions-to-clean-up"></a>

In the example, we may notice that if we have allocated some resources in `m2()` or `m3()`, they might not be deallocated because of the control flow of our exception handling.

So, it is recommended to handle the exception in the **called method** itself by using another `try-catch-finally` block. And if you still feel a need to pass the exception to the calling method, you can also do it by throwing this exception again in the `catch` block. For example,

{% code lineNumbers="true" %}

```java
public void m2() throws E2 {
  try {
    // setup resources
    m3();
  }
  catch (E2 e) {
    throw e;
  }
  finally {
    // clean up resources
  }
}
```

{% endcode %}

[^1]: or "elements", which is basically the "element" in the complex type. If you are from CS1010, which uses C as the teaching language, you should be fimilar with this notation of "element" :relaxed:.

[^2]: here "catch" means the exception being handled.
