Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
165 views

Object Oriented Programming in Java

This document provides an overview of an introductory course on object-oriented programming in Java. It discusses key concepts like classes, objects, interfaces, and information hiding. The course outline covers object-oriented programming basics, information hiding, and exceptions. Interactive examples are provided to illustrate class and interface definitions and usage.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
165 views

Object Oriented Programming in Java

This document provides an overview of an introductory course on object-oriented programming in Java. It discusses key concepts like classes, objects, interfaces, and information hiding. The course outline covers object-oriented programming basics, information hiding, and exceptions. Interactive examples are provided to illustrate class and interface definitions and usage.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 48

Principles

of Software Construction:
Objects, Design, and Concurrency

Object-Oriented Programming in Java

Josh Bloch Charlie Garrod Darya Melicher

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

• Every object has a class


– A class defines methods and fields
– Methods and fields collectively known as members
• Class defines both type and implementation
– Type ≈ where the object can be used
– Implementation ≈ how the object does things
• Loosely speaking, the methods of a class are its
Application Programming Interface (API)
– Defines how users interact with instances
17-214 6
Class example – complex numbers
class Complex {
private final double re; // Real Part
private final double im; // Imaginary Part

public Complex(double re, double im) {


this.re = re;
this.im = im;
}

public double realPart() { return re; }


public double imaginaryPart() { return im; }
public double r() { return Math.sqrt(re * re + im * im); }
public double theta() { return Math.atan(im / re); }

public Complex add(Complex c) {


return new Complex(re + c.re, im + c.im);
}
public Complex subtract(Complex c) { ... }
public Complex multiply(Complex c) { ... }
public Complex divide(Complex c) { ... }
}

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");
}
}

When you run this program, it prints


-1.0 + 1.0i
-0.0 + -1.0i

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();

Complex plus(Complex c);


Complex minus(Complex c);
Complex times(Complex c);
Complex dividedBy(Complex c);
}

An interface defines but does not implement API

17-214 10
Modifying class to use interface

class OrdinaryComplex implements Complex {


final double re; // Real Part
final double im; // Imaginary Part

public OrdinaryComplex(double re, double im) {


this.re = re;
this.im = im;
}

public double realPart() { return re; }


public double imaginaryPart() { return im; }
public double r() { return Math.sqrt(re * re + im * im); }
public double theta() { return Math.atan(im / re); }

public Complex add(Complex c) {


return new OrdinaryComplex(re + c.realPart(), im + c.imaginaryPart());
}
public Complex subtract(Complex c) { ... }
public Complex multiply(Complex c) { ... }
public Complex divide(Complex c) { ... }
}

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");
}
}

When you run this program, it still prints


-1.0 + 1.0i
-0.0 + -1.0i

17-214 12
Interface permits multiple implementations
class PolarComplex implements Complex {
final double r;
final double theta;

public PolarComplex(double r, double theta) {


this.r = r;
this.theta = theta;
}

public double realPart() { return r * Math.cos(theta) ; }


public double imaginaryPart() { return r * Math.sin(theta) ; }
public double r() { return r; }
public double theta() { return theta; }

public Complex plus(Complex c) { ... } // Completely different impls


public Complex minus(Complex c) { ... }
public Complex times(Complex c) { ... }
public Complex dividedBy(Complex c) { ... }
}

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");
}
}

When you run this program, it STILL prints


-1.0 + 1.0i
-0.0 + -1.0i

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

Set<Criminal> senate = new HashSet<>(); // Do this…


HashSet<Criminal> senate = new HashSet<>(); // Not this

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

• Single most important factor that distinguishes


a well-designed module from a bad one is the
degree to which it hides internal data and other
implementation details from other modules
• Well-designed code hides all implementation details
– Cleanly separates API from implementation
– Modules communicate only through APIs
– They are oblivious to each others’ inner workings
• Known as information hiding or encapsulation
• Fundamental tenet of software design [Parnas, ‘72]
17-214 21
Benefits of information hiding
• Decouples the classes that comprise a system
– Allows them to be developed, tested, optimized,
used, understood, and modified in isolation
• Speeds up system development
– Classes can be developed in parallel
• Eases burden of maintenance
– Classes can be understood more quickly and debugged
with little fear of harming other modules
• Enables effective performance tuning
– “Hot” classes can be optimized in isolation
• Increases software reuse
– Loosely-coupled classes often prove useful in other contexts

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

