Object Oriented Programming

Summary

Summary

Table of Contents

Compiling and running

# compile
$ javac HelloWorld.java
# compiler outputs HelloWorld.class
# run (no extension)
$ java HelloWorld

Java features

  1. compiled and interpreted
  2. platform independent
  3. object oriented

java_compiled_and_interpreted

Java Identifiers

Classes

Wrapper classes

Object Oriented Features

Static Members

Mutability

Standard Methods

Visibility Modifiers

Modifier Class Package Subclass Outside
public Y Y Y Y
protected Y Y Y N
default Y Y N N
private Y N N N

Motivation for Inheritance and Polymorphism

Inheritance

public class Subclass extends Superclass { ... }

Access control

new Rook() instanceof Piece;     // true
new Piece() instanceof Rook;     // false

Abstract vs Concrete classes

Object class

Interfaces

public interface Printable {
    int MAXIMUM_PIXEL_DENSITY = 1000;
    void print();
}
public class Image implements Printable {
    public void print() { ... }
}

public class Spreadsheet implements Printable {
    public void print() { ... }
}
public interface Printable {
    default void print() {
        System.out.println(this.toString()); 
    }
}
public interface Digitisable extends Printable {
    public void digitise();
}
public class Spreadsheet extends Document implements Printable, Colourable, Filterable,
  Comparable<Spreadsheet> {
    public void print() { ... } 
    ...
}

Sorting

Inheritance vs Interfaces

Polymorphism

Generics

T item = new T(); // <- cannot do this!
T[] elements = new T[];     // <- cannot do this!
public class Sample<T> {
    private T data;
    
    public void setData(T data) {
        this.data = data;
    }
    
    public T getData() {
        return data;
    }
}

Tuple

From Thinking in Java

public class TwoTuple<A, B> {
    public final A first;
    public final B second;
    
    public TwoTypePair(A first, B second) {
        this.first = first;
        this.second = second;
    }
    
    @Override
    public String toString() {
        return "(" + first + ", " + second ")";
    }
}

Usage:

public class TwoTupleDemo {
    public static void main(String[] args) {
        TwoTuple<String, Integer> rating = new TwoTuple<String, Integer>("The Car Guys", 8);
        System.out.println(rating);
    }
}

Subtyping

ArrayList<String> arrayListStr = new ArrayList<String>();
List<String> listStr = arrayListStr;
List<?> listUnknown = new ArrayList<A>(); // unknown wildcard
List<? extends A> listUnknown = new ArrayList<A>(); // extends wildcard
List<? super A> listUnknown = new ArrayList<A>();   // super wildcard
public void insert(List<? super Animal> myList) {
    myList.add(new Dog());
    myList.add(newBear());
}

List<Animal> animals = new ArrayList<Animal>();
insert(animals);
Object o = animals.get(0);  // upcast to object. Works
Animal a = animals.get(0);  // downcast to animal; error as list could be of type that is
                            // superclass of animal
  
List<Object> objects = new ArrayList<Object>(); 
insert(objects);    // this is fine.  Object is a superclass of Animal

Generic Methods

public <T> int genericMethod(T arg);        // generic argument
public <T> T genericMethod(String name);    // generic return value
public <T> T genericMethod(T arg);          // generic arg + return val
public <T,S> T genericMethod(S arg);        // generic arg + return val

Collections

Common Operations

Hierarchy

java_collections

ArrayList

Comparator

Maps

Common operations

Hierarchy

java_map

Use of HashMap

import java.util.HashMap;

public static void main(String[] args) {
    HashMap<String,Book> library = new HashMap<>();
    Book b1 = new Book("JRR Tolkien", "The Lord of the Rings", 1178);
    Book b2 = new Book("George RR Martin", "A Game of Thrones", 694);
    library.put(b1.author, b1);
    library.put(b2.author, b2);
    
    for (String author: library.keySet()) {
        Book b = library.get(author);
        System.out.println(b);
    }
}

Sorting with Maps

Here’s an example of sorting a HashMap by value, in reverse order, and printing the result:

public class Program {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("orange", 1);
        map.put("potato", 2);
        map.put("banana", 5);
        map.put("pineapple", 4);
        map.put("apple", 3);
        map.put("blueberry", 6);

        map.entrySet()
                .stream()
                .sorted(Collections.reverseOrder(Map.Entry.comparingByValue()))
                .forEach(System.out::println);

    }
}

Output:

blueberry=6
banana=5
pineapple=4
apple=3
potato=2
orange=1

Here’s another example of taking a HashMap, sorting by value, then converting to a List:

Map<Integer, String> map = new HashMap<>();
map.put(624642, "Zelda");
map.put(4556, "Legend");
map.put(24624, "Of");
List<Map.Entry<Integer, String>> sortedEntries = map.entrySet().stream()
    .sorted((e1, e2) -> e1.getValue().compareTo(e2.getValue()))
    .collect(Collectors.toList());
System.out.println(sortedEntries);

This outputs:

