03-Object-oriented programming in javacharlie/courses/17-214/2020-spring/slides... · 21/1/2020...

Preview:

Citation preview

117-214

PrinciplesofSoftwareConstruction:Objects,Design,andConcurrency

Object-OrientedProgramminginJava

JoshBloch CharlieGarrod

217-214

Administrivia

• Homework1dueThursday11:59p.m.– Everyonemustreadandsignourcollaborationpolicy

• FirstreadingassignmentdueTuesday– EffectiveJavaItems15and16

317-214

KeyconceptsfromThursday

• Bipartitetypesystem– primitives&objectrefs– Singleimplementationinheritance–Multipleinterfaceinheritance

• Easiestoutput– println ,printf• Easiestinput– Commandlineargs,Scanner• Collectionsframeworkispowerful&easytouse

417-214

Outline

I. Object-orientedprogrammingbasicsII. InformationhidingIII. Exceptions

517-214

Objects

• Anobject isabundleofstateandbehavior• State– thedatacontainedintheobject– InJava,thesearethefields oftheobject

• Behavior– theactionssupportedbytheobject– InJava,thesearecalledmethods–MethodisjustOO-speakforfunction– Invokeamethod=callafunction

617-214

Classes

• Everyobjecthasaclass– Aclassdefinesmethodsandfields–Methodsandfieldscollectivelyknownasmembers

• Classdefinesbothtypeandimplementation– Type≈wheretheobjectcanbeused– Implementation≈howtheobjectdoesthings

• Looselyspeaking,themethodsofaclassareitsApplicationProgrammingInterface(API)– Defineshowusersinteractwithinstances

717-214

Classexample– complexnumbersclass Complex {private final double re; // Real Partprivate 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) { ... }

}

817-214

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

}

Whenyourunthisprogram,itprints-1.0 + 1.0i-0.0 + -1.0i

917-214

Interfacesandimplementations

• MultipleimplementationsofAPIcancoexist–MultipleclassescanimplementthesameAPI– Theycandifferinperformanceandbehavior

• InJava,anAPIisspecifiedbyinterfaceorclass– InterfaceprovidesonlyanAPI– ClassprovidesanAPIandanimplementation– Aclasscanimplementmultipleinterfaces

1017-214

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

}

AninterfacedefinesbutdoesnotimplementAPI

1117-214

Modifyingclasstouseinterfaceclass OrdinaryComplex implements Complex {final double re; // Real Partfinal 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) { ... }

}

1217-214

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

}

Whenyourunthisprogram,itstillprints-1.0 + 1.0i-0.0 + -1.0i

1317-214

Interfacepermitsmultipleimplementationsclass 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 implspublic Complex minus(Complex c) { ... }public Complex times(Complex c) { ... }public Complex dividedBy(Complex c) { ... }

}

1417-214

public class ComplexUser {public static void main(String args[]) {

Complex c = new PolarComplex(1, Math.PI); // -1Complex d = new PolarComplex(1, Math.PI/2); // 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");}

}

Whenyourunthisprogram,itstill prints-1.0 + 1.0i-0.0 + -1.0i

Interfacedecouplesclientfromimplementation

1517-214

Whymultipleimplementations?

• Differentperformance– Chooseimplementationthatworksbestforyouruse

• Differentbehavior– Chooseimplementationthatdoeswhatyouwant– Behaviormust complywithinterfacespec(“contract”)

• Oftenperformanceandbehaviorboth vary– Providesafunctionality– performancetradeoff– Example:HashSet,LinkedHashSet,TreeSet

1617-214

Interfacesandclasses– thebigpicture

• Interfacesdefinetypes– Specifywhatfunctionalityisprovidedbyinstances– Thesearetheexpectationsimplementationsmustmeet

• Classesdefineimplementations(andtypes)– Describehow instancesmeetexpectations

1717-214

Preferinterfacestoclassesastypes…butdon’toverdoit

• Useinterfacetypesforparametersandvariablesunlessasingleimplementationwillsuffice– Supportschangeofimplementation– Preventsdependenceonimplementationdetails

• Butsometimesasingleimplementationwillsuffice

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

1817-214

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

}

WhatHappens?1. Animal a = new Animal(); a.vocalize();2. Dog b = new Dog(); b.vocalize();3. Animal c = new Cow(); c.vocalize();4. Animal d = new Cow(); d.moo();

