Relevant Reading Material

Chapters From How to Design Classes (HtDC)

  • Chapter 12

  • Chapter 13

  • Chapter 14

  • Chapter 15

  • Chapter 16

  • Intermezzo 2

Single Responsibility

Recall from CS5001 our rule

One task one function

The rule is still relevant for Java

One task one method

We have another rule that refers to classes

One class one responsibility

After mapping our information to data and in Java’s case, classes we aim to add methods to our classes based on the responsibility that we have assigned to our class.

Let’s consider out code for Shapes again

shape responsibility

One way to implement moveX() in the concrete classes that implement Shape could be

// In Class Circle
public Shape moveX(Integer dx) {
    return new Circle(new Posn(this.pin.getX() + dx), this.pin.getY()), this.radius);
}

// In Class Square
public Shape moveX(Integer dx) {
    return new Square(new Posn(this.pin.getX() + dx), this.pin.getY()), this.side);
}

// In Class Rectangle
public Shape moveX(Integer dx) {
    return new Rectangle(new Posn(this.pin.getX() + dx), this.pin.getY()), this.width, this.height);
}

Observe

  • The code is very similar

  • The code is essentially updating a value, the x coordinate of Posn, inside a class that is not Posn.

Who is responsible for manipulating x and y?

Posn should be the entity responsible for updating any data that we captured as being part of Posn. Here is another implementation

//In Class Posn
public Posn moveX(Intefer dx) {
    return new Posn(this.x + dx, this.y);
}



// In Class Circle
public Shape moveX(Integer dx) {
    return new Circle(this.pin.moveX(dx), this.radius);
}

// In Class Square
public Shape moveX(Integer dx) {
    return new Square(this.pin.moveX(dx), this.side);
}

// In Class Rectangle
public Shape moveX(Integer dx) {
    return new Rectangle(this.pin.moveX(dx), this.width, this.height);
}

And here is the updated UML Class Diagram

shape corrected

The code is similar for moveY(). Now any class that contains a Posn can leverage our new methods.

Here is a new rule, the Law of Demeter [1]

Only talk to your friends

For a method m inside a class C your friends are

  1. fields defined/inherited in the class C

  2. arguments of m

  3. methods defined/inherited in C

  4. methods available on the arguments of m

  5. methods available on the fields inherited/defined in C

  6. local values created in the body of m

  7. methods available on local values created in the body of m

Design Recipe

  1. Data Analysis

    1. Data Examples

    2. Template

  2. Signature

  3. Purpose

  4. Examples

  5. Function Definition

  6. Tests

  7. Review

Nothing has changed about the Design Recipe. What has changed is the outcome of each step since we are now going to create Java programs instead of Racket programs.

Racket

design-recipe
;;;; Data Analysis and Definitions:
(define-struct student (last first teacher))
;; A student is a (make-student Symbol Symbol Symbol)
;; INTERP: represents a student's first and last name
;;         and the name of the their teacher