[4556=Legend, 24624=Of, 624642=Zelda]

Exceptions

Errors

Protecting against runtime errors

try-catch statement

public void method(...) {
    try {
        // code to execute that may cause an exception
    } catch (<ExceptionClass> varName) {
        // code to execute to recover from exception/end gracefully
    } finally {
        // block of code that executes whether an exception occurred or not
    }
}

try-with

public void processFile(String filename) {
    try (BufferedReader reader = ...) {
        ...
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Chaining

public void processFile(String filename) {
    try {
        ...
    } catch (FileNotFoundException e) { // most specific exception
        e.printStackTrace();
    } catch (IOException e) {           // least specific exception
        e.printStackTrace();
    }
}

Generating exceptions

if (t == null) {
  throw new NullPointerException("t is null!");
}
class SimpleException extends Exception {}    // define a new exception extending Exception

public class InheritingExceptions {
    public void f() throws SimpleException {
        System.out.println("Throw SimpleException from f()");
        throw new SimpleException();
    }
    
    public static void main(String[] args) {
        InheritingExceptions sed = new InheritingExceptions();
        try {
            sed.f();
        } catch (SimpleException e) {
            System.out.println("Caught SimpleException!");
        }
    }
}

Types of Exceptions

Design Patterns

Classes of Patterns

Singleton Pattern

singleton

class Singleton {
    private static Singleton _instance = null;
    private Singleton() {   // <- private constructor prevents instantiation except by class itself
        ...
    }
    
    public static Singleton getInstance() {
        if (_instance == null) {
            _instance = new Singleton();
        }
        return _instance;
    }
}

// Collaboration
class TestSingleton {
    public void method1() {
        X = Singleton.getInstance();
    }
    
    public void method2() {
        Y = Singleton.getInstance();
    }
}

Template Method

template_method

bubble_sort

Strategy pattern

strategy_uml

strategy_pattern

Strategies for getting to the airport

Factory method

factory

factory_eg

Observer pattern

observer

Software Design

Javadocs

Code Smells

GRASP

Testing

JUnit testing

import static org.junit.Assert.*;
import org.junit.Test;

public class BoardTest {
    @Test
    public void testBoard() {
        Board board = new Board();
        assertEquals(board.cellIsEmpty(0, 0), true);
    }
    
    @Test
    public void testValidMove() {
        Board board = new Board();
        Move move = new Move(0, 0);
        assertEquals(board.isValidMove(move), true);
    }
    
    @Test
    public void testMakeMove() {
        Board board = new Board();
        Player player = new HumanPlayer("R");
        Move move = new Move(0, 0);
        board.makeMove(player, move);
        assertEquals(board.getBoard()[move.row][move.col], "r");
    }
}
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;

public class TestRunner {
    public static void main(String[] args) {
        Result result = JUnitCore.runClasses(BoardTest.class);
        for (Failure failure : result.getFailures()) {
            System.out.println(failure.toString());
        }
        System.out.println(result.wasSuccessful());
    }
}

Event Programming

Composition over inheritance

composition-vs-inheritance

Enumerated types

public enum Suit {
    SPADES(Colour.BLACK),
    CLUBS(Colour.BLACK),
    DIAMONDS(Colour.RED),
    HEARTS(Colour.RED);

    private Colour colour;
    private Suit(Colour colour) {
        this.colour = colour;
    }
}

Variadic Parameters

public String concatenate(String... strings) {
    String string= "";
    for (String s : strings) {
        string += s;
    }
    return string;
}

Functional interface

Predicate

public interface Predicate<T>

Unary operator

public interface UnaryOperator<T>

Lambda expressions

Predicate<Integer> p = i -> i > 0;  // very compact way to define function

Syntax:

(sourceVar1, sourceVar2, ...) -> <operation on source variables>

Method References

UnaryOperator<String> operator = s -> s.toLowerCase();
UnaryOperator<String> operator = String::toLowerCase;

Streams

e.g.

String output = people.stream() 
                        .filter(p -> p.getAge() >= 18)
                        .filter(p -> p.getAge() <= 40)
                        .map(Person::getName)
                        .map(string::toUpperCase)
                        .collect(Collectors.joining(", "));

Scanner

import java.util.Scanner;

public class ScannerProgram {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);  // create Scanner reading from System.in
        System.out.println("Enter your input: ");
        while (scanner.hasNextLine()) {     // while there are more lines to read
            String s = scanner.nextLine();  // read the next line
            System.out.println(s);
        }
    }
}

Reading files

import java.io.FileReader;      // low level file for simple character reading
import java.io.BufferedReader;  // higher level file object that reads Strings
import java.io.IOException;     // handle exceptions

public class ReadFile {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
            String text;
            while ((text = br.readLine()) != null) {
                // do stuff with text
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Packages

Defining a package

First statement in class as follows:

package <directory_name_1>.<directory_name_2>;

Using packages

import <packageName>.*;  // import all classes in package
import <packageName>.<className>; // import particular class

Default package


Edit this page.