1917-214

Historicalnote:simulationandtheoriginsofOOprogramming• Simula 67wasthefirstobject-orientedlanguage

• DevelopedbyKristinNygaardandOle-JohanDahlattheNorwegianComputingCenter

• Developedtosupportdiscrete-eventsimulation– Application:operationsresearch,e.g.trafficanalysis– Extensibilitywasakeyqualityattributeforthem– Codereusewasanother

2017-214

Outline

I. Object-orientedprogrammingbasicsII. InformationhidingIII. Exceptions

2117-214

Informationhiding

• Singlemostimportantfactorthatdistinguishesawell-designedmodulefromabadoneisthedegreetowhichithidesinternaldataandotherimplementationdetailsfromothermodules

• Well-designedcodehidesall implementationdetails– CleanlyseparatesAPIfromimplementation–Modulescommunicateonly throughAPIs– Theyareoblivioustoeachothers’innerworkings

• Knownasinformationhidingorencapsulation• Fundamentaltenetofsoftwaredesign[Parnas,‘72]

2217-214

Benefitsofinformationhiding

• Decouples theclassesthatcompriseasystem– Allowsthemtobedeveloped,tested,optimized,used,understood,andmodifiedinisolation

• Speedsupsystemdevelopment– Classescanbedevelopedinparallel

• Easesburdenofmaintenance– Classescanbeunderstoodmorequicklyanddebuggedwithlittlefearofharmingothermodules

• Enableseffectiveperformancetuning– “Hot”classescanbeoptimizedinisolation

• Increasessoftwarereuse– Loosely-coupledclassesoftenproveusefulinothercontexts

2317-214

Informationhidingwithinterfaces

• Declarevariablesusinginterfacetypes• Clientcanuseonlyinterfacemethods• Fieldsnotaccessiblefromclientcode• Butthisonlytakesussofar– Clientcanaccessnon-interfacemembersdirectly– Inessence,it’svoluntaryinformationhiding

2417-214

MandatoryInformationhidingvisibilitymodifiers formembers

• private – Accessibleonly fromdeclaringclass• package-private– Accessiblefromanyclassinthepackagewhereitisdeclared– Technicallyknownasdefaultaccess– Yougetthisifnoaccessmodifierisspecified

• protected – Accessiblefromsubclassesofdeclaringclass(andwithinpackage)

• public – Accessiblefromanywhere

2517-214

HidinginteriorstateinOrdinaryComplex

class OrdinaryComplex implements Complex {private double re; // Real Partprivate 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) { ... }

}

2617-214

Bestpracticesforinformationhiding

• CarefullydesignyourAPI• Provideonly functionalityrequiredbyclients– All othermembersshouldbeprivate

• Youcanalwaysmakeaprivatememberpubliclaterwithoutbreakingclients– Butnotvice-versa!

2717-214

Outline

I. Object-orientedprogrammingbasicsII. InformationhidingIII. Exceptions

2817-214

Whatdoesthiscodedo?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;

2917-214

Whatdoesthiscodedo?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;

3017-214

There’sabetterway:exceptionsFileInputStream fileInput = null;

try {fileInput = new FileInputStream(fileName);DataInput dataInput = new DataInputStream(fileInput);return dataInput.readInt();

} catch (IOException e) {System.err.println("Could not read file: " + e);return DEFAULT_VALUE;

}

3117-214

Exceptions

• Informcallerofproblembytransferofcontrol• Semantics– Propagatesupstackuntilmainmethodisreached(terminatesprogram),orexceptioniscaught

• Sources– Programcanthrowexplicitly– Underlyingvirtualmachine(JVM)cangenerate

3217-214

Control-flowofexceptionspublic 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; // Index is too high; throws exceptionSystem.out.println("Bottom");

} catch (NegativeArraySizeException e) {System.out.println("Caught negative array size");

}}

3317-214

Benefitsofexceptions

• Youcan’tforgettohandlecommonfailuremodes– Compare:usingaflagorspecialreturnvalue

• Providehigh-levelsummaryoferror,andstacktrace– Compare:coredumpinC

• Improvecodestructure– Separatenormalcodepathfromexceptional– Easetaskofrecoveringfromfailure