;;;; Data Examples:
;; (make-student 'Joe 'Doe 'Mary)
;; (make-student 'Mat 'Jones 'Fritz)

;;;; Template:
;; student-fn: Student -> ???
;; (define (student-fn a-student a-teacher)
;;   ... (student-last a-student) ...
;;   ... (student-first a-student) ...
;;   ... (student-teacher a-student) ...)



;;;; Signature: subst-teacher : Student Symbol -> Student

;;;; Purpose: to create a student structure with a new
;;;; teacher name if the teacher's name matches 'Fritz

;;;; Examples:
;; (subst-teacher (make-student 'Mat 'Jones 'Fritz) 'Elise)
;; =
;; (make-student 'Mat 'Jones 'Elise)
;; (subst-teacher (make-student 'Joe 'Doe 'Mary) 'Elise)
;; =
;; (make-student 'Joe 'Doe 'Mary)

;;;; Function Definition:
(define (subst-teacher a-student a-teacher)
  (cond
    [(symbol=? (student-teacher a-student) 'Fritz)
     (make-student (student-last a-student)
                   (student-first a-student)
                   a-teacher)]
    [else a-student]))

;;;; Tests:
(check-expect (subst-teacher (make-student 'Mat 'Jones 'Fritz) 'Elise)
              (make-student 'Mat 'Jones 'Elise))

(check-expect (subst-teacher (make-student 'Joe 'Doe 'Mary) 'Elise)
              (make-student 'Joe 'Doe 'Mary))

Java

Data Analysis

We are trying to map information to data. Instead of define-struct we are going to design Java classes. Create a UML class diagram to capture

  1. Java classes that you are going to create

  2. Fields for each class that you need

  3. Methods for each class that you need

  4. Dependencies between classes; arrows that show relationships between classes.

For example recall the Author example from Lab1

author

Data Examples

Java code that creates instance of your classes. This code ends up in your setup() method inside your Test class (e.g., AuthorTest, EmailTest, AddressTest).

Templates

The goal of the template it do decompose your data. At this point data in Java means a class. So we need a template for a class that, hopefully, all class methods can use as a starting point. The contents of the template is a list of operations and fields that we can rely on. It is in fact the same list as the list of "friends" as we have defined it for the Law of Demeter.

So lets take Author

author-template
public class Author {
    Person person;
    Email email;
    Address address;

    public Author(Person person, Email email, Address address) {
        this.person = person;
        this.email = email;
        this.address = address;
    }

    /**
      * Template for a no-argument method
      *

          ??? template() {

            ... this.person ...  // Person
            ... this.email  ...  // Email
            ... this.address ... // Address

            ... this.mmm() ...   // any method on `this`

            ... this.person.mmm() ...  // any public method on Person
            ... this.email.mmm() ...   // any public method on Email
            ... this.address.mmm() ... // any public method on Address

          }

      */

template() contains all the elements (fields and methods) that we can access.

Observer that the template above does not include equals(Object o). The template that we have above concerns only the Author class. This template has higher chances of being used for methods that do not take any argument.

We write a different template for every possible combination of argument types e.g.,

author-template-arg
public class Author {
    Person person;
    Email email;
    Address address;

    public Author(Person person, Email email, Address address) {
        this.person = person;
        this.email = email;
        this.address = address;
    }

    /**
      * Template
      *

          ??? template() {

            ... this.person ...
            ... this.email  ...
            ... this.address ...

            ... this.hashcode() ...
            ... this.toString() ...

          }


          ??? template(Author a) {

            ... this.person ...  // Person
            ... this.email  ...  // Email
            ... this.address ... // Address

            ... this.mmm() ...   // any method on `this`

            ... this.person.mmm() ...  // any public method on Person
            ... this.email.mmm() ...   // any public method on Email
            ... this.address.mmm() ... // any public method on Address

            ... a.mmm() ...    // any method on Author
        }

          ??? template(Email e) {

            ... this.person ...  // Person
            ... this.email  ...  // Email
            ... this.address ... // Address

            ... this.mmm() ...   // any method on `this`

            ... this.person.mmm() ...  // any public method on Person
            ... this.email.mmm() ...   // any public method on Email
            ... this.address.mmm() ... // any public method on Address

            ... e.mmm() ...    // any public method on Email
        }
        **/
}

Observe that template(Author a) can call any method on a because we are still within Author and have access to all (private, public and protected) fields and methods.

The third template template(Email e) can only call public methods on e which is of type Email.

We write a template for each combination of list of argument types that we plan to use in order to implement a method in our class.

Signature

The signature that we used to write for each Racket function is now embedded into the method signature for Java. The types that we have to include as part of the Java method’s signature are essentially the signature that we used to write as comments in Racket.

Racket style signatures added as Java comments.
public class MyInt {

  private Integer val;

  public MyInt(Integer val) {
    this.val = val;
  }

  // signature : getVal() :  -> Integer
  public Integer getVal() {
    return this.val;
  }

 // signature : greaterThan: Integer -> Boolean
  public Boolean greaterThan(Integer other) {
    return this.val > other.getVal();
  }

We do have to remember however that Java methods are inside a class and we always has access to the this class. In Racket we had to pass a value of our struct as an argument, in Java we are already inside the instance of the class.

Another way to visualizing this property is to assume an invinisble first argument that has the type of the class that defines this method and it is called this and that Java auto-populates each call with the right object for the first argument called this.

e.g.,

Incorrect Java showing how we can view this as an argument to each method.
public class MyInt {

  private Integer val;

  public MyInt(MyInt this, Integer val) {
    this.val = val;
  }

  // signature : getVal() : MyInt  -> Integer
  public Integer getVal(MyInt this) {
    return this.val;
  }

 // signature : greaterThan: MyInt Integer -> Boolean
  public Boolean greaterThan(MyInt this, Integer other) {
    return this.val > other.getVal();
  }

Purpose

Similar to Racket only in Java we need to write our purpose using Javadoc, which means that we have

  1. A one sentence description of what this method does.

  2. Any WHERE clauses that the method requires

  3. Any INVARIANTS, HALTING MEASURES, TERMINATION ARGUMENTS that the method requires

  4. A one line comment for each formal argument using @param

  5. A one line comment explaining the method’s return value using @return.

Examples

Examples in Java are written as part of the Javadoc comment for the method so that when we generate our documentation and provide it to clients they will have example uses for each method.

Function Definition (now Method Definition)

The name is misleading for Java since we do not have function but methods. So we will rename this step to Method Definition.

Tests

In Java our tests are found in a companion JUnit class. Instead of check-expect and its variants we use the JUnit Assert class along with its assertion methods.

Review

This step is the same. Go back and review each step of the Design Recipe.

UML Sequence Diagrams

UML Sequence Diagrams are used to model the flow of execution within your system. Sequence Diagrams are typically used to model:

  1. Usage scenarios. A sequence of operations that your code goes through.

  2. The logic of methods. Designate the steps taken during the excution of a method including the objects called, arguments passed etc.

  3. The logic of a component/service. Similar to methods but the entities used can be a component, a web service etc.

We will mostly use Sequence Diagrams to show the exectuion of our methods.

Consider the addition of the following method in Author

    ...

    /**
     * Return the author's first name
     *
     * @return the author's first name
     */
    public String getFirstName() {
        return this.person.getFirst();
    }

    ...

With the following code in our Test class

   ...
   Author a1 = new Author(new Person("John", "Smith"), ...); // elided arguments
   a1.getFirstName();
   ...

Here is the Sequence Diagrams for this getFirstName().

getPerson seq
  1. Sequence Diagrams are graphs with the Y-axis being time. Time moves from top to bottom.

  2. Each object appears as a line with the same header and footer. [2] The header and footer contain

    1. the object’s bound variable if any, if there is no bound variable then leave this blank

    2. a colon :

    3. the object’s runtime type

  3. A method call is an arrow from left to right where

    1. the arrow originates from the object that makes the method call

    2. the arrow terminates on the object that receives the method call

    3. the arrow is labeled with the method name and its arguments

  4. A method return is a dotted arrow from right to left where [3]

    1. the arrow originates from the object returning a value

    2. the arrow terminates on the object that receives the return value

    3. the arrow can be labelled with the return value

  5. Also notice that on the line that represents an object we see vertical rectangles. These rectangles denote the execution time of a method. Think of them as representing the method’s body.

Recursive Data

Recall Racket Lists

Using an itemization, structs and a self reference.

;;                     +-------------+
;;                    \/             |
;; A List of Number (LoN) is one of  |
;; - empty                           |
;; - (cons Number LoN) --------------+


;; Template
;; (define (lon-fn alon)
;;    (cond
;;       [(empty? alon) ...]
;;       [(cons? alon)  ... (first alon) ...
;;                      ... (lon-fn (rest alon)) ...]
;;

;;; Signature:
;;lon-size: LoN -> Number
;;;; Purpose
;; Given a list of numbers return the number of elements in the list.
       ;; +---------------+
       ;; \/            ;; |
(define (lon-size alon) ;; |
 (cond                  ;; |
    [(empty? alon) 0]   ;; |
    [(cons? alon) (+ 1 (lon-size (rest alon)))]))

Now in Java

Same idea, itemization, classes and a self reference

racketlist

Adding a size() operation will require the following modifications

  1. Add method Integer size() on List

  2. Implement size() in each class that implements List, i.e., Empty and Cons

Here is the updated UML diagram

listsize

And here is the Java code

List.java
/**
 * Represents a List of Integers
 */
public interface List {

    /**
     * Returns the total number of elements in the list.
     *
     * @return number of elements in this list
     */
    Integer size();                                (1)


    /**
     * Returns true if empty and false otherwise
     *
     */
    Boolean isEmpty();

    /**
     * Given a new element {@code element} prepend it to this list
     *
     * @param element new element to add to the list
     * @return updated list with {@code element} prependeds
     */
    List add(Integer element);


    /**
     * Return the last element of this list.
     *
     * @return the last element of this list.
     */
    Integer last();
}
Empty.java
/**
 * Represents the empty list of integers.
 */


public class Empty implements List {


    @Override
    public String toString() {
        return "Empty{}";
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        else return true;
    }


    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        return 42;
    }

    @Override
    public Integer size() {      (2)
        return 0;                (3)
    }

    @Override
    public Boolean isEmpty() {
        return true;
    }

    @Override
    public List add(Integer element) {
        return new Cons(element, this);
    }

    @Override
    public Integer last() throws InvalidCallException {
        throw new InvalidCallException("Called last() on empty!");
    }
}
Cons.java
/**
 * Represents a non-emty list of integers
 *
 */
public class Cons implements List {
    private Integer first;
    private List rest;

    /**
     * Given an integer and a list create a new list with the
     * same elements as {@code rest} and with {@code first} prepended.
     *
     * @param first new element to add to the beginning of the list
     * @param rest the list we are going to use to add our new element
     */
    public Cons(Integer first, List rest) {
        this.first = first;
        this.rest = rest;
    }

    /**
     * Getter for property 'first'.
     *
     * @return Value for property 'first'.
     */
    public Integer getFirst() {
        return first;
    }

    /**
     * Getter for property 'rest'.
     *
     * @return Value for property 'rest'.
     */
    public List getRest() {
        return rest;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Cons cons = (Cons) o;

        if (first != null ? !first.equals(cons.first) : cons.first != null) return false;
        return rest != null ? rest.equals(cons.rest) : cons.rest == null;

    }

    @Override
    public String toString() {
        return "Cons{" +
                "first=" + first +
                ", rest=" + rest +
                '}';
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        int result = first != null ? first.hashCode() : 0;
        result = 31 * result + (rest != null ? rest.hashCode() : 0);
        return result;
    }

    @Override
    public Integer size() {                    (4)
        return 1 + this.getRest().size();      (5)
    }

    @Override
    public Boolean isEmpty() {
        return false;
    }

    @Override
    public List add(Integer element) {
        return new Cons(element, this);
    }

    @Override
    public Integer last() {
        if (this.rest.isEmpty()) {
            return this.first;
        } else {
            return this.rest.last();
        }

    }
}
1 First we add the appropriate method signature on the List interface
2 We implement the method size() inside Empty
3 In the empty case the size of the list is 0
4 We implement the method size() inside Cons
5 In the non-empty case we add 1 to the size of the rest of the list. The rest of the list is the field rest inside Cons so we call size() on that object.

Here is the Sequence Diagrams for size() when called on a 3 element list.

list size sequence
Observer that the bodies of the methods inside the concrete classes contain similar code to the right-hand side expression in our cond clauses.

Lets also add the following methods

  1. a method called Boolean isEmpty() that returns true if our list is empty and false otherwise

  2. a method called List add(Integer num) that adds num to the beginning of the list.

  3. a method called Integer last() that returns the last element of the list

  4. a method called List addToEnd(Integer element) that adds the given element to the end of the list

  5. a method called Integer elementAt(Integer index) that returns the element at index index

Java Packages

Java allows you to organize your Java classes into groups. The grouping is similar (or inspired) to how you group files on your computer using folders.

The Java language provides the keyword package that we can use to create a package and provide a name. For example if we wanted to keep all of our code for lists of integers into a package called integerlist we add the following line at the top of each .java file

package integerlist;

/**
 * Represents a List of Integers
 */
public interface List {

    /**
     * Returns the total number of elements in the list.
     *
     * @return number of elements in this list
     */
    Integer size();                                (1)


    /**
     * Returns true if empty and false otherwise
     *
     */
    Boolean isEmpty();

    /**
     * Given a new element {@code element} prepend it to this list
     *
     * @param element new element to add to the list
     * @return updated list with {@code element} prependeds
     */
    List add(Integer element);


    /**
     * Return the last element of this list.
     *
     * @return the last element of this list.
     */
    Integer last();
}

The naming convention for Java packages is to keep all names lowercase. In order to refer to the List interface using it’s full qualified name we write

  • integerlist.List

We can also created nested packages, just like you can create nested folders. We separate nested packages with a ., e.g.,

package edu.neu.ccs.cs5004.lecture3.integerlist;

/**
 * Represents a List of Integers
 */
public interface List {

    /**
     * Returns the total number of elements in the list.
     *
     * @return number of elements in this list
     */
    Integer size();                                (1)


    /**
     * Returns true if empty and false otherwise
     *
     */
    Boolean isEmpty();

    /**
     * Given a new element {@code element} prepend it to this list
     *
     * @param element new element to add to the list
     * @return updated list with {@code element} prependeds
     */
    List add(Integer element);


    /**
     * Return the last element of this list.
     *
     * @return the last element of this list.
     */
    Integer last();
}

When we create a packages the Java language requires that your save your .java in a folder structure that *reflects your package’s name and nesting. So the preceding nested package example must have the following folder structure

edu
└── neu
    └── ccs
        └── cs5004
            └── lecture3
                └── List.java

If you use your IDE to create a package (by selecting New → Package instead of New → Class the IDE will create the necessary folder structure.

We use fully qualified names when we use Java’s import to include code from other libraries. By default java.lang is always imported so we can omit importing java.lang. Recall that the Java Documentation as well as your documentation uses package names to organize your Javadoc’s generated HTML pages.

Accessing Class properties

Here is a table that explains what can be accessed from which location (class, package, world) for each Java modifier (public, private, protected and default) [4]

Access Modifier Same Class Same Package Subclass Other Packages

public

Y

Y

Y

Y

protected

Y

Y

Y

N

private

Y

N

N

N

default

Y

Y

  • Y if in the same package

  • N if in different package

N

In this course avoid using default.

Exceptions

An exception is an event that occurs during execution of a program and disrupts the normal flow of execution.

Three kinds of exceptions

  1. Checked Exceptions capture events that a well-written application must anticipate and recover from.

    • opening a file using the file name provided by the user and cannot find that file

    • opening a connection to a server whose address was provided to the program by an external entity

  2. Errors capture exceptional conditions external to the application that the application cannot anticipate or recover from.

    • error reading from the disk

    • error reading from the connection to the database

  3. Runtime Exception captures events that are exceptional and internal to the application. The application typically cannot anticipate them or recover from

    • passing in the incorrect values for the arguments to a function

    • logical errors; going over the length of a list

Java’s exception hierarchy dictates the kind of exception (checked, runtime or error).

javaexceptions

Java provides special syntax to mark code that could throw an exception as well as catching an exception. Let’s look at an example.

/**
 * Represents an exception thrown when an invalid value is given for radius
 */

public class InvalidRadiusException extends RuntimeException {
    /**
     * {@inheritDoc}
     */
    public InvalidRadiusException(String message) {
        super(message);
    }
}

Since our InvalidRadiusException extends RuntimeException it is not a checked exception. It is a runtime exception.

We can then throw this exception when appropriate in our Circle 's constructor method using the Java keyword throw and passing an object of our exception.

public class Circle extends AbstractShape {


    /**
     * Given a pin and a radius greater than 0, creates a circle
     *
     * @param pin the location of this circle's pin
     * @param radius this circle's radius. The radius must be greater than 0
    public Circle(Posn pin, Integer radius)  {
        super(pin);

        if (radius <= 0) {
            throw new InvalidRadiusException("Radius must be > 0, given: " + radius);
        }

       this.radius = radius;
    }

    // elided code
}

Code that calls the constructor of Circle can optionally catch the exception and accordingly do something about this abnormal case. For example one possibility would be

class StickFigure {
   private Circle head;
   private Body body;

   public StickFigure(Integer head, Integer body) {
       try {  
          this.head = new Circle(new Pin(0,0) head);(1)
       } catch (InvalidRadiusException invalidRadius) {  
         ShowErrorMEssage errorMessage =(2)
              new ShowErrorMessage("We detected an incorrect value " +
                                   "for the stick figure's head. " +
                                   "Please provide a positive number.");

         new Window(errorMessage).exit();
       }

       this.body = new Body(body);
   }

}
1 Code that is calling a method that can throw an exception can try to call the method. If there is not exception because of the execution of the code in the try -block then Java jumps over the catch -block and continues as normal
2 if the execution of the code inside the try -block does throw an exception then Java will check each catch statement to see if there type of the thrown exception matches the argument of the catch -block. If it does, then run the code inside the catch -block and exit.

If there is no catch -block that matches the thrown exception, Java will traverse all the callers that lead to the execution of this code. If none of the callers deal with the thrown exception the JVM will exit and print out the details of the thrown exception on your Console.

Java allows us to have more than one catch -blocks.

try {
    // try to run these expressions/statements that may throw an exception
} catch (ExceptionType ext) {
    // catch an exception of type ExceptionType, bind it to the variable ext
    // perform actions to recover
} catch (ExceptionType2 ext2) {
    // catch an exception of type ExceptionType2, bind it to the variable ext2
    // perform actions to recover
} catch (IOException | SQLException ex) {
    // catching multiple exceptions for which we deal with in the same
    // way
}

In the case where your exception is a checked exception, any method that might throw the checked exception must [5] declare it’s intend to do so in the method header.

Syntax to declare that a method can throw an exception (of any kind)

 public Integer method() throws RuntimeException, ArgumentException, NetworkException {
 }
Always create your own exceptions. Do not rely on the String message allowed by the already defined exceptions.

Testing methods that throw exceptions in JUnit

JUnit can be used to check your methods even under conditions that throw exceptions. To tell JUnit that you expect an exception to the thrown we add to the @Test annotation the expected exception

@Test(expected=MyException.class)
public void testElementAt() throws Exception {
    //call the method in a way that causes an the expected exception to be thrown
}

Let’s add a test for our Circle class that will validate the use case when we pass a value for radius that is not a positive integer.

CircleTest.java
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class CircleTest {
    private Circle incorrectCircle;
    private Circle circleRadius10;

    @Before
    public void setUp() throws Exception {
//        this.incorrectCircle = new Circle(new Posn(1,1),-1);
        this.circleRadius10 = new Circle(new Posn(10,10), 10);

    }

    @Test
    public void testGetRadius() throws Exception {
        Assert.assertEquals(this.circleRadius10.getRadius(), new Integer(10));
    }

    @Test(expected=InvalidRadiusException.class)
    public void testInvalidRadius() throws Exception {
        this.incorrectCircle = new Circle(new Posn(0,0), -1);
    }

}

Also let’s see what happens if we call Circle 's constructor without using a try-catch block. We create a simple class UseCircle with only one method.

UseCircle.java
/**
 * Created by therapon on 5/24/16.
 */
public class UseCircle {


    public Circle createAnInvalidCircle(){
        return new Circle(new Posn(0,0), -1);
    }
}

and a corresponding test for UseCircle called UseCircleTest

UseCircleTest.java
import org.junit.Before;
import org.junit.Test;

public class UseCircleTest {
    private UseCircle uc;

    @Before
    public void setUp() throws Exception {
        this.uc = new UseCircle();
    }

    @Test
    public void createAnInvalidCircle() throws Exception {
        uc.createAnInvalidCircle();
    }

}

And here is the output on our Console when we run the tests inside UseCircleTest

Console
InvalidRadiusException: Radius must be > 0, given: -1

	at Circle.<init>(Circle.java:10)
	at UseCircle.createAnInvalidCircle(UseCircle.java:8)
	at UseCircleTest.createAnInvalidCircle(UseCircleTest.java:14)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

1. The Law of Demeter has more variations. We will use our more general definiton of the Law of Demeter.
2. To same space we sometimes omit the footer
3. When the return value is not relevant or obvious we can omit the return arrow
4. There are more nuances on accessibility and modifiers that we will touch upon later in the course.
5. The Java compiler does not require to declare Runtime and Errors to be declared in your method’s signature, but it is considered good practise to do so.