Fading Coder

One Final Commit for the Last Sprint

Home > Notes > Content

Java Tutorial: Generics, Packages, and Exceptions

Notes May 2 11

Generics

Generics provide a way to create classes, interfaces, and methods that operate on types while providing compile-time type safety. They allow you to write reusable code that can work with different data types.

Questions and Exercises

  1. Write a generic method to count elements in a collection that have a specific property (e.g., odd numbers, prime numbers, palindromes).

    public static <T> int countElements(Collection<T> collection, Predicate<T> predicate) {
        int count = 0;
        for (T element : collection) {
            if (predicate.test(element)) {
                count++;
            }
        }
        return count;
    }
    
  2. Will the following class compile? If not, why?

    public final class Algorithm {
        public static <T> T max(T x, T y) {
            return x > y ? x : y;
        }
    }
    

    No, it won't compile because the > operator cannot be used with generic types. You need to restrict T to a type that implements Comparable.

  3. Write a generic method to swap two distinct elements in an array.

    public static <T> void swap(T[] array, int index1, int index2) {
        T temp = array[index1];
        array[index1] = array[index2];
        array[index2] = temp;
    }
    
  4. If the compiler erases all type parameters at compile time, why should you use generics?

    Generics provide compile-time type safety, allowing you to catch type errors early and write more robust code.

  5. What is the class converted to after type erasure?

    public class Pair<K, V> {
        private K key;
        private V value;
        // constructors, getters, setters
    }
    

    After type erasure, it becomes:

    public class Pair {
        private Object key;
        private Object value;
        // constructors, getters, setters
    }
    
  6. What is the method converted to after type erasure?

    public static <T extends Comparable<T>> int findFirstGreaterThan(T[] at, T elem) {
        // implementation
    }
    

    After type erasure:

    public static int findFirstGreaterThan(Comparable[] at, Comparable elem) {
        // implementation
    }
    
  7. Will the following method compile? If not, why?

    public static void print(List<? extends Number> list) {
        for (Number n : list)
            System.out.print(n + " ");
        System.out.println();
    }
    

    Yes, it will compile. The wildcard ? extends Number allows reading from the list.

  8. Write a generic method to find the maximum element in a list range [begin, end).

    public static <T extends Comparable<T>> T findMax(List<T> list, int begin, int end) {
        T max = list.get(begin);
        for (int i = begin + 1; i < end; i++) {
            if (list.get(i).compareTo(max) > 0) {
                max = list.get(i);
            }
        }
        return max;
    }
    
  9. Will the following class compile? If not, why?

    public class Singleton<T> {
        private static T instance = null;
        public static T getInstance() {
            if (instance == null)
                instance = new Singleton<T>();
            return instance;
        }
    }
    

    No, it won't compile because you cannot create a new instance of a generic type T directly. You need to use reflection or a factory method.

  10. Given the following classes:

    class Shape { /* ... */ }
    class Circle extends Shape { /* ... */ }
    class Rectangle extends Shape { /* ... */ }
    
    class Node<T> { /* ... */ }
    

    Will the following code compile? If not, why?

    Node<Circle> nc = new Node<>();
    Node<Shape> ns = nc;
    

    No, it won't compile because generics are invariant. You cannot assign a Node<Circle> to a Node<Shape>.

  11. Consider this class:

    class Node<T> implements Comparable<T> {
        public int compareTo(T obj) { /* ... */ }
    }
    

    Will the following code compile? If not, why?

    Node<String> node = new Node<>();
    Comparable<String> comp = node;
    

    Yes, it will compile because Node<String> implements Comparable<String>.

  12. How would you call the following method to find the first integer in a list that is coprime with a specified list of integers?

    public static <T> int findFirst(List<T> list, int begin, int end, UnaryPredicate<T> p)
    

    You would implement a UnaryPredicate that checks if two integers are coprime and pass it to the method.

Packages

Packages are used to organize classes and interfaces into namespaces, avoiding naming conflicts and controlling access. They provide a way to group related types together.

Creating and Using Packages

To create a package, add a package statement at the top of your source file:

package com.example.graphics;

Place your source files in a directory structure that matches the package name. For example, if your package is com.example.graphics, your files should be in com/example/graphics/.

Package Naming

Package names should be in lowercase and typically use a reversed domain name as a prefix, e.g., com.example.mypackage.

Using Package Members

To use classes from other packages, you can either use the fully qualified name or import the class:

// Using fully qualified name
com.example.graphics.Rectangle rect = new com.example.graphics.Rectangle();