• Easetaskofwritingrobust,maintainablecode

3417-214

Checkedvs.uncheckedexceptions

• Checkedexception–Mustbecaughtorpropagated,orprogramwon’tcompile– Exceptionalconditionthatprogrammermustdealwith

• Uncheckedexception– Noactionisrequiredforprogramtocompile…• Butuncaughtexceptionwillcausefailureatruntime

– Usuallyindicatesaprogrammingerror

• Error– SpecialuncheckedexceptionthrownbyJVM*– Recoveryisimpossible*

3517-214

Java’sexceptionhierarchy

Throwable

Exception

RuntimeException

IOException

EOFException

FileNotFoundException

NullPointerException

IndexOutOfBoundsException

ClassNotFoundException

Object

Error

StackOverflowError

Checked Exceptions

3617-214

Designchoice:checkedexceptions,uncheckedexceptions,anderrorcodes• Uncheckedexception– Programmingerror,otherunrecoverablefailure

• Checkedexception– Anerrorthateverycallershouldbeawareofandhandle

• Specialreturnvalue(e.g.,null fromMap.get)– Commonbutatypicalresult

• Donotuseerrorcodes– tooeasytoignore• Donotreturnnull toindicatezero-lengthresult– Useazero-lengthlistorarrayinstead

3717-214

Usingyourownexceptiontypesclass SpanishInquisitionException extends RuntimeException {

SpanishInquisitionException(String detail) {super(detail);

}}

public class HolyGrail {public void seek() {

...if (heresyByWord() || heresyByDeed())

throw new SpanishInquisitionException("heresy");...

}}

3817-214

Guidelinesforusingexceptions(1)

• Avoidunnecessarycheckedexceptions(EJItem71)• Favorstandardexceptions(EJItem72)– IllegalArgumentException – invalidparametervalue– IllegalStateException – invalidobjectstate– NullPointerException – nullparamwhereprohibited– IndexOutOfBoundsException – invalidindexparam

• Throwexceptionsappropriatetoabstraction(EJItem73)

3917-214

Guidelinesforusingexceptions(2)

• Documentallexceptionsthrownbyeachmethod– Checkedandunchecked(EJItem74)– Butdon’tdeclare uncheckedexceptions!

• Includefailure-captureinfoindetailmessage(Item75)– throw new IlegalArgumentException(

"Modulus must be prime: " + modulus);

• Don’tignoreexceptions(EJItem77)// Empty catch block IGNORES exception – Bad smell in code!try {

...} catch (SomeException e) { }

4017-214

Rememberthisslide?There’sonepartwedidn’tshowyou:cleanupFileInputStream fileInput = null;

try {fileInput = new FileInputStream(fileName);DataInput dataInput = new DataInputStream(fileInput);return dataInput.readInt();

} catch (IOException e) {System.err.println("Could not read file: " + e);return DEFAULT_VALUE;

} finally { // Close file if it’s openif (fileInput != null) {

try {fileInput.close();

} catch (IOException ignored) {// No recovery necessary (or possible)

}}

}

4117-214

Manualresourceterminationisuglyanderrorprone,esp.formultipleresources• Evengoodprogrammersusuallygetitwrong– Sun’sGuidetoPersistentConnectionsgotitwrongincodethatclaimedtobeexemplary

– Solutiononpage88ofBlochandGafter’s JavaPuzzlersisbadlybroken;noonenoticedforyears

• 70%oftheusesoftheclosemethodintheJDKitselfwerewrongin2008(!)

• Even“correct”idiomsformanualresourcemanagementaredeficient

4217-214

Thesolution:try-with-resourcesAutomaticallyclosesresources!try (DataInput dataInput =

new DataInputStream(new FileInputStream(fileName))) {return dataInput.readInt();

} catch (IOException e) {System.err.println("Could not read file: " + e);return DEFAULT_VALUE;

}

4317-214

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

}}

}

4417-214

Filecopywithtry-with-resourcesstatic 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);}

}

4517-214

Summary

• Interface-baseddesignshandlechangewell• Informationhidingiscrucialtogooddesign• Exceptionsarefarbetterthanerrorcodes• Theneedforcheckedexceptionsisrare• try-with-resourcesisabigwin;alwaysuseit

Recommended