Object Oriented Programming in Java
Object Oriented Programming in Java
of Software Construction:
Objects, Design, and Concurrency
17-214 1
Administrivia
• Homework 1 due Thursday 11:59 p.m.
– Everyone must read and sign our collaboration policy
• First reading assignment due Tuesday
– Effective Java Items 15 and 16
17-214 2
Key concepts from Thursday
• Bipartite type system – primitives & object refs
– Single implementation inheritance
– Multiple interface inheritance
• Easiest output – println , printf
• Easiest input – Command line args, Scanner
• Collections framework is powerful & easy to use
17-214 3
Outline
I. Object-oriented programming basics
II. Information hiding
III. Exceptions
17-214 4
Objects
• An object is a bundle of state and behavior
• State – the data contained in the object
– In Java, these are the fields of the object
• Behavior – the actions supported by the object
– In Java, these are called methods
– Method is just OO-speak for function
– Invoke a method = call a function
17-214 5
Classes
17-214 7
Class usage example
public class ComplexUser {
public static void main(String args[]) {
Complex c = new Complex(-1, 0);
Complex d = new Complex(0, 1);
Complex e = c.plus(d);
System.out.println(e.realPart() + " + "
+ e.imaginaryPart() + "i");
e = c.times(d);
System.out.println(e.realPart() + " + "
+ e.imaginaryPart() + "i");
}
}
17-214 8
Interfaces and implementations
• Multiple implementations of API can coexist
– Multiple classes can implement the same API
– They can differ in performance and behavior
• In Java, an API is specified by interface or class
– Interface provides only an API
– Class provides an API and an implementation
– A class can implement multiple interfaces
17-214 9
An interface to go with our class
public interface Complex {
// No constructors, fields, or implementations!
double realPart();
double imaginaryPart();
double r();
double theta();
17-214 10
Modifying class to use interface
17-214 11
Modifying client to use interface
public class ComplexUser {
public static void main(String args[]) {
Complex c = new OrdinaryComplex(-1, 0);
Complex d = new OrdinaryComplex(0, 1);
Complex e = c.plus(d);
System.out.println(e.realPart() + " + "
+ e.imaginaryPart() + "i");
e = c.times(d);
System.out.println(e.realPart() + " + "
+ e.imaginaryPart() + "i");
}
}
17-214 12
Interface permits multiple implementations
class PolarComplex implements Complex {
final double r;
final double theta;
17-214 13
Interface decouples client from implementation
public class ComplexUser {
public static void main(String args[]) {
Complex c = new PolarComplex(Math.PI, 1); // -1
Complex d = new PolarComplex(Math.PI/2, 1); // i
Complex e = c.plus(d);
System.out.println(e.realPart() + " + "
+ e.imaginaryPart() + "i");
e = c.times(d);
System.out.println(e.realPart() + " + "
+ e.imaginaryPart() + "i");
}
}
17-214 14
Why multiple implementations?
• Different performance
– Choose implementation that works best for your use
• Different behavior
– Choose implementation that does what you want
– Behavior must comply with interface spec (“contract”)
• Often performance and behavior both vary
– Provides a functionality – performance tradeoff
– Example: HashSet, TreeSet
17-214 15
Java interfaces and classes
• A type defines a family of objects
– Each type offers a specific set of operations
– Objects are otherwise opaque
• Interfaces vs. classes
– Interface: specifies expectations
– Class: delivers on expectations (the implementation)
17-214 16
Classes as types
• Classes do define types
– Public class methods usable like interface methods
– Public fields directly accessible from other classes
• But generally prefer the use of interfaces
– Use interface types for variables and parameters
unless you know a single implementation will suffice
• Supports change of implementation
• Prevents dependence on implementation details
17-214 17
Check your understanding
interface Animal {
void vocalize();
}
class Dog implements Animal {
public void vocalize() { System.out.println("Woof!"); }
}
class Cow implements Animal {
public void vocalize() { moo(); }
public void moo() { System.out.println("Moo!"); }
}
What Happens?
1. Animal a = new Animal();
a. vocalize();
2. Dog d = new Dog();
d.vocalize();
3. Animal b = new Cow();
b.vocalize();
4. b.moo();
17-214 18
Historical note: simulation and the origins of
OO programming
• Simula 67 was the
first object-oriented
language
• Developed by Kristin
Nygaard and Ole-Johan
Dahl at the Norwegian
Computing Center
• Developed to support discrete-event simulation
– Application: operations research, e.g. traffic analysis
– Extensibility was a key quality attribute for them
– Code reuse was another
17-214 19
Outline
I. Object-oriented programming basics
II. Information hiding
III. Exceptions
17-214 20
Information hiding
17-214 22
Information hiding with interfaces
• Declare variables using interface types
• Client can use only interface methods
• Fields not accessible from client code
• But this only takes us so far
– Client can access non-interface members directly
– In essence, it’s voluntary information hiding
17-214 23
Mandatory Information hiding
visibility modifiers for members
• private – Accessible only from declaring class
• package-private – Accessible from any class in
the package where it is declared
– Technically known as default access
– You get this if no access modifier is specified
• protected – Accessible from subclasses of
declaring class (and within package)
• public – Accessible from anywhere
17-214 24
Hiding interior state in OrdinaryComplex
17-214 25
Discussion
• You know the benefits of private fields
• What are the benefits of private methods?
17-214 26
Best practices for information hiding
• Carefully design your API
• Provide only functionality required by clients
– All other members should be private
• You can always make a private member public
later without breaking clients
– But not vice-versa!
17-214 27
Outline
I. Object-oriented programming basics
II. Information hiding
III. Exceptions
17-214 28
What does this code do?
FileInputStream fIn = new FileInputStream(fileName);
if (fIn == null) {
switch (errno) {
case _ENOFILE:
System.err.println(“File not found: “ + …);
return -1;
default:
System.err.println(“Something else bad happened: “ + …);
return -1;
}
}
DataInput dataInput = new DataInputStream(fIn);
if (dataInput == null) {
System.err.println(“Unknown internal error.”);
return -1; // errno > 0 set by new DataInputStream
}
int i = dataInput.readInt();
if (errno > 0) {
System.err.println(“Error reading binary data from file”);
return -1;
} // The Slide lacks space to close the file. Oh well.
return i;
17-214 29
What does this code do?
FileInputStream fIn = new FileInputStream(fileName);
if (fIn == null) {
switch (errno) {
case _ENOFILE:
System.err.println(“File not found: “ + …);
return -1;
default:
System.err.println(“Something else bad happened: “ + …);
return -1;
}
}
DataInput dataInput = new DataInputStream(fIn);
if (dataInput == null) {
System.err.println(“Unknown internal error.”);
return -1; // errno > 0 set by new DataInputStream
}
int i = dataInput.readInt();
if (errno > 0) {
System.err.println(“Error reading binary data from file”);
return -1;
} // The Slide lacks space to close the file. Oh well.
return i;
17-214 30
Compare to:
17-214 31
Exceptions
• Notify the caller of an exceptional condition by
automatic transfer of control
• Semantics:
– Propagates up stack until main method is reached
(terminates program), or exception is caught
• Sources:
– Program – e.g., IllegalArgumentException
– JVM – e.g., StackOverflowError
17-214 32
Control-flow of exceptions
public static void main(String[] args) {
try {
test();
} catch (IndexOutOfBoundsException e) {
System.out.println"("Caught index out of bounds");
}
}
17-214 33
Checked vs. unchecked exceptions
• Checked exception
– Must be caught or propagated, or program won’t compile
• Unchecked exception
– No action is required for program to compile
– But uncaught exception will cause program to fail!
17-214 34
The exception hierarchy in Java
Object
Throwable
Exception Error
...
RuntimeException IOException
… …
ClassNotFoundException
NullPointerException EOFException
FileNotFoundException
IndexOutOfBoundsException
17-214 35
Design choice: checked and unchecked
exceptions and return values
• Unchecked exception
– Programming error, other unrecoverable failure
• Checked exception
– An error that every caller should be aware of and handle
• Special return value (e.g., null from Map.get)
– Common but atypical result
• Do NOT use return codes
• NEVER return null to indicate a zero-length result
– Use a zero-length list or array instead
17-214 36
One more alternative – return Optional<T>
17-214 37
A sample use of Optional<T>
// Returns maximum value in collection as an Optional<E>
public static <E extends Comparable<E>>
Optional<E> max(Collection<E> c) {
if (c.isEmpty())
return Optional.empty();
E result = null;
for (E e : c)
if (result == null || e.compareTo(result) > 0)
result = Objects.requireNonNull(e);
return Optional.of(result);
}
17-214 38
Creating and throwing your own exceptions
public class SpanishInquisitionException extends RuntimeException {
public SpanishInquisitionException() {
}
}
17-214 39
Benefits of exceptions
17-214 40
Guidelines for using exceptions (1)
17-214 41
Guidelines for using exceptions (2)
17-214 42
Remember this slide?
You can do much better!
17-214 43
Manual resource termination is ugly
and error prone
• Even good programmers usually get it wrong
– Sun’s Guide to Persistent Connections got it wrong in
code that claimed to be exemplary
– Solution on page 88 of Bloch and Gafter’s Java
Puzzlers is badly broken; no one noticed for years
• 70% of the uses of the close method in the JDK
itself were wrong in 2008(!)
• Even “correct” idioms for manual resource
management are deficient
17-214 44
The solution: try-with-resources (TWR)
Automatically closes resources
17-214 45
File copy without TWR
static void copy(String src, String dest) throws IOException {
InputStream in = new FileInputStream(src);
try {
OutputStream out = new FileOutputStream(dest);
try {
byte[] buf = new byte[8 * 1024];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
} finally {
out.close();
}
} finally {
in.close();
}
}
}
17-214 46
File copy with TWR
static void copy(String src, String dest) throws IOException {
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dest)) {
byte[] buf = new byte[8 * 1024];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
}
}
17-214 47
Summary
• Interface-based designs handle change well
• Information hiding is crucial to good design
• Exceptions are far better than error codes
• The need for checked exceptions is rare
• try-with-resources (TWR) is a big win
17-214 48