// Importing the class
import com.example.graphics.Rectangle;
Rectangle rect = new Rectangle();

You can also import an entire package:

import com.example.graphics.*;

Managing Source Files and Class Files

Source files should be organized in directories matching the package structure. Class files should be placed in a similar structure, and the classpath should be set to include these directories.

Questions and Exercises

  1. What line of code do you need to add to each source file to place each class in the correct package?

    Add a package statement at the top of each file, e.g., package mygame.server;.

  2. What subdirectories do you need to create in your development directory, and where should each source file be placed?

    Create subdirectories mygame/server, mygame/shared, and mygame/client. Place Server.java in mygame/server, Utilities.java in mygame/shared, and Client.java in mygame/client.

  3. Do you think you need to make any other changes to the source files to compile them correctly?

    No, as long as the package statements and directory structure are correct, the files should compile.

Exceptions

Exceptions are events that disrupt the normal flow of a program. Java provides a robust exception handling mechanism to manage errors and other exceptional situations.

What is an Exception?

An exception is an event that occurs during the execution of a program that disrupts the normal flow of instructions. When an exception occurs, an object is created and thrown to the runtime system.

Catching or Declaring Exceptions

Methods that can throw checked exceptions must either catch them or declare them in a throws clause.

Catching and Handling Exceptions

Use try-catch blocks to handle exceptions:

try {
    // code that might throw an exception
} catch (ExceptionType e) {
    // handle the exception
} finally {
    // cleanup code
}

Try-with-Resources Statement

The try-with-resources statement ensures that resources are closed automatically:

try (FileReader fr = new FileReader("file.txt");
     BufferedReader br = new BufferedReader(fr)) {
    // use the resource
}

Questions and Exercises

  1. Is the following code legal?

    try {
    } finally {
    }
    

    Yes, it is legal. The try block is empty, but the finally block will always execute.

  2. What types of exceptions can the following handler catch? What is the problem with using this type of exception handler?

    catch (Exception e) {
    }
    

    It can catch any exception, but it's too broad and can hide specific exceptions.

  3. What is wrong with the following exception handler? Will this code compile?

    try {
    } catch (Exception e) {
    } catch (ArithmeticException a) {
    }
    

    The code will not compile because the more specific catch block (ArithmeticException) must come before the more general one (Exception).

  4. Match each situation in the first list with an item in the second list.

    1. int[] A; A[0] = 0;
    2. JVM starts running your program but cannot find Java platform classes.
    3. A program is reading a stream and reaches the end-of-stream marker.
    4. A program tries to read a stream again before closing it and after reaching the end-of-stream marker.
    5. Error
    6. Checked exception
    7. Compile error
    8. No exception

    1. Compile error
    2. Error
    3. No exception
    4. Checked exception

Basic I/O

Java provides classes for performing input and output operations. I/O streams represent sources and destinations of data.

Byte Streams

Byte streams handle raw binary data. Use InputStream and OutputStream for byte-level operations.

try (FileInputStream in = new FileInputStream("input.txt");
     FileOutputStream out = new FileOutputStream("output.txt")) {
    int c;
    while ((c = in.read()) != -1) {
        out.write(c);
    }
}

Character Streams

Character streams handle text data, automatically converting between internal and local character sets.

try (FileReader reader = new FileReader("input.txt");
     FileWriter writer = new FileWriter("output.txt")) {
    int c;
    while ((c = reader.read()) != -1) {
        writer.write(c);
    }
}

Line-Oriented I/O

Use BufferedReader and PrintWriter for line-oriented input and output.

try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
     PrintWriter writer = new PrintWriter(new FileWriter("output.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        writer.println(line);
    }
}

Related Articles

Designing Alertmanager Templates for Prometheus Notifications

How to craft Alertmanager templates to format alert messages, improving clarity and presentation. Alertmanager uses Go’s text/template engine with additional helper functions. Alerting rules referenc...

Deploying a Maven Web Application to Tomcat 9 Using the Tomcat Manager

Tomcat 9 does not provide a dedicated Maven plugin. The Tomcat Manager interface, however, is backward-compatible, so the Tomcat 7 Maven Plugin can be used to deploy to Tomcat 9. This guide shows two...

Skipping Errors in MySQL Asynchronous Replication

When a replica halts because the SQL thread encounters an error, you can resume replication by skipping the problematic event(s). Two common approaches are available. Methods to Skip Errors 1) Skip a...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.