Upload
others
View
3
Download
0
Embed Size (px)
Citation preview
115-214
SchoolofComputerScience
PrinciplesofSoftwareConstruction:Objects,Design,andConcurrency
MoreIntroductoryJava,SpecificationandTesting
JoshBloch CharlieGarrod
215-214
Administrivia
• Firsthomeworkduetoday,11:59PM• IwillbejoiningTuaninCitadelCommonsforaspecialHWofficehourfrom5:00-6:00today
• Secondhomeworkwillbepostedshortly
315-214
KeyconceptsfromTuesday
• Interfaces-baseddesignsareflexible• Informationhidingiscrucialtogooddesign• Exceptionsarewaybetterthanerrorcodes• Theneedforcheckedexceptionsisrare
415-214
UnfinishedBusiness:Exceptions
515-214
RememberthisslidefromTuesday?Youcandomuchbetter!
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();
}
615-214
Manualresourceterminationisuglyanderrorprone• Evengoodprogrammersusuallygetitwrong– Sun’sguidetoPersistentConnectionsgotitwrongincodethatclaimedtobeexemplary
– Solutiononpage88ofBlochandGafter’s JavaPuzzlersisbadlybroken;noonenoticedforyears
• 70%oftheusesoftheclosemethodintheJDKitselfwerewrongin2008(!)
• Even“correct”idiomsformanualresourcemanagementaredeficient
6
715-214
Thesolution:try-with-resourcesautomaticallyclosesresources
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);}
815-214
FilecopywithoutARM
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();
}}
}8
915-214
FilecopywithARM
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);}
}
9
1015-214
Outline
I. OverridingObjectmethodsII. EnumsIII. Specifyingprogrambehavior– contractsIV. Testingcorrectness– Junitandfriends
1115-214
Review:Objectmethods
• equals – trueifthetwoobjectsare“equal”• hashCode – ahashcodeforuseinhashmaps• toString – aprintablestringrepresentation
1215-214
OverridingtoStringreview
final class PhoneNumber {private final short areaCode;private final short prefix;private final short lineNumber;...
@Override public String toString() {return String.format("(%03d) %03d-%04d",
areaCode, prefix, lineNumber);}
}
Number jenny = ...;System.out.println(jenny);Prints:(707) 867-5309
1315-214
Review:Object implementations
• toString – ugly anduninformative– Youknowwhatyourobjectissoyoucandobetter– Alwaysoverrideunlessyouknowinwon’tbecalled
• equals &hashCode – identity semantics– Youmust overrideifyouwantvalue semantics– Otherwisedon’t– InLecture2,Isaiditwashardtooverridethem– Ilied
1415-214
Theequals contract
Theequalsmethodimplementsanequivalencerelation.Itis:– Reflexive:Foranynon-nullreferencevaluex,x.equals(x)must
returntrue.– Symmetric:Foranynon-nullreferencevaluesxandy,x.equals(y)
mustreturntrueifandonlyify.equals(x)returnstrue.– Transitive:Foranynon-nullreferencevaluesx,y,z,ifx.equals(y)
returnstrueandy.equals(z)returnstrue,thenx.equals(z)mustreturntrue.
– Consistent:Foranynon-nullreferencevaluesxandy,multipleinvocationsofx.equals(y)consistentlyreturntrueorconsistentlyreturnfalse,providednoinformationusedinequalscomparisonsontheobjectsismodified.
– Foranynon-nullreferencevaluex,x.equals(null)mustreturnfalse.
1515-214
Theequals contractinEnglish
• Reflexive – everyobjectisequaltoitself• Symmetric – if a.equals(b) thenb.equals(a)• Transitive – ifa.equals(b) andb.equals(c),thena.equals(c)
• Consistent– equalobjectsstayequalunlessmutated• “Non-null”– a.equals(null) returnsfalse• Takentogethertheseensurethatequalsisaglobalequivalencerelationoverallobjects
1615-214
equals OverrideExample
public final class PhoneNumber {private final short areaCode;private final short prefix;private final short lineNumber;
@Override public boolean equals(Object o) {if (!(o instanceof PhoneNumber)) // Does null check
return false;PhoneNumber pn = (PhoneNumber) o;return pn.lineNumber == lineNumber
&& pn.prefix == prefix&& pn.areaCode == areaCode;
}
...}
1715-214
ThehashCode contract
Wheneveritisinvokedonthesameobjectmorethanonceduringanexecutionofanapplication,thehashCode methodmustconsistentlyreturnthesameinteger,providednoinformationusedinequalscomparisonsontheobjectismodified.Thisintegerneednotremainconsistentfromoneexecutionofanapplicationtoanotherexecutionofthesameapplication.– Iftwoobjectsareequalaccordingtotheequals(Object)method,thencalling
thehashCode methodoneachofthetwoobjectsmustproducethesameintegerresult.
– Itisnotrequiredthatiftwoobjectsareunequalaccordingtotheequals(Object)method,thencallingthehashCode methodoneachofthetwoobjectsmustproducedistinctintegerresults.However,theprogrammershouldbeawarethatproducingdistinctintegerresultsforunequalobjectsmayimprovetheperformanceofhashtables.
1815-214
ThehashCode contractinEnglish
• Equalobjectsmusthaveequalhashcodes– Ifyouoverrideequals youmustoverridehashCode
• Unequalobjectsshould havedifferenthashcodes– Takeallvaluefieldsintoaccountwhenconstructingit
• Hashcodemustnotchangeunlessobjectmutated
1915-214
hashCode overrideexample
public final class PhoneNumber {private final short areaCode;private final short prefix;private final short lineNumber;
@Override public int hashCode() {int result = 17; // Nonzero is goodresult = 31 * result + areaCode; // Constant must be oddresult = 31 * result + prefix; // " " " " result = 31 * result + lineNumber; // " " " " return result;
}
...}
2015-214
AlternativehashCode overrideLessefficient,butotherwiseequallygood!public final class PhoneNumber {
private final short areaCode;private final short prefix;private final short lineNumber;
@Override public int hashCode() {return arrays.hashCode(areaCode, prefix, lineNumber);
}
...}
Aoneliner.NoexcuseforfailingtooverridehashCode!
2115-214
Formorethanyouwanttoknowaboutoverridingobjectmethods,seeEffectiveJavaChapter2
2215-214
The== operatorvs.equalsmethod
• Forprimitivesyoumust use==• Forobjectreferencetypes– The== operatorprovidesidentitysemantics• ExactlyasimplementedbyObject.equals• EvenifObject.equals hasbeenoverridden• Thisisseldomwhatyouwant!
– youshould(almost)alwaysuse.equals– Using ==onanobjectreferenceisabadsmellincode
if (input == "yes") // A bug!!!
2315-214
Popquiz:whatdoesthisprint?public class Name {
private final String first, last;public Name(String first, String last) {
if (first == null || last == null) throw new NullPointerException();
this.first = first; this.last = last;}public boolean equals(Name o) {
return first.equals(o.first) && last.equals(o.last);}public int hashCode() {
return 31 * first.hashCode() + last.hashCode();}public static void main(String[] args) {
Set<Name> s = new HashSet<>();s.add(new Name("Mickey", "Mouse"));System.out.println(
s.contains(new Name("Mickey", "Mouse")));}
}
(a)true(b)false(c)Itvaries(d)Noneoftheabove
2415-214
WhatDoesItPrint?
(a)true(b)false(c)Itvaries(d)Noneoftheabove
Name overrideshashCode butnotequals!ThetwoName instancesarethusunequal.
2515-214
AnotherLookpublic class Name {
private final String first, last;public Name(String first, String last) {
if (first == null || last == null) throw new NullPointerException();
this.first = first; this.last = last;}public boolean equals(Name o) { // Accidental overloading!
return first.equals(o.first) && last.equals(o.last);}public int hashCode() { // Overriding
return 31 * first.hashCode() + last.hashCode();}public static void main(String[] args) {
Set<Name> s = new HashSet<>();s.add(new Name("Mickey", "Mouse"));System.out.println(
s.contains(new Name("Mickey", "Mouse")));}
}
2615-214
HowDoYouFixIt?Replacetheoverloadedequalsmethodwithanoverridingequalsmethod
@Override public boolean equals(Object o) {if (!(o instanceof Name))
return false;Name n = (Name) o;return n.first.equals(first) && n.last.equals(last);
}
Withthischange,programprintstrue
2715-214
TheMoralofthispuzzler
• Ifyouwanttooverrideamethod:–Makesuresignaturesmatch– Use@Override socompilerhasyourback– Do copy-and-pastedeclarations(orletIDEdoitforyou)
2815-214
Outline
I. OverridingObjectmethodsII. EnumsIII. Specifyingprogrambehavior– contractsIV. Testingcorrectness– Junitandfriends
2915-214
Enumsreview• Javahasobject-orientedenums• Insimpleform,theylookjustlikeCenums:
public enum Planet { MERCURY, VENUS, EARTH, MARS,JUPITER, SATURN, URANUS, NEPTUNE }
• Buttheyhavemanyadvantages[EJItem30]!– Compile-timetypesafety– Multipleenum typescansharevaluenames– Canaddorreorderwithoutbreakingconstants– High-qualityObjectmethods– Screamingfastcollections(EnumSet,EnumMap)– Caniterateoverallconstantsofanenum
3015-214
Youcanadddatatoenumspublic enum Planet {
MERCURY(3.302e+23, 2.439e6), VENUS (4.869e+24, 6.052e6),EARTH (5.975e+24, 6.378e6), MARS (6.419e+23, 3.393e6);
private final double mass; // In kg.private final double radius; // In m.
private static final double G = 6.67300E-11;
Planet(double mass, double radius) {this.mass = mass;this.radius = radius;
}public double mass() { return mass; }public double radius() { return radius; }public double surfaceGravity() { return G * mass / (radius * radius); }
}
3115-214
Youcanaddbehaviortoo!
public enum Planet {... as on previous slide
public double surfaceWeight(double mass) {return mass * surfaceGravity; // F = ma
}}
3215-214
Watchitgo
public static void main(String[] args) {double earthWeight = Double.parseDouble(args[0]);double mass = earthWeight / EARTH.surfaceGravity();for (Planet p : Planet.values()) {
System.out.printf("Your weight on %s is %f%n",p, p.surfaceWeight(mass));
}}
$ java Planet 180Your weight on MERCURY is 68.023205Your weight on VENUS is 162.909181Your weight on EARTH is 180.000000Your weight on MARS is 68.328719
3315-214
Canaddconstant-specificbehavior
• Eachconst canhaveitsownoverrideofamethod– Don'tdothisunlessyouhaveto– Ifaddingdataissufficient,dothatinsteadpublic interface Filter { Image transform(Image original); }
public enum InstagramFilter implements Filter {EARLYBIRD {public Image transform(Image original) { ... }},MAYFAIR {public Image transform(Image original) { ... }},AMARO {public Image transform(Image original) { ... }},RISE {public Image transform(Image original) { ... }};
}
// See Effective Java Items 30 and 34 for more information
3415-214
Outline
I. OverridingObjectmethodsII. EnumsIII. Specifyingprogrambehavior– contractsIV. Testingcorrectness– Junitandfriends
3515-214
Whatisacontract?review• Agreementbetweenanobjectanditsuser• Includes–Methodsignature(typespecifications)– Functionalityandcorrectnessexpectations– Performanceexpectations
• Whatthemethoddoes,nothowitdoesit– Interface(API),notimplementation
• “Focusonconceptsratherthanoperations”
3615-214
Methodcontractdetails
• Statesmethod’sandcaller’sresponsibilities• Analogy:legalcontract– Ifyoupaymethisamountonthisschedule…– Iwillbuildawiththefollowingdetailedspecification– Somecontractshaveremediesfornonperformance
• Methodcontractstructure– Preconditions:whatmethodrequiresforcorrectoperation– Postconditions:whatmethodestablishesoncompletion– Exceptionalbehavior:whatitdoesifpreconditionviolated
• Defineswhatitmeansforimpl tobecorrect36
3715-214
FormalcontractspecificationJavaModellingLanguage(JML)/*@ requires len >= 0 && array != null && array.length == len;@@ ensures \result ==@ (\sum int j; 0 <= j && j < len; array[j]);@*/
int total(int array[], int len);
• Theoreticalapproach– Advantages
• Runtimechecksgeneratedautomatically• Basisforformalverification• Automaticanalysistools
– Disadvantages• Requiresalotofwork• Impracticalinthelarge• Someaspectsofbehaviornotamenabletoformalspecification
postcondition
precondition
3815-214
Textualspecification- Javadoc• Practicalapproach• Document– Everyparameter– Returnvalue– Everyexception(checkedandunchecked)– Whatthemethoddoes,including
• Purpose• Sideeffects• Anythreadsafetyissues• Anyperformanceissues
• Donot documentimplementationdetails
3915-214
SpecificationsintherealworldJavadoc/*** Returns the element at the specified position of this list.* * <p>This method is <i>not</i> guaranteed to run in constant time.* In some implementations, it may run in time proportional to the* element position.* * @param index position of element to return; must be non-negative and * less than the size of this list.* @return the element at the specified position of this list* @throws IndexOutOfBoundsException if the index is out of range* ({@code index < 0 || index >= this.size()})*/E get(int index);
postcondition
precondition
4015-214
Outline
I. OverridingObjectmethodsII. EnumsIII. Specifyingprogrambehavior– contractsIV. Testingcorrectness– Junitandfriends
4115-214
Semanticcorrectnessadherencetocontracts
• Compilerensurestypesarecorrect(type-checking)– Preventsmanyruntimeerrors,suchas“MethodNotFound”and“Cannotaddboolean toint”
• Staticanalysistools(e.g.,FindBugs)recognizemanycommonproblems(bugpatterns)– Overiding equals withoutoverridinghashCode
• Buthowdoyouensuresemanticcorrectness?
41
4215-214
Formalverification
• Usemathematicalmethodstoprovecorrectnesswithrespecttotheformalspecification
• Formallyprovethatallpossibleexecutionsofanimplementationfulfillthespecification
• Manualeffort;partialautomation;notautomaticallydecidable
"Testingshowsthepresence,nottheabsenceofbugs.”
Edsger W.Dijkstra,1969
4315-214
Testing
• Executingtheprogramwithselectedinputsinacontrolledenvironment
• Goals– Revealbugs,sotheycanbefixed(maingoal)– Assessquality– Clarifythespecification,documentation
“Bewareofbugsintheabovecode;Ihaveonlyproveditcorrect,nottriedit.”
DonaldKnuth,1977
4415-214
Who’sright,Dijkstra orKnuth?
• They’rebothright!• Pleasesee“Extra,Extra- ReadAllAboutIt:NearlyAllBinarySearchesandMergesorts areBroken”– Official“GoogleResearch”blog– http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html
• Thereisnosilverbullet– Usealltoolsatyourdisposal
4515-214
Manualtesting?
• LiveSystem?• ExtraTestingSystem?• Checkoutput/assertions?• Effort,Costs?• Reproducible?
4615-214
Automatetesting
• Executeaprogramwithspecificinputs,checkoutputforexpectedvalues
• Setuptestinginfrastructure• Executetestsregularly– Afterevery change
4715-214
Unittests
• Unittestsforsmallunits:methods,classes,subsystems– Smallesttestablepartofasystem– Testpartsbeforeassemblingthem– Intendedtocatchlocalbugs
• Typicallywrittenbydevelopers• Manysmall,fast-running,independenttests• Fewdependenciesonothersystempartsorenvironment• Insufficient,butagoodstartingpoint
4815-214
JUnit
• Popularunit-testingframeworkforJava• Easytouse• Toolsupportavailable• Canbeusedasdesignmechanism
4915-214
Selectingtestcases:commonstrategies
• Readspecification• Writetestsfor
– Representativecase– Invalidcases– Boundaryconditions
• Writestresstests– Automaticallygeneratehugenumbersoftestcases
• Thinklikeanattacker– Thetester’sgoalistofindbugs!
• Howmanytestshouldyouwrite?– Aimtocoverthespecification– Workwithintime/moneyconstraints
5015-214
JUnit conventions
• TestCasecollectsmultipletests(inoneclass)• TestSuitecollectstestcases(typicallypackage)• Testsshouldrunfast• Testsshouldbeindependent
• Testsaremethodswithoutparameterandreturnvalue• AssertErrorsignalsfailedtest(uncheckedexception)
• TestRunnerknowshowtorunJUnittests– (usesreflectiontofindallmethodswith@Testannotat.)
5115-214
Testorganization
• Conventions(notrequirements)• HaveatestclassFooTest foreachpublicclassFoo
• Haveasourcedirectoryandatestdirectory– StoreFooTest andFoointhesamepackage
– Testscanaccessmemberswithdefault(package)visibility
5215-214
Testablecode
• Thinkabouttestingwhenwritingcode• Unittestingencouragesyoutowritetestablecode• Modularityandtestabilitygohandinhand• Sametestcanbeusedonmultipleimplementationsofaninterface!
• Test-DrivenDevelopment– Adesignanddevelopmentmethodinwhichyouwritetestsbeforeyouwritethecode
– WritingtestscanexposeAPIweaknesses!
5315-214
Runtestsfrequently
• Youshouldonlycommitcodethatispassingalltests• Runtestsbeforeeverycommit• Ifentiretestsuitebecomestoolargeandslowforrapidfeedback:– Runlocalpackage-leveltests("smoketests“)frequently– Runalltestsnightly– Mediumsizedprojectseasilyhave1000softestcases
• Continuousintegrationservershelptoscaletesting
5415-214
Continuousintegration- TravisCI
Automatically builds, tests, and displays the result
5515-214
Continuousintegration- TravisCI
You can see the results of builds over time
5615-214
Outlook:statementcoverage
• Tryingtotestallpartsoftheimplementation• Executeeverystatement,ideally
• Does100%coverageguaranteecorrectness?
5715-214
Summary
• Usetry-with-resources,notmanualcleanup• Overrideequalswhenyouneedvaluesemantics• OverridehashCodewhenyouroverrideequals• Enums areawesome• Documentcontractofeverymethod• Testearly,testoften!