class OrdinaryComplex implements Complex {


private double re; // Real Part
private double im; // Imaginary Part

public OrdinaryComplex(double re, double im) {


this.re = re;
this.im = im;
}

public double realPart() { return re; }


public double imaginaryPart() { return im; }
public double r() { return Math.sqrt(re * re + im * im); }
public double theta() { return Math.atan(im / re); }

public Complex add(Complex c) {


return new OrdinaryComplex(re + c.realPart(), im + c.imaginaryPart());
}
public Complex subtract(Complex c) { ... }
public Complex multiply(Complex c) { ... }
public Complex divide(Complex c) { ... }
}

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:

FileInputStream fileInput = null;


try {
fileInput = new FileInputStream(fileName);
DataInput dataInput = new DataInputStream(fileInput);
return dataInput.readInt();
} catch (FileNotFoundException e) {
System.out.println("Could not open file " + fileName);
} catch (IOException e) {
System.out.println("Couldn’t read file: " + e);
} finally {
if (fileInput != null)
fileInput.close();
}

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");
}
}

public static void test() {


try {
System.out.println("Top");
int[] a = new int[10];
a[42] = 42;
System.out.println("Bottom");
} catch (NegativeArraySizeException e) {
System.out.println("Caught negative array size");
}
}

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>

• Optional<T> is a single T instance or nothing


– A value is said to present, or the optional is empty
– Can think of it as a subsingleton collection
• Similar in spirit to checked exceptions
– Force caller to confront possibility of no value
• But optionals demand less boilerplate in client
• Can be tricky to decide which alternative to use
• See Effective Java Item 55 for more information

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() {
}
}

public class HolyGrail {


public void seek() {
...
if (heresyByWord() || heresyByDeed())
throw new SpanishInquisitionException();
...
}
}

17-214 39
Benefits of exceptions

• You can’t forget to handle common failure modes


– Compare: using a flag or special return value
• Provide high-level summary of error, and stack trace
– Compare: core dump in C
• Improve code structure
– Separate normal code path from exceptional
– Ease task of recovering from failure
• Ease task of writing robust, maintainable code

17-214 40
Guidelines for using exceptions (1)

• Avoid unnecessary checked exceptions (EJ Item 71)


• Favor standard exceptions (EJ Item 72)
– IllegalArgumentException – invalid parameter value
– IllegalStateException – invalid object state
– NullPointerException – null param where prohibited
– IndexOutOfBoundsException – invalid index param
• Throw exceptions appropriate to abstraction
(EJ Item 73)

17-214 41
Guidelines for using exceptions (2)

• Document all exceptions thrown by each method


– Checked and unchecked (EJ Item 74)
– But don’t declare unchecked exceptions!
• Include failure-capture info in detail message (Item 75)
– throw new IlegalArgumentException(
"Modulus must be prime: " + modulus);

• Don’t ignore exceptions (EJ Item 77)


// Empty catch block IGNORES exception – Bad smell in code!
try {
...
} catch (SomeException e) { }

17-214 42
Remember this slide?
You can do much better!

FileInputStream fileInput = null;


try {
FileInputStream fileInput = new FileInputStream(fileName);
DataInput dataInput = new DataInputStream(fileInput);
return dataInput.readInt();
} catch (FileNotFoundException e) {
System.out.println("Could not open file " + fileName);
} catch (IOException e) {
System.out.println("Couldn’t read file: " + e);
} finally {
if (fileInput != null) fileInput.close();
}

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

try (DataInput dataInput =


new DataInputStream(new FileInputStream(fileName))) {
return dataInput.readInt();
} catch (FileNotFoundException e) {
System.out.println("Could not open file " + fileName);
} catch (IOException e) {
System.out.println("Couldn’t read file: " + e);
}

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

You might also like