On this page:
24.1 Two Ideas:   Java and Types
24.2 Programming in Java
24.2.1 Java Syntax
24.3 Running Java Programs
24.4 A More Complex Example
24.5 Recursive Unions
24.6 Enumerations
24.7 Parameterized Data Definitions
24.8 Abstraction
5.92

24 Java

24.1 Two Ideas: Java and Types

Types are a mechanism for enforcing data definitions and contracts.

Java is a programming language like the one we’ve seen, with a different syntax and with types.

24.2 Programming in Java
24.2.1 Java Syntax
;; A C is (C Number String String)
(define-class C
  (fields x y z)
  ;; Number Number -> C
  (define (m p q)
    ...))

class C {

    Number x;

    String y;

    String z;

    public C m(Number p, Number q) {

        ...

    }

    public C(Number x, String y, String z) {

        this.x = x;

        this.y = y;

        this.z = z;

    }

}

Let’s create a simple pair of numbers:

class Pair {

    Number left;

    Number right;

 

    public Pair(Number left, Number right) {

        this.left = left;

        this.right = right;

    }

 

    public Pair swap() {

        return new Pair(this.right, this.left);

    }

}

But really, this doesn’t work, because Java doesn’t have the type Number. So we’ll choose Integer instead.

class Pair {

    Integer left;

    Integer right;

 

    public Pair(Integer left, Integer right) {

        this.left = left;

        this.right = right;

    }

 

    public Pair swap() {

        return new Pair(this.right, this.left);

    }

}

To test this, we’ll import a testing library:

import tester.Tester;

and write some examples:

class Examples {

    public Examples() {}

    public boolean testSwap(Tester t) {

        return t.checkExpect(new Pair(3,4).swap(),

                             new Pair(4,3));

    }

}

24.3 Running Java Programs

We don’t have a Run button in Java, so we need a different way to run our program. To do this, we first need to install our test library. This requires installing a JAR file from the NU Tester web site.

The we have to compile the program.

24.4 A More Complex Example

What if we want to represent a union?

class Square {

    Integer size;

    public Square(Integer size) {

        this.size = size;

    }

}

class Circ {

    Integer radius;

    public Circ(Integer radius) {

        this.radius = radius;

    }

}

How do we declare that both of these are Shapes?

import tester.Tester;

 

interface IShape {}

 

class Square implements IShape {

    Integer size;

    public Square(Integer size) {

        this.size = size;

    }

    public IShape nothing(IShape i) {

        return i;

    }

}

 

class Circ implements IShape {

    Integer radius;

    public Circ(Integer radius) {

        this.radius = radius;

    }

}

 

class Examples {

    Examples () {}

    public boolean testNothing(Tester t) {

        Square s = new Square(5); // A local binding

        return t.checkExpect(s.nothing(new Circ(2)),

                             new Circ(2));

    }

}

 

24.5 Recursive Unions

import tester.Tester;

class Mt implements IList {

    public Mt() {}

}

 

class Cons implements IList {

    Integer first;

    IList rest;

 

    public Cons(Integer first, IList rest) {

        this.first = first;

        this.rest = rest;

    }

}

 

interface IList {}

 

class Examples {

    public Examples() {}

 

    public boolean testList(Tester t) {

        return t.checkExpect(new Mt(), new Mt())

            && t.checkExpect(new Cons(5, new Mt()), new Cons(5, new Mt()));

    }

}

 

24.6 Enumerations

In Fundies I, we might have written:

;; A Title is one of
;; - 'dr
;; - 'mr
;; - 'ms

In Java, we write:

interface ITitle {}

class Dr implements ITitle {

    Dr() {}

}

class Mr implements ITitle {

    Mr() {}

}

class Ms implements ITitle {

    Ms() {}

}

Why write these silly constructors?

interface ITitle {}

class Dr implements ITitle {

    Dr() {}

}

class Mr implements ITitle {

    Mr() {}

}

class Ms implements ITitle {

    Integer x;

    Ms() {}

 

    public Integer m() {

        return x+1;

    }

}

 

class Main {

    public static void main(String[] args) {

        new Ms().m();

        return;

    }

}

Now we get a NullPointerException. But what is that?

A discussion of the evils of null.

For example, this compiles:

interface ITitle {}

class Dr implements ITitle {

    Dr() {}

}

class Mr implements ITitle {

    Mr() {}

}

class Ms implements ITitle {

    Integer x;

    Ms(Integer x) {

        this.x = x;

    }

 

    public Integer m() {

        return null;

    }

}

 

class Main {

    public static void main(String[] args) {

        new Ms().m();

        return;

    }

}

Never write null in your program!

A long sermon on null.

24.7 Parameterized Data Definitions

Consider our Pair class:

class Pair {

    Integer left;

    Integer right;

 

    public Pair(Integer left, Integer right) {

        this.left = left;

        this.right = right;

    }

 

    public Pair swap() {

        return new Pair(this.right, this.left);

    }

}

Now if we want a Pair of Strings:

class PairString {

    String left;

    String right;

 

    public Pair(String left, String right) {

        this.left = left;

        this.right = right;

    }

 

    public Pair swap() {

        return new Pair(this.right, this.left);

    }

}

This is obviously bad—we had to copy and paste. So let’s abstract:

class Pair<T,V> {

    T left;

    V right;

 

    public Pair(T left, V right) {

        this.left = left;

        this.right = right;

    }

 

    public Pair<V,T> swap() {

        return new Pair<V,T>(this.right, this.left);

    }

}

 

class Examples {

    public Examples() {}

    public boolean testSwap(Tester t) {

        return t.checkExpect(new Pair<Integer,Integer>(3,4).swap(),

                             new Pair<Integer,Integer>(4,3));

    }

}

 

24.8 Abstraction

 

class C {

    Integer x;

    Integer y;

    C(Integer x, Integer y) {

        this.x = x;

        this.y = y;

    }

 

    public Integer sq() {

        return this.x * this.x;

    }

}

 

 

class D {

    Integer x;

    String z;

    D(Integer x, String z) {

        this.x = x;

        this.z = z;

    }

 

    public Integer sq() {

        return this.x * this.x;

    }

}

 

Now to abstract:

 

class S {

    Integer x;

    public Integer sq() {

        return this.x * this.x;

    }

    S(Integer x) {

        this.x = x;

    }

}

 

class C extends S {

    Integer y;

    C(Integer x, Integer y) {

        super(x);

        this.y = y;

    }

}

 

 

class D {

    Integer x;

    String z;

    D(Integer x, String z) {

        this.x = x;

        this.z = z;

    }

 

    public Integer sq() {

        return this.x * this.x;

    }

}