General Stuff

// Point.java
public class Point {
	int x;
	int y;
	public Point(int x, int y) {
		this.x = x;
		this.y = y;
	}
}
// Shape.java
abstract class Shape implements GetAreable, Comparable { // comparable not actually implemented, just an example
	private int numAxesOfSymmetry;
 
	public boolean isSymmetric() {
		return numAxesOfSymmetry > 0;
	}
}
// Circle.java
public class Circle extends Shape {
	Point centre;
	int radius;
	public Circle(Point centre, int radius) {
		this.centre = centre;
		this.radius = radius;
	}
 
	@Override
	public double getArea() {
		return Math.PI * Math.pow(r, 2);
	}
	
	@Override
	public boolean equals(Object x) {
		return false;
	}
 
	public boolean equals(Circle c) {
		return this.centre.equals(c.centre) && this.radius == c.radius;
	}
}
// ColouredCircle.java
public class ColouredCircle extends Circle {
	String colour;
	public ColouredCircle(Point centre, int radius, String colour) {
		super(centre, radius);
		this.colour = colour;
	}
	
	@Override
	public boolean equals(ColouredCircle c) {
		return super.equals(c) && this.colour == c.colour;
	}
}
// GetAreable.java
public interface GetAreable {
	double getArea();
}
// Main.java
public class Main {
	public static void main(String[] args) {
		Point origin = new Point(0,0);
		Shape[] shapes = {
			new Circle(origin, 1), 
			new ColouredCircle(origin, 1, "green") }
		// or Shape[] shapes = new Shape[2] for empty array
		// shapes.length is the array length
		for (Shape shape : shapes) {
			System.out.println(shape.getArea());
		}
	}
}

Exceptions

// MyFileNotFoundException.java
// This is a checked exception, which means we have to handle it with a try catch, or declare it with a throws statement. It is checked at compile time.
// This is used when the exception is caused by something out of our control e.g. a file not existing, web request fail etc.
class MyFileNotFoundException extends Exception {
	public MyFileNotFoundException(String message) {
		super(message);
	}
 
	@Override
	public String getMessage() {
		return "File not found! Message: " + super.getMessage();
	}
}
// ArrayIndexException.java
// This is an unchecked exception, which means we do not need to handle it in the code.
// This is used for programmer error e.g. null pointer exception, array index out of bounds
class ArrayIndexException extends RuntimeException {
}
class Example {
	public String readFile(String path) throws MyFileNotFoundException {
		// ...
		throw new MyFileNotFoundException("file " + path + " not found!");
	}
 
	public String readFiles(String[] paths) {
		String result = "";
		for (String path : paths) {
			try {
				result += this.readFile(path)
			} catch (MyFileNotFoundException e) {
				System.out.println(e.getMessage());
			} finally {
				// this code is always run
				System.out.println("done with a file!");
			}
		}
	}
}

In CS2030S, we should always use a finally block

Generic Types

Generic Class

// Pair.java
public class Pair<S, T> { 
// convention: type parameters are single capital letters
	private S first;
	private T second;
 
	public Pair(S first, T second) {
		this.first = first;
		this.second = second;
	}
 
	public S getFirst() {
		return this.first;
	}
 
	public T getSecond() {
		return this.second;
	}
}
 
// note: generic types need to be reference types, not primatives
// does not work, int is not a reference type:
Pair<int, String> a = new Pair<int, String>(123, "Hello"); 
// works:
Pair<Integer, String> a = new Pair<Integer, String>(123, "Hello");
// syntax to use the type parameters of the variable:
Pair<Integer, String> a = new Pair<>(123, "Hello"); // <> diamond operator is equivalent to above
 
// Generic types can be bound, 
public class Pair<S extends Abc, T> {// ... }
// Abc can be a class or interface. This just means that S should be a subtype of Abc
// Multiple bounds
public class Pair<S extends Abc & Def, T> {// ... }

Generic Method

// Contains.java
public class Contains {
	public static <T> boolean contains(T[] items, T target) {
		for (T item : items) {
			if (item.equals(target)) {
				return true;
			}
		}
		return false;
	}
}
 
// application
Integer[] ints = new Integer[] {1,2,3};
Contains.<Integer>contains(ints, 2);

Generics cannot be used with arrays, due to type erasure

new Pair<String, Integer>[2]; // error
class Abc<S, T> {
	private S[] arr; // ok
	// ...
	new Pair<S, T>[2]; // error
	this.arr = new S[2]; // error
	this.arr = (S[]) new Object[2]; // ok, but produces warning
	// to suppress this warning:
	@SuppressWarnings("unchecked") // be careful of how items can be added to the array
	S[] a = (S[]) new Object[2];
	this.arr = a;
}

Wildcards

class Shape {}
class Circle extends Shape {}
 
class Container<T> {
	private T item;
 
	public Container(T item) {
		this.item = item;
	}
	
	public T get() {
	    return item;
	}
	
	public void set(T item) {
	    this.item = item;
	}
 
	// upper bound wildcard
	// we want to allow copying from a container that contains anything that is a subtype of T
	public void copyFrom(Container<? extends T> c) {
	    this.item = c.get();
	}
 
	// lower bound wildcard
	// we want to allow copying to a container that contains anything that is a supertype of T
	public void copyTo(Container<? super T> c) {
	    c.set(this.item);
	}
}
 
// demo
Shape s = new Shape();
Circle c = new Circle();
        
Container<Shape> sc = new Container<>(s);
Container<Circle> cc = new Container<>(c);
        
sc.copyFrom(cc); // ok
cc.copyFrom(sc); // error
        
cc.copyTo(sc); // ok
sc.copyTo(cc); // error
@SuppressWarnings("unchecked")
Queue<Passenger>[] q = (Queue<Passenger>[]) new Queue<?>[nStops];
this.queues = q; // Queue<Passenger> <: Queue<?>