Java For Testers - index-of.co.ukindex-of.co.uk/Programming/Java For Testers Learn Java...
Transcript of Java For Testers - index-of.co.ukindex-of.co.uk/Programming/Java For Testers Learn Java...
JavaForTesters
LearnJavafundamentalsfastThisversionwaspublishedon2015-02-27
TherightofAlanRichardsontobeidentifiedastheauthorofthisworkhasbeenassertedbyhiminaccordancewiththeCopyright,DesignandPatentsAct1988.
Theviewsexpressedinthisbookarethoseoftheauthor.
FirstpublishedinGreatBritainin2015by:
CompendiumDevelopmentshttp://www.compendiumdev.co.uk
contactdetails:
RelatedWebSites:
JavaForTesters:javaForTesters.comAuthor’sSoftwareTestingBlog:eviltester.comCompendiumDevelopments:compendiumdev.co.ukAuthor’sSeleniumBlog:seleniumSimplified.com
Everyefforthasbeenmadetoensurethattheinformationcontainedinthisbookisaccurateatthetimeofgoingtopress,andthepublishersandauthorcannotacceptanyresponsibilityforanyerrorsoromissions,howevercaused.Noresponsibilityforlossordamageoccasionedbyanypersonacting,orrefrainingfromaction,asaresultofthematerialinthispublicationcanbeacceptedbytheeditor,thepublisherortheauthor.
Apartfromanyfairdealingforthepurposesofresearchorprivatestudy,orcriticismorreview,aspermittedundertheCopyright,DesignandPatentsAct1988;thispublicationmayonlybereproduced,storedortransmitted,inanyformorbyanymeans,withthepriorpermissionofthepublishers,orinthecaseofreprographicreproductioninaccordancewiththetermsandlicensesissuedbytheCopyrightLicensingAgency,90TottenhamCourtRoad,London,W1T4LP.Enquiriesconcerningreproductionoutsidethesetermsshouldbesenttothepublishers.
e-bookISBN:978-0-9567332-4-5
©2013-2015AlanRichardson,CompendiumDevelopmentsLtd
Asever.ThisbookisdedicatedtoBillieandKeeran.
TableofContents
IntroductionTestersuseJavadifferentlyExclusionsSupportingSourceCodeAbouttheAuthorAcknowledgments
ChapterOne-BasicsofJavaRevealedJavaExampleCode
ChapterTwo-InstalltheNecessarySoftwareIntroductionDoyoualreadyhaveJDKorMaveninstalled?InstallTheJavaJDKInstallMavenInstallTheIDECreateaProjectusingtheIDEAboutyournewprojectAddJUnittothepom.xmlfileSummary
ChapterThree-WritingYourFirstJavaCodeMyFirstJUnitTestPrerequisitesCreateAJUnitTestClassCreateaMethodMakethemethodaJUnittestCalculatethesumAssertthevalueRunthe@TestmethodSummaryReferencesandRecommendedReading
ChapterFour-WorkwithOtherClassesUse@TestmethodstounderstandJavaWarningsaboutIntegerSummaryReferencesandRecommendedReading
ChapterFive-WorkingwithOurOwnClassesContextFirstcreatean@Testmethod
Writecodethatdoesn’texistNewRequirementsNowRefactorSummary
ChapterSix-JavaClassesRevisited:Constructors,Fields,Getter&SetterMethodsContextConstructorGettersandSettersSummaryReferencesandRecommendedReading
ChapterSeven-BasicsofJavaRevisitedCommentsStatementPackagesJavaClassesImportingClassesStaticImportsDataTypesOperatorsStringsSummaryReferencesandRecommendedReading
ChapterEight-SelectionsandDecisionsTernaryOperatorsifstatementelsestatementNestedifelseswitchstatementSummaryReferencesandRecommendedReading
ChapterNine-ArraysandForLoopIterationArraysExercisesSummaryReferencesandRecommendedReading
ChapterTen-IntroducingCollectionsASimpleIntroductionIteratingwithwhileanddo…whileInterfacesSummary
ReferencesandRecommendedReading
ChapterEleven-IntroducingExceptionsWhatisanexception?CatchingExceptionsAnExceptionisanobjectCatchmorethanoneexceptionJUnitandExceptionsThrowinganExceptionfinally
SummaryReferencesandRecommendedReading
ChapterTwelve-IntroducingInheritanceInheritanceInheritfromInterfacesandAbstractClassesSummaryReferencesandRecommendedReading
ChapterThirteen-MoreAboutExceptionsUncheckedandCheckedExceptionsDifferencebetweenException,ErrorandThrowableCreateyourownExceptionclassSummaryReferencesandRecommendedReading
ChapterFourteen-JUnitExplored@Test
Before&After@Ignore
JUnitAssertionsAssertingwithHamcrestMatchersandassertThatfail
staticimportingSummaryReferencesandRecommendedReading
ChapterFifteen-StringsRevisitedStringSummarySystem.out.println
SpecialcharacterencodingStringConcatenationConvertingto/fromaStringConstructorsComparingStringsManipulatingStrings
BasicStringparsingwithsplitManipulatingstringsWithStringBuilderConcatenation,.format,orStringBuilderSummaryReferencesandRecommendedReading
ChapterSixteen-RandomDataMath.random
java.util.random
SeedingrandomnumbersUsingRandomNumberstogenerateRandomStringsDiscussionrandomdatainautomationSummaryReferencesandRecommendedReading
ChapterSeventeen-DatesandTimescurrentTimeMillisandnanoTimeDate
SimpleDateFormat
Calendar
SummaryReferencesandRecommendedReading
ChapterEighteen-PropertiesandPropertyFilesPropertiesBasicsJava’sSystemPropertiesWorkingwithPropertyfilesSummaryReferencesandRecommendedReading
ChapterNineteen-FilesExampleofreadingandwritingafileFileWritingAndReadingFilesAdditionalFileMethodsFilesSummaryReferencesandRecommendedReading
ChapterTwenty-MathandBigDecimalBigDecimalMathSummaryReferencesandRecommendedReading
ChapterTwentyOne-CollectionsRevisitedSet
MapImplementationsSummaryReferencesandRecommendedReading
ChapterTwentyTwo-AdvancingConceptsInterfacesAbstractClassesGenericsLoggingEnumRegularExpressionsReflectionAnnotationsDesignPatternsConcurrencyAdditionalFileconsiderationsSummary
ChapterTwentyThree-NextStepsRecommendedReadingRecommendedVideosRecommendedWebSitesNextStepsReferences
Appendix-IntelliJHintsandTipsShortcutKeysCodeCompletionNavigatingSourceCodeRunningaJUnitTestLoadingProjectSourceHelpMenuSummary
Appendix-ExerciseAnswersChapterThree-MyFirstJUnitTestChapterFour-WorkWithOtherClassesChapterFive-WorkWithOurOwnClassesChapterSix-JavaClassesRevisited:Constructors,Fields,Getter&SetterMethodsChapterEight-SelectionsandDecisionsChapterNine-ArraysandForLoopIterationChapterTen-IntroducingCollectionsChapterEleven-IntroducingExceptionsChapterTwelve-IntroducingInheritanceChapterThirteen-MoreExceptions
ChapterFourteen-JUnitExploredChapterFifteen-StringsRevisitedChapterSixteen-RandomDataChapterSeventeen-Dates&TimesChapterEighteen-PropertiesandPropertyFilesChapterNineteen-FilesChapterTwenty-MathandBigDecimalChapterTwentyOne-CollectionsRevisited
Introduction
Thisisanintroductorytext.Attimesittakesatutorialapproachandadoptsstepbystepinstructionstocoding.Somepeoplemorefamiliarwithprogrammingmightfindthisslow.Thisbookisnotaimedatthosepeople.
ThisbookisaimedatpeoplewhoareapproachingJavaforthefirsttime,specificallywithaviewtoaddingautomationtotheirtestapproach.Idonotcoverautomationtoolsinthisbook.
IdocoverthebasicJavaknowledgeneededtowriteandstructurecodewhenautomating.
Iprimarilywrotethisbookforsoftwaretesters,andtheapproachtolearningisorientedaroundwritingautomationcodetosupporttesting,ratherthanwritingapplications.AssuchitmightbeusefulforanyonelearningJava,whowantstolearnfroma“testfirst”perspective.
Automationtosupporttestingisnotlimitedtotestersanymore,sothisbookissuitableforanyonewantingtoimprovetheiruseofJavainautomation:managers,businessanalysts,users,andofcourse,testers.
TestersuseJavadifferentlyIrememberwhenIstartedlearningJavafromtraditionalbooks,andIrememberthatIwasunnecessarilyconfusedbysomeoftheconceptsthatIrarelyhadtousee.g.creatingmanifestfiles,andcompilingfromthecommandline.
TestersuseJavadifferently.
MostJavabooksstartwitha‘main’classandshowhowtocompilecodeandwritesimpleapplicationsfromthecommandline,thenbuildupintomoreJavaconstructsandGUIapplications.WhenIwriteJava,Irarelycompileittoastandaloneapplication,IspendalotoftimeintheIDE,writingandrunningsmallchecksandrefactoringtoabstractionlayers.
BylearningthebasicsofJavapresentedinthisbook,youwilllearnhowtoreadandunderstandexistingcodebases,andwritesimplechecksusingJUnitquickly.Youwillnotlearnhowtobuildandstructureanapplication.Thatisusefulknowledge,butitcanbelearnedafteryouknowhowtocontributetotheJavacodebasewithJUnittests.
MyaimistohelpyoustartwritingautomationcodeusingJava,andhavethebasicknowledgeyouneedtodothat.ThisbookfocusesoncoreJavafunctionalityratherthanalotofadditionallibraries,sinceonceyouhavethebasics,pickingupalibraryandlearninghowtouseitbecomesamatterofreadingthedocumentationandsamplecode.
Exclusions
Thisisnota‘comprehensive’introduction.Thisisa‘gettingstarted’guide.EventhoughIconcentrateoncoreJava,therearestillaspectsofJavathatIhaven’tcoveredindetail,Ihavecoveredthem‘justenough’tounderstand.e.g.inheritance,interfaces,enums,innerclasses,etc.
Somepeoplemaylookdisparaginglyonthetextbasedontheexclusions.SoconsiderthisanopinionatedintroductiontoJavabecauseIknowthatIdidnotneedtousemanyofthoseexclusionsforthefirstfewyearsofmyautomationprogramming.
ImaintainthatthereisacoresetofJavathatyouneedinordertostartwritingautomationcodeandstartaddingvaluetoautomationprojects.Iaimtocoverthatcoreinthisbook.
Essentially,IlookedattheJavaIneededwhenIstartedwritingautomationtosupportmytesting,andusedthatasscopeforthisbook.WhileknowledgeofInterfaces,Inheritance,andenums,allhelpmakemyautomationabstractionsmorereadableandmaintainable;Ididnotusethoseconstructswithmyearlyautomation.
Ialsowanttokeepthebooksmall,andapproachable,sothatpeopleactuallyreaditandworkthroughit,ratherthanbuyingandleavingontheirshelfbecausetheyweretoointimidatedtopickitup.AndthatmeansleavingoutthepartsofJava,whichyoucanpickupyourself,onceyouhavemasteredtheconceptsinthisbook.
ThisbookdoesnotcoveranyJava1.8functionality.ThehighestversionofJavarequiredtoworkwiththisbookisJava1.7.ThecodeinthisbookwillworkwithJava1.8,Isimplydon’tcoveranyofthenewfunctionalityaddedinJava1.8becauseIwantyoutolearnthebasics,andstartbeingproductivequickly.Afteryoucompletethisbook,youshouldbeabletopickupthenewfeaturesinJava1.8whenyouneedthem.
SupportingSourceCodeYoucandownloadthesourcecodeforthisbookfromgithub.com.Thesourcecontainstheexamplesandanswerstoexercises.
Isuggestyouworkthroughthebookandgiveityourbestshotbeforeconsultingthesourcecode.
github.com/eviltester/javaForTestersCode
Thesourcecodehasbeenorganizedintotwohighlevelsourcefolders:mainandtest.Thefullsignificanceofthesewillbeexplainedinlaterchapters.Butfornow,thetestfoldercontainsalltheJUnitteststhatyouseeinthisbook.Eachchapterhasapackageandbeneaththatanexercisesandanexamplesfolder:
e.g.
ThemainfolderforChapter3is:src\test\java\com\javafortesters\chap003myfirsttest
itcontainsanexamplesfolderwithallthecodeusedinthemainbodyofthetextitcontainsanexercisesfolderwithallthecodefortheanswersIcreatedfortheexercisesinChapter3
Thisshouldmakeiteasierforyoutonavigatethecodebase.Andifyouexperiencedifficultiestypinginanyofthecodethenyoucancompareitwiththeactualcodetosupportthebook.
Toallowyoutoreadthebookwithoutneedingtohavethesourcecodeopen,Ihaveaddedalotofcodeinthebodyofthebookandyoucanfindmuchofthecodefortheexercisesintheappendix.
TheAppendix“IntelliJHintsandTips”hasinformationonloadingthesourceandoffersareferencesectionforhelpingyounavigateandworkwiththesourcecodeinIntelliJ.
AbouttheAuthorAlanRichardsonhasworkedasaSoftwareprofessionalsince1995(althoughitfeelslonger).PrimarilyworkingwithSoftwareTesting,althoughhehaswrittencommercialsoftwareinC++,andavarietyofotherlanguages.
Alanhasavarietyofon-linetrainingcourses,bothfreeandcommercial:
“Selenium2WebDriverWithJava”“StartUsingSeleniumWebDriver”“TechnicalWebTesting”
Youcanfinddetailsofhisotherbooks,trainingcourses,conferencepapersandslides,andvideos,onhismaincompanywebsite:
CompendiumDev.co.uk
Alanmaintainsanumberofwebsites:
SeleniumSimplified.com:WebAutomationusingSeleniumWebDriverEvilTester.com:TechnicaltestingJavaForTesters.com:Java,aimedatsoftwaretesters.
JavaForTesters.comalsoactsasthesupportsiteforthisbook.
Alantweetsusingthehandle@eviltester
AcknowledgmentsThisbookwascreatedasa“workinprogress”onleanpub.com.Mythanksgotoeveryonewhoboughtthebookinitsearlystages,thisprovidedthecontinuedmotivationtocreatesomethingthataddedvalue,andthenspendtheextratimeneededtoaddpolishandreadability.
Specialthanksgotothefollowingpeoplewhoprovidedearlyandhelpfulfeedbackduringthewritingprocess:JayGehlot,FaezehSeyedarabi,SzymonKazmierczak,SrinivasKadiyala,TonyBruce,James‘Drew’Cobb,AdrianRapan.
IamalsogratefultoeveryJavadeveloperthatIhaveworkedwithwhotookthetimetoexplaintheircode.Youhelpedmeobservewhatagooddeveloperdoesandhowthey
work.Thefactthatyouweregood,forcedmeto‘upmygame’andimprovebothmycodingandtestingskills.
Allmistakesinthisbookaremyfault.Ifyoufindany,pleaseletmeknowviacompendiumDev.co.uk/contactorviaanyofthesitesmentionedabove.
ChapterOne-BasicsofJavaRevealed
ChapterSummaryAnoverviewofJavacodetosetthescene:
classisthebasicbuildingblockaclasshasmethodsmethodnamesstartwithlowercaselettersclassnamesstartwithuppercaselettersaJUnittestisamethodannotatedwith@TestJUnittestmethodscanberunwithoutcreatinganapplication
InthisfirstchapterIwillshowyouJavacode,andthelanguageIusetodescribeit,withlittleexplanation.
Idothistoprovideyouwithsomecontext.IwanttowrapyouinthelanguagetypicallyusedtodescribeJavacode.AndIwanttoshowyousmallsectionsofcodeincontext.Idon’texpectyoutounderstandityet.Justreadthepageswhichfollow,lookatthecode,soakitin,acceptthatitworks,andisconsistent.
Theninlaterpages,Iwillexplainthecodeconstructsinmoredetail,youwillwritesomecode,andI’llreinforcetheexplanations.
JavaExampleCode
Remember-justreadthefollowingsectionJustreadthefollowingsection,anddon’tworryifyoudon’tunderstanditallimmediately.Iexplainitinlaterpages.IhaveemphasizedtextwhichIwillexplainlater.Soifyoudon’tunderstandwhatanemphasizedwordmeans,thendon’tworry,youwillinafewpagestime.
AnemptyclassAclassisthebasicbuildingblockthatweusetobuildourJavacodebase.
Allthecodethatwewritetodostuff,wewriteinsideaclass.IhavenamedthisclassAnEmptyClass.1packagecom.javafortesters.chap001basicsofjava.examples.classes;
2
3publicclassAnEmptyClass{
4}
Justlikeyourname,ClassnamesstartwithanuppercaseletterinJava.I’musingsomethingcalledCamelCasetoconstructthenames,insteadofspacestoseparatewords,wewritethefirstletterofeachwordinuppercase.
ThefirstlineisthepackagethatIaddedtheclassto.Apackageislikeadirectoryonthefilesystem,thisallowsustofind,anduse,theClassintherestofourcode.
AclasswithamethodAclass,onitsown,doesn’tdoanything.Wehavetoaddmethodstotheclassbeforewecandoanything.Methodsarethecommandswecancall,tomakesomethinghappen.
InthefollowingexampleIhavecreatedanewclasscalledAClassWithAMethod,andthisclasshasamethodcalledaMethodOnAClasswhich,whencalled,printsout"HelloWorld"totheconsole.1packagecom.javafortesters.chap001basicsofjava.examples.classes;
2
3publicclassAClassWithAMethod{
4
5publicvoidaMethodOnAClass(){
6System.out.println("HelloWorld");
7}
8}
Methodnamesstartwithlowercaseletters.
WhenwestartlearningJavawewillcallthemethodsofourclassesfromwithinJUnittests.
AJUnitTestForthecodeinthisbookwewilluseJUnit.JUnitisacommonlyusedlibrarywhichmakesiteasyforustowriteandrunJavacodewithassertions.
AJUnittestissimplyamethodinaclasswhichisannotatedwith@Test(i.e.wewrite@Testbeforethemethoddeclaration).1packagecom.javafortesters.chap014junit.examples;
2
3importcom.javafortesters.chap001basicsofjava.examples.classes.AClassWithAMethod;
4importorg.junit.Test;
5
6publicclassASysOutJunitTest{
7
8@Test
9publicvoidcanOutputHelloWorldToConsole(){
10AClassWithAMethodmyClass=newAClassWithAMethod();
11myClass.aMethodOnAClass();
12}
13}
Intheabovecode,IinstantiateavariableoftypeAClassWithAMethod(whichisthenameIgavetotheclassearlier).IhadtoimporttheclassandpackagebeforeIcoulduseit,andIdidthatasoneofthefirstlinesinthefile.
IcanrunthismethodfromtheIDEwithoutcreatingaJavaapplicationbecauseIhaveusedJUnitandannotatedthemethodwith@Test.
WhenIrunthismethodthenIwillseethefollowingtextprintedouttotheJavaconsoleinmyIDE:
HelloWorld
SummaryIhavethrownyouintothedeependhere;presentingyouwithapageofpossiblegobbledygook.AndIdidthattointroduceyoutoatheJavaProgrammingLanguagequickly.
JavaProgrammingLanguageConcepts:
ClassMethodJUnitAnnotationPackageVariablesInstantiatevariablesTypeImport
ProgrammingConventionConcepts:
CamelCaseJUnitTestsareJavamethodsannotatedwith@Test
IntegratedDevelopmentEnvironmentConcepts:
Console
Overthenextfewchapters,I’llstarttoexplaintheseconceptsinmoredetail.
ChapterTwo-InstalltheNecessarySoftware
ChapterSummaryInthischapteryouwilllearnthetoolsyouneedtoprograminJava,andhowtoinstallthem.YouwillalsofindlinkstoadditionalFAQsandVideotutorials,shouldyougetstuck.
Thetoolsyouwillinstallare:
JavaDevelopmentKitMavenAnIntegratedDevelopmentEnvironment(IDE)
Youwillalsolearnhowtocreateyourfirstproject.
Whenyoufinishthischapteryouwillbereadytostartcoding.
Isuggestyoufirst,readthiswholechapter,andthenworkthroughthechapterfromthebeginningandfollowthestepslisted.
IntroductionProgrammingrequiresyoutosetupabunchoftoolstoallowyoutowork.
ForJava,thismeansyouneedtoinstall:
JDK-JavaDevelopmentKitIDE-IntegratedDevelopmentEnvironment
Forthisbookwearealsogoingtoinstall:
Maven-adependencymanagementandbuildtool
InstallingMavenaddsanadditionaldegreeofcomplexitytothesetupprocess,buttrustme.ItwillmakethewholeprocessofbuildingprojectsandtakingyourJavatothenextlevelaloteasier.
Ihavecreatedasupportpageforinstallation,withvideosandlinkstotroubleshootingguides.
JavaForTesters.com/install
Ifyouexperienceanyproblemsthatarenotcoveredinthischapter,oronthesupportpages,thenpleaseletmeknowsoIcantrytohelp,oramendthischapter,andpossiblyaddnewresourcestothesupportpage.
DoyoualreadyhaveJDKorMaveninstalled?
Someofyoumayalreadyhavethesetoolsinstalledwithyourmachine.Thefirstthingweshoulddoislearnhowtocheckiftheyareinstalledornot.
JavaJDKManyofyouwillalreadyhaveaJREinstalled(JavaRuntimeEnvironment),butwhendevelopingwithJavaweneedtouseaJDK.
Ifyoutypejavac-versionatyourcommandlineandgetanerrorsayingthatjavaccannotbefound(orsomethingsimilar).ThenyouneedtoinstallandconfigureaJDK.
Ifyouseesomethingsimilarto:javac1.7.0_10
ThenyouhaveaJDKinstalled.ItisworthfollowingtheinstructionsbelowtocheckifyourinstalledJDKisuptodate,butifyouhavea1.7.xJDK(orhigher)installedthenyouhaveagoodenoughversiontoworkthroughthisbookwithoutamendment.IfyourJDKisversion1.6thensomeofthecodeexampleswillnotwork.
JavaHasMultipleVersionsTheJavalanguageimprovesovertime.Witheachnewversionaddingnewfeatures.IfyouareunfortunateenoughtonotbeallowedtoinstallJava1.7atwork(thenIsuggestyouworkthroughthisbookathome,oronaVM),thenpartsofthesourcecodewillnotworkandthecodeyoudownloadforthisbookwillthrowerrors.
Specifically,wecoverthefollowingfeaturesintroducedinJava1.7:
TheDiamondoperator<>intheCollectionschaptersBinaryliteralse.g.0b1001Underscoresinliteralse.g.9_000_000_000LswitchstatementsusingStrings
Theabovestatementsmaynotmakesenseyet,butifyouareusingaversionofJavalowerthan1.7thenyoucanexpecttoseetheseconceptsthrowerrorswithJDK1.6orbelow.
InstallMavenMavenrequiresaversionofJavainstalled,soifyoucheckedforJavaanditwasn’tthere,youwillneedtoinstallMaven.
Ifyoutypemvn-versionatyourcommandline,andreceiveanerrorthatmvncannotbefound(orsomethingsimilar).ThenyouneedtoinstallandconfigureMavenbeforeyoufollowthetextinthisbook.
Ifyouseesomethingsimilarto:ApacheMaven3.0.4(r1232337;2012-01-1708:44:56+0000)
Mavenhome:C:\mvn\apache-maven-3.0.4
Javaversion:1.7.0_10,vendor:OracleCorporation
Javahome:C:\ProgramFiles\Java\jdk1.7.0_10\jre
Defaultlocale:en_GB,platformencoding:Cp1252
OSname:"windows8",version:"6.2",arch:"amd64",family:"windows"
ThenyouhaveMaveninstalled.Thisbookdoesn’trequireaspecificversionofMaven,buthavingaversionof3.x.xoraboveshouldbefine.
InstallTheJavaJDKTheJavaJDKcanbedownloadedfromoracle.com.Ifyoumistakenlydownloadfromjava.comthenyouwillbedownloadingtheJRE,andfordevelopmentworkweneedtheJDK.
oracle.com/technetwork/java/javase/downloads
Fromtheabovesiteyoushouldfollowtheinstallationinstructionsforyourspecificplatform.
YoucanchecktheJDKisinstalledbyopeninganewcommandlineandrunningthecommand:javac-version
Thisshouldshowyoutheversionnumberwhichyoudownloadedandinstalledfromoracle.com
InstallMavenMavenisadependencymanagementandbuildtool.WewilluseittoaddJUnittoourprojectandwriteourcodebasedonMavenfolderconventionstomakeiteasierforotherstoreviewandworkwithourcodebase.
TheofficialMavenwebsiteismaven.apache.org.YoucandownloadMavenandfindinstallationinstructionsontheofficialwebsite.
DownloadMavenbyvisitingthedownloadpage:
maven.apache.org/download.cgi
Theinstallationinstructionscanalsobefoundonthedownloadpage:
maven.apache.org/download.cgi#Installation_Instructions
Isummarizetheinstructionsbelow:
UnzipthedistributionarchivewhereyouwanttoinstallMavenCreateanM2_HOMEuser/environmentvariablethatpointstotheabovedirectoryCreateanM2user/environmentvariablethatpointstoM2_HOME\bin
onWindows%M2_HOME%\binsometimesonWindows,IfindIhavetoavoidre-usingtheM2_HOMEvariableandinsteadcopythepathinagain
onUnix$M2_HOME/binAddtheM2user/environmentvariabletoyourpathMakesureyouhaveaJAVA_HOMEuser/environmentvariablethatpointstoyourJDKrootdirectory
AddJAVA_HOMEtoyourpath
Youcancheckitisinstalledbyopeningupanewcommandlineandrunningthecommand:mvn-version
ThisshouldshowyoutheversionnumberthatyoujustinstalledandthepathforyourJDK.
Irecommendyoutakethetimetoreadthe“Mavenin5Minutes”guideontheofficialMavenwebsite:
maven.apache.org/guides/getting-started/maven-in-five-minutes.html
InstallTheIDEWhilethecodeinthisbookwillworkwithanyIDE,IrecommendyouinstallIntelliJ.IfindthatIntelliJworkswellforbeginnerssinceittendstopickuppathsanddefaultlocationsbetterthanEclipse.
Forthisbook,IwilluseIntelliJandanysupportingvideosIcreateforthisbook,oranyshortcutkeysImentionrelatingtotheIDEwillassumeyouareusingIntelliJ.
TheofficialIntelliJwebsiteisjetbrains.com/idea
IntelliJcomesintwoversionsa‘Community’editionwhichisfree,andan‘Ultimate’editionwhichyouhavetopayfor.
Forthepurposesofthisbook,andmostofyourautomationdevelopmentwork,the‘Community’editionwillmeetyourneeds.
DownloadtheCommunityEditionIDEfrom:
jetbrains.com/idea/download
Theinstallationshouldusethestandardinstallationapproachforyourplatform.
Whenyouarecomfortablewiththeconceptsinthisbook,youcanexperimentwithotherIDEse.g.EclipseorNetbeans.
IsuggestyoustickwithIntelliJuntilyouaremorefamiliarwithJavabecausethenyouminimizetheriskofissueswiththeIDEconfusingyouintobelievingthatyouhaveaproblemwithyourJava.
CreateaProjectusingtheIDETocreateyourfirstproject,useIntelliJtodothehardwork.
StartyourinstalledIntelliJChooseFile\NewProjectOntheNewProjectwizard:
chooseMavenModule
typeaprojectnamee.g.javafortesterschoosealocationfortheprojectsourcefilesIntelliJshouldhavefoundyourinstalledJDKSelectNext
Youshouldbeabletouseallthedefaultsettingsforthewizard.
AboutyournewprojectTheNewProjectwizardshouldcreateanewfolderwithastructuresomethinglikethefollowing:+javaForTesters
+.idea
+src
+main
+java
+resources
+test
+java
javaForTesters.iml
pom.xml
Intheabovehierarchy,
the.ideafolderiswheremostoftheIntelliJconfigurationfileswillbestored,the.imlfilehasotherIntelliJconfigurationdetails,thepom.xmlfileisyourMavenprojectconfigurationfile.
Ifthewizardcreatedany.javafilesinanyofthedirectoriesthenyoucandeletethemastheyarenotimportant.Youwillbestartingthisprojectfromscratch.
TheabovedirectorystructureisastandardMavenstructure.MavenexpectscertainfilestobeincertaindirectoriestousethedefaultMavenconfiguration.Sinceyouarejuststartingyoucanleavethedirectorystructureasitis.
Certainconventionsthatyouwillfollowtomakeyourlifeasabeginningdevelopereasier:
AddyourJUnitTestClassesintothesrc\test\javafolderhierarchyWhenyoucreateaJUnitTestClass,makesureyouappendTesttotheClassname
Thesrc\main\javafolderhierarchyisforJavacodethatisnotusedforassertingbehaviour.Typicallythisisapplicationcode.Wewillusethisforourabstractionlayercode.Wecouldaddallthecodewecreateinthisbookinthesrc\test\javahierarchybutwherepossibleIsplittheabstractioncodeintoaseparatefolder.
Theaboveconventiondescriptionmaynotmakesenseatthemoment,buthopefullyitwillbecomeclearasyouworkthroughthebook.Don’tworryaboutitnow.
Thepom.xmlfilewillprobablylooklikethefollowing:<?xmlversion="1.0"encoding="UTF-8"?>
<projectxmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>javaForTesters</groupId>
<artifactId>javaForTesters</artifactId>
<version>1.0-SNAPSHOT</version>
</project>
Thisisthebasicsforablankprojectfileanddefinesthenameoftheproject.
Youcanfindinformationaboutthepom.xmlfileontheofficialMavensite.
maven.apache.org/pom.html
AddJUnittothepom.xmlfileWewillusealibrarycalledJUnittohelpusrunourcode.
junit.org
YoucanfindinstallationinstructionsforusingJUnitwithMavenontheJUnitwebsite.
github.com/junit-team/junit/wiki/Download-and-Install
Webasicallyeditthepom.xmlfiletoincludeadependencyonJUnit.WedothisbycreatingadependenciesXMLelementandadependencyXMLelementwhichdefinestheversionofJUnitwewanttouse.Atthetimeofwritingitisversion4.11
Thepom.xmlfilethatwewilluseforthisbook,onlyrequiresadependencyonJUnit,soitlookslikethis:<?xmlversion="1.0"encoding="UTF-8"?>
<projectxmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>javaForTesters</groupId>
<artifactId>javaForTesters</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
YoucanseeIalsoaddedabuildsectionwithamaven-compiler-plugin.ThiswasmainlytocutdownonwarningsintheMavenoutput.Ifyoureallywanttomakethepom.xmlfilesmallyoucouldgetawaywithaddingthe<dependencies>XMLelementandallitscontaininginformationaboutJUnit.
Amendyourpom.xmlfiletocontainthedependenciesandbuildelementsabove.IntelliJshoulddownloadtheJUnitdependencyreadyforyoutowriteyourfirstJUnitTest,inthenextchapter.
YoucanfindmoreinformationaboutthispluginontheMavensite:
maven.apache.org/plugins/maven-compiler-plugin
SummaryIfyoufollowedtheinstructionsinthischapterthenyoushouldnowhave:
Maveninstalled-mvn-versionJDKinstalled-javac-versionIntelliJIDEinstalledCreatedyourfirstprojectApom.xmlfilewithJUnitasadependency
Ican’tanticipatealltheproblemsyoumighthaveinstallingthethreetoolslistedinthischapter(JDK,Maven,IDE).
Theinstallationshouldbesimple,butthingscangowrong.
IhavecreatedafewvideosontheJavaForTesters.com/installsitewhichshowhowtoinstallthevarioustools.
JavaForTesters.com/install
IaddedsomeMavenTroubleshootingHintsandTipstothe“JavaForTesters”blog:
javafortesters.blogspot.co.uk/2013/08/maven-troubleshooting-faqs-and-tips.html
Ifyoudogetstuckthentryanduseyourfavouritesearchengineandcopyandpastetheexacterrormessageyoureceiveintothesearchengineandyou’llprobablyfindsomeoneelsehasalreadymanagedtoresolveyourexactissue.
ChapterThree-WritingYourFirstJavaCode
ChapterSummaryInthistutorialchapteryouwillfollowalongwiththetextandcreateyourfirstJUnittest.Youwilllearn:
HowtoorganizeyourcodeandimportotherclassesCreatingclassesandnamingclassesasJUnittestsMakingJavamethodsrunasJUnittestsAddingassertstoreporterrorsduringtheexecutionHowtorunJUnittestsfromtheIDEandthecommandlineHowtowritebasicarithmeticstatementsinJavaAboutJavacomments
Followalongwiththetext,andusetheexamplecodeasaguide.Ifyouhaveissuesthencomparethecodeyouhavewrittencarefullyagainstthecodeinthebook.
Inthischapterwewilltakeaslightlydifferentapproach.Wewilladvancestep-by-stepthroughthechapterandwewillwriteasimplemethodwhichwewillrunasaJUnittest.
MyFirstJUnitTestThecodewillcalculatetheanswerto“2+2”,andthenassertthattheansweris“4”.
Thecodewewritewillbeverysimple,andwilllooklikethefollowing:1packagecom.javafortesters.chap003myfirsttest.examples;
2importorg.junit.Test;
3importstaticorg.junit.Assert.assertEquals;
4
5publicclassMyFirstTest{
6
7@Test
8publicvoidcanAddTwoPlusTwo(){
9intanswer=2+2;
10assertEquals("2+2=4",4,answer);
11}
12}
I’mshowingyouthisnow,soyouhaveanunderstandingofwhatweareworkingtowards.Ifyougetstuck,youcanreferbacktothisfinalstateandcompareitwithyourcurrentstatetohelpresolveanyproblems.
PrerequisitesI’massumingthatyouhavefollowedthesetupchapterandhavethefollowinginplace:
JDKInstalledIDEInstalledMavenInstalledCreatedaproject
AddedJUnittotheprojectpom.xml
Wearegoingtoaddallthecodewecreateinthisbooktotheprojectyouhavecreated.
CreateAJUnitTestClassThefirstthingwehavetodoiscreateaclass,towhichwewilladdourJUnittestmethod.
AclassisthebasicbuildingblockforourJavacode.SowewanttocreateaclasscalledMyFirstTest.
ThenameMyFirstTesthassomeveryimportantfeatures.
ItstartswithanuppercaseletterIthasthewordTestattheendItusescamelcase
Itstartswithanuppercaseletterbecause,byconvention,Javaclassesstartwithanuppercaseletter.Byconventionmeansthatitdoesn’thaveto.Youwon’tseeJavathrowanyerrorsifyounametheclassmyFirstTestwithalowercaseletter.Whenyourunthecode,Javawon’tcomplain.
Buteveryonethatyouworkwithwill.
WeexpectJavaclassestostartwithanuppercaseletterbecausetheyarepropernames.
Trustme.
Getinthehabitofnamingyourclasseswiththefirstletterinuppercase.Thenwhenyoureadcodeyoucantellthedifferencebetweenaclassandavariable,andyou’llexpectthesamefromcodethatotherpeoplehavewritten.
IthasthewordTestattheend.Wecantakeadvantageofthe‘outofthebox’MavenfunctionalitytorunourJUnittestsfromthecommandline,insteadoftheIDE,bytypingmvntest.Thismightnotseemimportantnow,butatsomepointwearegoingtowanttorunourcodeautomaticallyaspartofabuildprocess.AndwecanmakethateasierifweaddTestintheClassname,eitherasthestartoftheclassname,orattheend.Bynamingourclassesinthisway,MavenwillautomaticallyrunourJUnittestclassesattheappropriatepartofthebuildprocess.
IncorrectlyNamedClassesWillRunFromtheIDE
VeryoftenwerunourJUnittestcodefromtheIDE.AndtheIDEwillrunthemethodsinJUnittestclasseseveniftheclassesarenotnamedasMavenrequires.IfwedonotnameaclasscorrectlythenitwillnotrunfromthecommandlinewhenwetypemvntestbutbecausewesawitrunintheIDE,webelieveitisrunning.
Thisleavesusthinkingwehavemorecoveragethanweactuallydo.
Itusescamelcasewhereeach‘word’inastringofconcatenatedwordsstartswithanuppercaseletter.ThisagainisaJavaconvention,itisnotenforcedbythecompiler.Butpeoplereadingyourcodewillexpecttoseeitwrittenlikethis.
MavenProjectsneedtobeimportedAsyoucode,ifyouseealittlepopupinIntelliJwhichsays“MavenProjectsneedtobeimported”.Clickthe“EnableAuto-Import”.Thiswillmakeyourlifeeasierasitwillautomaticallyaddimportstatementsinyourcodeandupdatewhenyouchangeyourpom.xmlfile.
TocreatetheclassIntheIDE,openuptheProjecthierarchysothatyoucanseethesrc\test\javabranchandthesrc\main\javabranch.
Myprojecthierarchylookslikethis:+javaForTesters
+.idea
+src
+main
+java
+resources
+test
+java
.ideaistheIntelliJfolder,soIcanignorethat.
IrightclickonthejavafolderundertestandselecttheNew\JavaClassmenuitem.
Or,Icouldclickonthejavafolderundertestandusethekeyboardshortcutalt+insert,andselectJavaClass(onaMacusectrl+n)
TypeinthenameoftheJavaclassthatyouwanttocreatei.e.MyFirstTestandselect[OK]
Don’tworryaboutthepackagestructurefornow.Wecaneasilymanuallymoveourcodearoundlater.OrhaveIntelliJmoveitaroundforususingrefactoring.
TemplatecodeYoumightfindthatyouhaveacodeblockofcommentswhichIntelliJaddedautomatically/**
*CreatedwithIntelliJIDEA.
*User:Alan
*Date:24/04/13
*Time:11:48
*TochangethistemplateuseFile|Settings|FileTemplates.
*/
Youcanignorethiscodeasitisacomment.Youcandeleteallthoselinesifyouwantto.
IntroductiontoCommentsInJavaCommentsareexplanatorytextthatisnotexecuted.
Youcanuse//tocommentouttotheendofaline.
Youcancommentoutblocksoftextbyusing/*and*/
Where/*delimitsthestartofthecommentand*/delimitstheendofthecomment.
So/*everythinginsideisacomment*/
/*Commentscreatedwithforwardslashasteriskcanspanmultiplelines*/
AddtheclasstoapackageIntelliJwillhavecreatedanemptyclassforus.e.g.publicclassMyFirstTest{
}
Andsincewedidn’tspecifyapackage,itwillbeattherootlevelofourtest\javahierarchy.
Wehavetwowaysofcreatingapackageandthenmovingtheclassintoit:
ManuallycreatethepackageanddraganddroptheclassintoitAddthepackagestatementintoourcodeandhaveIntelliJmovetheclass
ManuallycreatethepackageanddraganddroptheclassintoitbyrightclickingonthejavafolderundertestandselectingNew\Package,thenenterthepackagenameyouwanttocreate.
Forthisbook,I’mgoingtosuggestthatyouusethetoplevelpackagestructure:
com.javafortesters
Andthennameanysubstructuresasrequired.Soforthisclasswecouldcreateapackagecalledcom.javafortesters.chap003myfirsttest.examples.Youdon’thavetousethechap003prefix,butitmighthelpyoutraceyourcodebacktothechapterinthebook.Iusethisconventiontohelpyoufindtheexampleandexercisesourcecodeinthesourcedownload.
PackageNamingInJava,packagenamestendtobealllowercase,andnotusecamelCase.
Ifwewantto,wecanaddthepackagestatementintoourcodeandhaveIntelliJmovetheclass:
Addthefollowinglineasthefirstlineintheclass:
packagecom.javafortesters.chap003myfirsttest.examples;
Thesemi-colonattheendofthelineisimportantbecauseJavastatementsendwithasemi-colon.
IntelliJwillhighlightthislinewitharedunderscorebecauseourclassisnotinafolderstructurethatrepresentsthatpackage.
IntelliJcandomorethanjusttelluswhatourproblemsare,itcanalsofixthisproblemforusifweclickthemouseintheunderscoredtext,andthenpressthekeysalt+return.
IntelliJwillshowapopupmenuwhichwillofferustheoptionto:Movetopackagecom.javafortesters.chap003myfirsttest.examples
SelectthisoptionandIntelliJwillautomaticallymovetheclasstothecorrectlocation.
YoucouldcreatethepackagefirstOfcourse,Icouldhavecreatedthepackagefirst,butsometimesIliketocreatetheclasses,andconcentrateonthecode,beforeIconcentrateontheorderingandcategorizationofthecode.
Youwilldevelopyourownstyleofcodingasyoubecomemoreexperienced.IliketohavetheIDEdoasmuchworkformeasIcan,whileIremaininthe‘flow’ofcoding.
TheEmptyClassExplainedpackagecom.javafortesters.chap003myfirsttest.examples;
publicclassMyFirstTest{
}
Ifyou’vefollowedalongthenyouwillhaveanemptyclass,inthecorrectpackageandtheProjectwindowwillshowadirectorystructurethatmatchesthepackagehierarchyyouhavecreated.
PackageStatement
Thepackagestatementisalineofcodewhichdefinesthepackagethatthisclassbelongsin.packagecom.javafortesters.chap003myfirsttest.examples;
Whenwewanttousethisclassinourlatercodethenwewouldimporttheclassfromthispackage.
Thepackagemapsontothephysicalfolderstructurebeneathyoursrc\testfolder.Soifyoulookinexplorerunderyourprojectfolderyouwillseethatthepackageisactuallyanestedsetoffolders.+src
+test
+java
Andunderneaththejavafolderyouwillhaveafolderstructurethatrepresentsthepackagestructure.+com
+javafortesters
+chap003myfirsttest
+examples
Javaclassesonlyhavetobeuniquelynamedwithinapackage.SoIcouldcreateanotherclasscalledMyFirstTestandplaceitintoadifferentpackageinmysourcetreeandJavawouldnotcomplain.Iwouldsimplyhavetoimportthecorrectpackagestructuretogetthecorrectversionoftheclass.
ClassDeclaration
Thefollowinglines,areourclassdeclaration.publicclassMyFirstTest{
}
Wehavetodeclareaclassbeforeweuseit.Andwhenwedoso,wearealsodefiningtherulesabouthowotherclassescanuseittoo.
Heretheclasshaspublicscope.Thismeansthatanyclass,inanypackage,canusethisclassiftheyimportit.
JavahasmorescopedeclarationsJavahasotherscopedeclarations,likeprivateandprotectedbutwedon’thavetoconcernourselveswiththoseyet.
WhenwecreateclassesthatwillbeusedforJUnittests,weneedtomakethempublicsothatJUnitcanusethem.
The{and}areblockmarkers.Theopeningbrace{delimitsthestartofablock,andtheclosingbrace}delimitstheendofablock.
Allthecodethatwewriteforaclasshastogobetweentheopeningandclosingblockthatrepresentstheclassbody.
Inthiscasetheclassbodyisempty,becausewehaven’twrittenanycodeyet,butwestillneedtohavetheblockmarkers,otherwiseitwillbeinvalidJavasyntaxandyourIDEwillflagthecodeasbeinginerror.
CreateaMethodWearegoingtocreateamethodtoaddtwonumbers.Specifically2+2.
Icreateanewmethodbytypingoutthemethoddeclaration:publicvoidcanAddTwoPlusTwo(){
}
Remember,themethoddeclarationisenclosedinsidetheclassbodyblock:publicclassMyFirstTest{
publicvoidcanAddTwoPlusTwo(){
}
}
public
ThismethodisdeclaredaspublicmeaningthatanyclassthatcanuseMyFirstTestcancallthemethod.
WhenweuseJUnit,anymethodthatwewanttouseasaJUnittestshouldbedeclaredaspublic.
void
Thevoidmeansthatthemethoddoesnotreturnavaluewhenitiscalled.Wewillcoverthisindetaillater,butasageneralrule,ifyouaregoingtomakeamethodaJUnittest,youprobablywanttodeclareitasvoid.
()
Everymethoddeclarationhastodefinewhatparametersthemethodcanbecalledwith.Atthemomentwehaven’texplainedwhatthismeansbecauseourmethoddoesn’ttakeanyparameters,andsoafterthemethodnamewehave“()”,theopenandcloseparentheses.Ifwedidhaveanyparameterstheywouldbedeclaredinsidetheseparentheses.
{}
Inordertowritecodeinamethodweadditinthecodeblockofthemethodbodyi.e.insidetheopeningandclosingbraces.
Wehaven’twrittenanycodeinthemethodyet,sothecodeblockisempty.
NamingJUnitTest`MethodsAlotofpeopledon’tgiveenoughthoughttoJUnittestmethodnames.AndusenameslikeaddTestoraddNumbers.Itrytowritenamesthat:
explainthepurposeofthemethodwithoutwritingadditionalcommentsdescribethecapabilityorfunctionwewanttocheckshowthescopeofwhatisbeingchecked
MakethemethodaJUnittestWecanmakethemethodaJUnittest.Byannotatingitwith@Test.
Inthisbookwewilllearnhowtouseannotations.Werarelyhavetocreatecustomannotationswhenautomating,sowewon’tcoverhowtocreateyourownannotationsinthisbook.
JUnitimplementsafewannotationsthatwewilllearn.Thefirst,andmostfundamental,isthe@Testannotation.JUnitonlyrunsthemethodswhichareannotatedwith@TestasJUnittests.Wecanhaveadditionalmethodsinourclasseswithouttheannotation,andJUnitwillnottryandrunthose.
Becausethe@TestannotationcomeswithJUnitwehavetoimportitintoourcode.
Whenyoutype@Testonthelinebeforethemethoddeclaration.TheIDEwillhighlightitasanerror.@Test
publicvoidcanAddTwoPlusTwo(){
}
Whenweclickonthelinewiththeerrorandpressthekeycombinationalt+returnthenwewillreceiveanoptionto:ImportClass
ChoosingthatoptionwillresultinIntelliJaddingtheimportstatementintoourclass.importorg.junit.Test;
Wehavetomakesurethatwelookatthelistofimportoptionscarefully.Sometimeswewillbeofferedmultipleoptions,becausetheremaybemanyclasseswiththesamename,wherethedifferenceisthepackagetheyhavebeenplacedinto.
IfyouselectthewrongimportIfyouaccidentallyselectthewrongimportthensimplydeletetheexistingimportstatementfromthecode,andthenuseIntelliJtoalt+returnandimportthecorrectclassandpackage.
CalculatethesumToactuallycalculatethesum2+2Iwillneedtocreateavariable,thenIcanstoretheresultofthecalculationinthevariable.intanswer=2+2;
Variablesareasymbolwhichrepresentsomeothervalue.Inprogramming,weusethemtostorevalues:strings,integersetc.sothatwecanusethemandamendthemduringtheprogramcode.
Iwillcreateavariablecalledanswer.
Iwillmakethevariablean‘int’.intdeclaresthetypeofvariable.intisshortforintegerandisaprimitivetype,sodoesn’thavealotoffunctionalityotherthanstoringanintegervalueforus.Anintisnotaclasssodoesn’thaveanymethods.
Thesymbol2inthecodeiscalledanumericliteral,oranintegerliteral.
AninthaslimitsAnintcanstorevaluesfrom-2,147,483,648to2,147,483,647.e.g.
intminimumInt=-2147483648;
intmaximumInt=2147483647;
WhenIcreatethevariableIwillsetitto2+2.
JavawilldothecalculationforusbecauseIhaveusedthe+operator.The+operatorwillactontwointoperandsandreturnaresult.i.e.itwilladd2and2andreturnthevalue4whichwillbestoredintheintvariableanswer.
JavaOperatorsJavahasafewobviousbasicoperatorswecanuse:
+toadd-tosubtract*tomultiply/todivide
Therearemore,butwewillcoverthoselater.
AssertthevalueThenextthingwehavetodoisassertthevalue.assertEquals("2+2=4",4,answer);
Whenwewrite@Testmethodswehavetomakesurethatweassertsomethingbecausewewanttomakesurethatourcodereportsfailurestousautomatically.
Anassertisaspecialtypeofcheck:
Ifthecheckfailsthentheassertthrowsanassertionerrorandourmethodwillfail.Ifthecheckpassesthentheassertdoesn’thaveanyside-effects
TheassertswewillinitiallyuseinourcodecomefromtheJUnitAssertpackage.
SowhenItypetheassert,IntelliJwillshowthestatementasbeinginerror,becauseIhaven’timportedtheassertEqualsmethodorAssertclassfromJUnit.
TofixtheerrorIwillalt+returnontheassertEqualsstatementandchooseto:staticimportmethod…
from
Assert.assertEqualsintheorg.junitpackage
IntelliJwillthenaddthecorrectimportstatementintomycode.importstaticorg.junit.Assert.assertEquals;
TheassertEqualsmethodispolymorphic.Whichsimplymeansthatitcanbeusedwithdifferenttypesofparameters.
Ihavechosentouseaformof:assertEquals("2+2=4",4,answer);
Where:
assertEqualsisanassertthatchecksiftwovaluesareequal
"2+2=4"isamessagethatisdisplayediftheassertfails.4isanintliteralthatrepresentstheexpectedvalue,i.e.Iexpect2+2toequal4answeristheintvariablewhichhastheactualvalueIwanttocheckagainsttheexpectedvalue
Icouldhavewrittentheassertas:assertEquals(4,answer);
Inthisform,Ihavenotaddedamessage,soiftheassertfailstherearefewercluestellingmewhatshouldhappen,andinsomecasesImightevenhavetoaddacommentinthecodetoexplainwhattheassertdoes.
ItrytoremembertoaddamessagewhenIusetheJUnitassertmethodsbecauseitmakesthecodeeasiertoreadandhelpsmewhenassertsdofail.
Notethatinbothforms,theexpectedresultistheparameter,beforetheactualresult.
IfyougetthesethewrongwayroundthenJUnitwon’tthrowanerror,sinceitdoesn’tknowwhatyouintended,buttheoutputfromafailedassertwouldmisleadyou.e.g.ifIaccidentallywrote2+3wheninitializingtheintanswer,andIputtheexpectedandactualresultthewrongwayround,thentheoutputwouldsaysomethinglike:java.lang.AssertionError:2+2=4expected:<5>butwas:<4>
Andthatwouldconfuseme,becauseIwouldexpect2+2toequal4.
AssertionTipsTrytoremembertoaddamessageintheassertiontomaketheoutputreadable.
Makesurethatyouputtheexpectedandactualparametersinthecorrectorder.
Runthe@TestmethodNowthatwehavewrittenthemethod,itistimetorunitandmakesureitpasses.
Todothateither:
Runallthe@Testannotatedmethodsintheclass
rightclickontheclassnameintheProjectHierarchyandselect:Run'MyFirstTest'
clickontheclassintheProjectHierarchyandpressthekeycombination:ctrl+shift+F10
rightclickontheclassnameinthecodeeditorandselect:Run'MyFirstTest'
Runasingle@Testannotatedmethodintheclass
rightclickonthemethodnameinthecodeeditorandselect:Run'canAddTwoPlusTwo()'
clickonthemethodnameinthecodeeditorandpressthekeycombination:ctrl+shift+F10
Sinceweonlyhaveone@Testannotatedmethodatthemomenttheywillbothachievethesameresult,butwhenyouhavemorethanone@Testannotatedmethodintheclassthentheabilitytorunindividualmethods,ratherthanallthemethodsintheclasscancomeinveryhandy.
Runallthe@Testannotatedmethodsfromthecommandline
Ifyouknowhowtousethecommandlineonyourcomputer,andchangedirectorythenyoucanalsorunthe@Testannotatedmethodsfromthecommandlineusingthecommand:
mvntest
Todothis:
openacommandprompt,ensurethatyouareinthesamefolderastherootofyourproject.i.ethesamefolderasyourpom.xmlfilerunthecommandmvntest
YoushouldseetheannotatedmethodsrunandtheMavenoutputtothecommandline.
SummaryThatwasafairlyinvolvedexplanationofaverysimpleJUnittestclass:1packagecom.javafortesters.chap003myfirsttest.examples;
2importorg.junit.Test;
3importstaticorg.junit.Assert.assertEquals;
4
5publicclassMyFirstTest{
6
7@Test
8publicvoidcanAddTwoPlusTwo(){
9intanswer=2+2;
10assertEquals("2+2=4",4,answer);
11}
12}
Hopefullywhenyoureadthecodenow,itallmakessense,andyoucanfeelconfidentthatyoucanstartcreatingyourownsimpleselfcontainedtests.
ThisbookdiffersfromnormalpresentationsofJava,becausetheywouldstartwithcreatingsimpleapplicationswhichyourunfromthecommandline.
Whenwewriteautomationcode,wespendalotoftimeworkingintheIDEandrunningthe@TestannotatedmethodsfromtheIDE,sowecodeandrunJavaslightlydifferentlythanifyouwerewritinganapplication.
ThisalsomeansthatyouwilllearnJavaconceptsinaslightlydifferentorderthanotherbooks,buteverythingyoulearnwillbeinstantlyusable,ratherthanlearningthingsin
ordertoprogressthatyouarenotlikelytouseveryoftenintherealworld.
Althoughthereisnotalotofcode,wehavecoveredthebasicsofalotofimportantJavaconcepts.
OrderingclassesintopackagesImportingclassesfrompackagestousethemCreatingandnamingclassesCreatingmethodsCreatingaJUnitTestAddinganassertiontoaJUnittestRunning@TestannotatedmethodsfromtheIDEprimitivetypesbasicarithmeticoperatorsanintroductiontoJavavariablesJavacommentsJavastatementsJavablocks
YoualsoencounteredthefollowingIntelliJshortcutkeys:
Function Windows MacCreateNew alt+insert ctrl+n
IntentionActions alt+enter alt+enter
IntentionActions alt+return alt+return
RunJUnitTest ctrl+shift+F10 ctrl+shift+F10
Andnowthatyouknowthebasics,wecanproceedfasterthroughthenextsections.
Exercise:Checkfor5insteadof4Amendthecodesothattheassertionmakesacheckfor5astheexpectedvalueinsteadof4:
Runthemethodandseewhathappens.Thiswillgetyouusedtoseeingtheresultofafailingmethod.
Exercise:Createadditional@Testannotatedmethodstocheck:2-2=04/2=22*2=4
Exercise:CheckthenamingoftheJUnittestclasses:WhenyourunJUnittestclassesfromtheIDEtheydonotrequire‘Test’atthestartorendofthename.ButtheydoneedthatconventiontorunfromMaven.Verifythis.
Createaclasswithamethodcontainingafailingasserte.g.assertTrue(false);
Renametheclasstothedifferentrulesbelow,andrunitfrommvntestandfromtheIDEsoyouseethenamingmakesadifference.
Testatthestarte.g.TestNameClassrunsintheIDEandfrommvntestTestattheende.g.NameClassTestrunsintheIDEandfrommvntestTestinthemiddlee.g.NameTestClassrunsintheIDEbutnotfrommvntestwithoutTeste.g.NameClassrunsintheIDEbutnotfrommvntest
ReferencesandRecommendedReading
CamelCaseexplanationonWikiPediaen.wikipedia.org/wiki/CamelCase
OfficialOracleJavaDocumentationWhatisanObject?
docs.oracle.com/javase/tutorial/java/concepts/object.htmlWhatisaClass?
docs.oracle.com/javase/tutorial/java/concepts/class.htmlJavaTutorialonPackageNamingconventions
docs.oracle.com/javase/tutorial/java/package/namingpkgs.htmlJavacodeblocks
docs.oracle.com/javase/tutorial/java/nutsandbolts/expressions.htmlJavaOperators
docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.htmlJUnit
HomePagejunit.org
Documentationgithub.com/junit-team/junit/wiki
APIDocumentationjunit.org/javadoc/latest
@Testjunit.org/javadoc/latest/org/junit/Test.html
IntelliJIntelliJEditorAutoImportSettings
jetbrains.com/idea/webhelp/maven-importing.htmlIntelliJMavenImportingSettings
jetbrains.com/idea/webhelp/maven-importing.html
ChapterFour-WorkwithOtherClasses
ChapterSummaryInthischapteryouwilllearn:
HowtousestaticmethodsofanotherclassHowtoinstantiateaclasstoanobjectvariableHowtoaccessstaticfieldsandconstantsonaclassThedifferencebetweenIntegervalueandinstantiation
Inthischapteryouaregoingtolearnhowtouseotherclassesinyour@Testmethodcode.Eventuallythesewillbeclassesthatyouwrite,butforthemomentwewilluseotherclassesthatarebuiltintoJava.
Youhavealreadydonethisinthepreviouschapter.BecauseyouusedtheJUnitAssertclasstocheckconditions,butweimporteditstatically,soyoumightnothavenoticed.(I’llexplainwhatstaticimportmeansinthenextchapter).
Butfirst,someguidanceonhowtolearnJava.
Use@TestmethodstounderstandJavaWhenIworkwithpeoplelearningJava,IencouragethemtowritemethodsandassertionswhichhelpthemunderstandtheJavalibrariestheyareusing.
Forexample,youhavealreadyseenaprimitivetypecalledanint.
JavaalsoprovidesaclasscalledInteger.
BecauseIntegerisaclass,ithasmethodsthatwecancall,andwecaninstantiateanobjectvariableasanInteger.
WhenIcreateanintvariable,allIcandowithit,isstoreanumberinthevariable,andretrievethenumber.
IfIcreateanIntegervariable,Igainaccesstoalotofmethodsontheintegere.g.
compareTo-compareittoanotherintegerintValue-returnanintprimitivelongValue-returnalongprimitiveshortValue-returnashortprimitive
ExploretheIntegerclasswith@TestmethodsInfactyoucanseeforyourselfthemethodsavailabletoaninteger.
Createanewpackage:com.javafortesters.chap004testswithotherclasses.examples
CreateanewclassIntegerExamplesTestCreateamethodintegerExplorationAnnotatethemethodwith@TestsoyoucanrunitwithJUnit
Youshouldendupwithsomethinglikethefollowing:packagecom.javafortesters.chap004testswithotherclasses.examples;
importorg.junit.Test;
publicclassIntegerExamplesTest{
@Test
publicvoidintegerExploration(){
}
}
WecanusetheintegerExplorationmethodtoexperimentwiththeIntegerclass.
InstantiateanIntegerClass
ThefirstthingweneedtodoiscreateavariableoftypeInteger.Integerfour=newInteger(4);
BecauseIntegerisaclass,thisiscalledinstantiatingaclassandthevariableisanobjectvariable.
intwasaprimitivetype.Integerisaclass.TouseaclassweinstantiateitwiththenewkeywordThenewkeywordcreatesanewinstanceofaclassThenewinstanceisreferredtoasanobjectoraninstanceofaclass
YoucanalsoseethatIpassedintheliteral4asaparameter.IdidthisbecausetheIntegerclasshasaconstructormethodwhichtakesanintasaparametersotheobjecthasavalueof4.
WhatisaConstructor?Aconstructorisamethodonaclasswhichiscalledwhenanewinstanceoftheclassiscreated.
Aconstructorcantakeparameters,butneverreturnsavalueandisdeclaredwithoutareturntype.e.g.publicInteger(intvalue){...}
Aconstructorhasthesamenameastheclassincludingstartingwithanuppercaseletter.
TheIntegerclassactuallyhasmorethanoneconstructor.Youcanseethisforyourself.
TypeinthestatementtoinstantiateanewIntegerobjectwiththevalue4Clickinsidetheparentheseswherethe4is,asifyouwereabouttotypeanewparameter,pressthekeysctrl+p(cmd+ponaMac)
Youshouldseeapop-upshowingyoualltheformstheconstructorcantake.InthecaseofanIntegeritcanacceptanintoraString.
CheckthatintValuereturnsthecorrectint
WeknowthattheIntegerclasshasamethodintValuewhichreturnsanint,sowecancreateanassertiontocheckthereturnedvalue.
AfterthestatementwhichinstantiatestheInteger.
AddanewstatementwhichassertsthatintValuereturnsanintwiththevalue4.assertEquals("intValuereturnsint4",
4,four.intValue());
Whenyourunthismethoditshouldpass.
InstantiateanIntegerwithaString
WesawthatoneoftheconstructorsforIntegercantakeaString,soletswritesomecodetoexperimentwiththat.
InstantiateanewIntegervariable,callingtheIntegerconstructorwiththeString"5",AssertthatintValuereturnstheInteger5
Integerfive=newInteger("5");
assertEquals("intValuereturnsint5",
5,five.intValue());
QuickSummary
Itmightnotseemlikeitbutwejustcoveredsomeimportantthingsthere.
Didyounoticethatyoudidn’thavetoimporttheIntegerclass?BecausetheIntegerclassisbuiltintothelanguage,wecanjustuseit.Thereareafewclasseslikethat,Stringisanotherone.Theclassesdoexistinapackagestructure,theyareinjava.lang,butyoudon’thavetoimportthemtousethem.
Wejustlearnedthattouseanobjectofaclass,thatsomeoneelsehasprovided,orthatwewrite,wehavetoinstantiatetheobjectvariablesusingthenewkeyword.Usectrl+ptohavetheIDEshowyouwhatparametersamethodcantake(cmd+ponaMac).Whenweinstantiateaclasswiththenewkeyword,aconstructormethodontheclassiscalledautomatically.
AutoBoxing
IntheversionsofJavathatwewillbeusing,wedon’tactuallyneedtoinstantiatetheIntegerclasswiththenewkeyword.
WecantakeadvantageofaJavafeaturecalled‘autoboxing’whichwasintroducedinJavaversion1.5.Autoboxingwillautomaticallyconvertfromaprimitivetypetotheassociatedclassautomatically.
SowecaninsteadsimplyassignaninttoanIntegerandautoboxingwilltakecareoftheconversionforuse.g.Integersix=6;
assertEquals("autoboxingassignmentfor6",
6,six.intValue());
StaticmethodsontheIntegerclass
Anotherfeaturethatclassesprovidearestaticmethods.
YoualreadyusedstaticmethodsontheAssertclassfromJUnit.i.e.assertEquals
Astaticmethodoperatesattheclasslevel,ratherthantheinstanceorobjectlevel.Whichmeansthatwedon’thavetoinstantiatetheclassintoavariableinordertocallastaticmethod.
e.g.Integerprovidesstaticmethodslike:
Integer.valueOf(Strings)-returnsanIntegerinitializedwiththevalueoftheString
Integer.parseInt(Strings)-returnsanintinitializedwiththevalueoftheString
YoucanseeallthestaticmethodsbylookingatthedocumentationforInteger,orinyourcodewriteInteger.thenimmediatelyaftertypingthe.theIDEshouldshowyouthecodecompletionforallthestaticmethods.
Foreachofthesemethods,ifyoupressctrl+q(ctrl+jonaMac)youshouldseethehelpfileinformationforthatmethod.
Exercise:ConvertaninttoHex:IntegerhasastaticmethodcalledtoHexStringwhichtakesanintasparameter,thisreturnstheintasaStringformattedinhex.
Writean@TestannotatedmethodwhichusestoHexStringandasserts:
that11becomesbthat10becomesathat3becomes3that21becomes15
PublicConstantsontheIntegerclass
Itispossibletocreatevariablesataclasslevel(thesearecalledfields)whicharealsostatic.Thesefieldvariablesareavailablewithoutinstantiatingtheclass.TheIntegerclassexposesafewofthesebutthemostimportantonesareMIN_VALUEandMAX_VALUE.
Inadditiontobeingstaticfields,thesearealsoconstants,inthatyoucan’tchangethem.(We’llcoverhowtodothisinalaterchapter).Thenamingconventionforconstantsistouseonlyuppercase,with_astheworddelimiter.
MIN_VALUEandMAX_VALUEcontaintheminimumandmaximumvaluesthatanintcansupport.Itisworthusingthesevaluesinsteadof-2147483648and2147483647toensurefuturecompatibilityandcrossplatformcompatibility.
Toaccessaconstant,youdon’tneedtoaddparenthesisbecauseyouareaccessingavariable,andnotcallingamethod.
i.e.youwrite“Integer.MAX_VALUE”andnot“Integer.MAX_VALUE()”.
Exercise:ConfirmMAXandMINIntegersizes:Inthepreviouschapterwesaidthatanintrangedfrom-2147483648,to2147483647.IntegerhasstaticconstantsMIN_VALUEandMAX_VALUE.
Writean@Testannotatedmethodtoassertthat:
Integer.MIN_VALUEequals-2147483648Integer.MAX_VALUEequals2147483647
DothisregularlyIencourageyoutodothefollowingregularly.
Whenyouencounter:
anyJavalibrarythatyoudon’tknowhowtousepartsofJavathatyouareunsureofcodeonyourteamthatyoudidn’twriteanddon’tunderstand
Thenyoucan:
readthedocumentation-ctrl+q(ctrl+jonMac)oron-linewebdocsreadthesource-ctrlandclickonthemethod,toseethesourcewritesome@Testannotatedmethods,withassertions,tohelpyouexplorethefunctionalityofthelibrary
Whenwritingthe@Testmethodsyouneedtokeepthefollowinginmind:
writejustenoughcodetotriggerthefunctionalityensureyouwriteassertionstatementsthatcoverthefunctionalitywellandarereadableexperimentwith‘odd’circumstances
Thiswillhelpyouwhenyoucometowriteassertionsagainstyourowncodeaswell.
WarningsaboutIntegerIusedIntegerinthischapterbecauseweusedtheintprimitiveinanearlierchapterandIntegeristherelatedfollowonclass.
But…experienceddeveloperswillnowbeworriedthatyouwillstartusingIntegerinyourcode,andworse,instantiatingnewintegersinyourcodee.g.newInteger(0)
Theyworrybecausewhileanintequalsanint,anIntegerdoesnotalwaysequalanInteger.
I’mlessworriedbecause:
Itrustyou,Automationcodehasslightlydifferentusagesthanproductioncodeandyou’llmorethanlikelyusetheIntegerstaticmethodsI’musingthisasanexampleofinstantiatingaclassandusingstaticmethods,Thisisonly“Chapter4”andwestillhaveawaytogo
I’llillustratewithacodeexample,whytheexperienceddevelopersareconcerned.Youmightnotunderstandthenextfewparagraphsyet,butIjustwanttogiveyoualittledetailastowhyoneInteger,oroneObject,doesnotalwaysequalanotherObject.
e.g.ifthefollowingassertionswereinan@Testmethodthentheywouldpass:assertEquals(4,4);
assertTrue(4==4);
Notethat“==”istheJavaoperatorforcheckingifonethingequalsanother.
Ifthefollowingcodewasinan@Testmethod,thenthesecondassertionwouldfail:IntegerfirstFour=newInteger(4);
IntegersecondFour=newInteger(4);
assertEquals(firstFour,secondFour);
assertTrue(firstFour==secondFour);
Specifically,thefollowingassertionwouldfail:assertTrue(firstFour==secondFour);
Whyisthis?
Well,primitivesaresimpleandthereisnodifferencebetweenvalueandidentityforprimitives.Every4inthecodereferstothesame4.
Objectsaredifferent,weinstantiatethem,sothetwoIntegervariables(firstFourandsecondFour)bothrefertodifferentobjects.Eventhoughtheyhavethesame‘value’,theyaredifferentobjects.
WhenIdoanassertEquals,JUnitusestheequalsmethodontheobjecttocomparethe‘value’ortheobject(i.e.4inthiscase).ButwhenIusethe"=="operator,Javaischeckingifthetwoobjectvariablesrefertothesameinstantiation,andtheydon’t,theyrefertotwoindependentlyinstantiatedobjects.
SotheassertEqualsisactuallyequivalentto:assertTrue(firstFour.equals(secondFour));
Don’tworryifyoudon’tunderstandthisyet.Itwillmakesenselater.
Fornow,justrecognizethat:
youcancreateobjectinstancesofaclasswiththenewkeyword,andusethenon-staticmethodsontheclasse.g.anInteger.intValue()youcanaccessthestaticmethodsontheclasswithoutinstantiatingtheclassasanobjecte.g.Integer.equals(..).
SummaryYoulearnedthatinIntelliJyoucanpressctrlandthentheleftmousebuttontoclickonamethodnameandIntelliJwilljumptothesourceofthatmethod.
Youlearnedthefollowingshortcutkeys:
Function Windows MacShowParameters ctrl+p cmd+p
ShowJavaDoc ctrl+q ctrl+j
Youalsolearnedaboutstaticmethodsandthedifferencebetweenobjectvalueandobjectidentity.
Whateveryoulearninthisbook,makesureyoucontinuetoexperimentwithwritingassertionsaroundcodethatyouuseorwanttounderstand.
Youalsolearnedhowtoinstantiateanewobjectandwhataconstructordoes.
ReferencesandRecommendedReading
CreatingObjectsdocs.oracle.com/javase/tutorial/java/javaOO/objectcreation.html
Autoboxingdocs.oracle.com/javase/tutorial/java/data/autoboxing.html
Integerdocs.oracle.com/javase/7/docs/api/java/lang/Integer.html
ChapterFive-WorkingwithOurOwnClasses
ChapterSummaryInthischapteryouwilllearnhowto:
WriteyourownclassWrite@TestannotatedmethodstohelpcheckyourclassmethodfunctionalityCallthemethodsontheclassCreatestaticmethodsandstaticconstantsSeethedifferencebetweenstaticandnon-staticUsetheIDEtowritemuchofyourcodeforyou
AndyouwilllearnhowtodoallofthisusingTestDrivenDevelopment.
WhenwewritecodeusingTDD(TestDrivenDevelopment)wewrite@Testmethodsandassertionsfirst,andthenwritethecodetomaketheassertionspass.
IliketodothiswhenI’mwritingcodebecauseIcanusetheIDE’sfeaturestohelpmetypelessandwritecodewithfewersyntaxerrors.
ContextThroughoutthisbookIwanttouseexamplesandcodewhichprepareyouforusingJavaintherealworldwhenwritingautomationcodetosupporttesting.AssuchwearegoingtobebuildingdifferenttypesofexamplesthanwewouldinanormalJavabook.
Wearegoingtostartsmall,andIwanttointroduceyoutotheconceptofa‘domain’object.A‘domain’objectisanobjectinstantiatedfromaClasswhichrepresentssomethinginthe‘domain’youareworkingine.g.ifyouworkonabankingapplicationthenyoumighthave‘domain’objectssuchas:account,balance,transaction,etc.
Whenwebuildautomationcodeweneedtobuildalibraryofsupportingobjectstohelpus.Wedothissothat:
ourcodeismaintainable,ourcodebecomemorereadable,ourcodeisfastertowrite,becausewehavehigherlevelabstractionstohelp,weavoidrepeatingcode.
Alloftheabovearenormalcodingprocessgoodness.Becausewhenwewriteautomationcodeforaproductionapplication,wearewritingproductioncode,anditmuststanduptothesamescrutinythatweapplytotheliveproductioncode.
Wehaveanumberofpossibleobjectgroupingswhenwritingautomationcode,thefollowingisoneIusealot:
Physical
Applicatione.g.loginpage,navigationmenu
Environmentale.g.installedURI,port
LogicalDomainEntities
e.g.user,account
Essentiallyyoucanbuildasmanycategorizationsandmodelinglevelsasyouneed,inordertoeffectivelymodelyoursystem.Irecommendthebook‘DomainDrivenDesign’byEricEvans,ifyouwanttolearnmoreaboutdomainmodeling.
FortheexamplesinthischapterwearegoingtolookatanenvironmentaldomainobjectcalledTestAppEnvwhichrepresentsthetestenvironmentwerunourautomationandassertionsagainst.
Imaginethatyouhaveanapplicationundertest,thatyouhaveinstalleditonanumberoftestenvironments,andyouwanttorunyourautomationcodeonanyofthoseenvironments(andpossiblyonlive).
Youdon’twanttohavetochangeyourautomationcodeeverytimeyouuseadifferentenvironment,soyouwanttoabstractawaytheactualenvironmentconfigurationbehindanobjectthatwillhandlethatforyou.
Soinsteadofwritingan@Testmethodlikethefollowing:@Test
publicvoidcheckTitleCorrectOnApp(){
FirefoxDriverdriver=newFirefoxDriver();
driver.get("http://192.123.0.3:67");
assertEquals("Titleshouldmatch",
"TestApp",driver.getTitle());
}
Note:theabovesamplecodeaboveusestheWebDriverAPI,soitwon’tworkifyoutypeitin.Whatitsaysis:startFirefoxbrowser,opentheURL"http://192.123.0.3:67"andcheckthepagetitleis"TestApp".
Youcouldinsteadabstractawaytheapplicationconnectiondetailsintoanenvironmentdomainobject,e.g.TestAppEnv:@Test
publicvoidcheckTitleCorrectOnAppWithDomainObject(){
FirefoxDriverdriver=newFirefoxDriver();
driver.get(TestAppEnv.getUrl());
assertEquals("Titleshouldmatch",
"TestApp",driver.getTitle());
}
Bydoingthis,insteadofhavingahardcodedStringliteral"http://192.123.0.3:67"inallyour@Testmethods,youmakeacalltoanobjectTestAppEnv.getUrl().
Byfollowingalongwiththetextinthischapter,youaregoingtobuildtheTestAppEnvclass,withitsassociated@Testmethodsandassertions.
Firstcreatean@TestmethodThefirstthingwewanttodo,iscreatean@Testmethod.
Todothat,weneedaClasstoputthemethodin.
@Testmethodsresideinthetestfolderhierarchyofyourproject.I’mgoingtocreateapackagecalled
com.javafortesters.chap005testwithourownclasses.domainobject.examples
Andinthatpackage,createaclasscalledTestAppEnvironmentTest.
ReminderonpackageandJUnittestclasscreationUsetheProjectTreetocreatepackages.Clickontheparentpackage,intheappropriatesrcfolderbranche.g.src\test\javathenrightclickandselectNew\Package.Thenenterthepackagename.
Ifyoumessitupyoucandeleteitandstartagain,orjustdragitintothecorrectplaceusingtheProjectTree.
UsetheProjectTreetocreateclasses.RepeattheabovebutchooseNew\JavaClassinthepackageyouwanttocreatetheclass.
packagecom.javafortesters.chap005testwithourownclasses.domainobject.examples;
publicclassTestAppEnvironmentTest{
}
[email protected]’mgoingtocreateonecalledcanGetUrlStaticallybecauseIhavedecidedthatIwanttobeabletoretrievetheURLfromtheTestAppEnvclassstatically,ratherthaninstantiateanewinstanceofTestAppEnveverytimeIwanttouseit.@Test
publicvoidcanGetUrlStatically(){
}
Reminderon@TestmethodcreationCreatethemethodcodeinsidethebodyoftheclass,betweenthestart{andend}codeblockbraces.
Remembertoaddimportorg.junit.Test;toimportthe@TestannotationiftheIDEdoesnotadditautomatically.
Writecodethatdoesn’texistSinceIhaven’tcreatedtheTestAppEnvclassyet,anycodethatIwriteusingit,isn’tgoingtowork.
Thenaturaltendencythen,wouldbetogooffancreatetheTestAppEnvclass,writethecode,andthencomebacktoourJUnittestclassandwritemethodsandassertionsto
checkit.
Wearenotgoingtodothat.Wearegoingtodriveourcodecreationbywritingautomationcode.
SointhecanGetUrlStatically@Testmethodwearegoingtowritethecodethatwewanttoseeexist.
Ineffectwearedesigningthecodebyseeingitinausagecontext.
SoinmymethodcanGetUrlStaticallyIwritetheline:assertEquals("ReturnsHardCodedURL",
"http://192.123.0.3:67",
TestAppEnv.getUrl());
WecanautomaticallyaddtheimportforassertEqualsfromtheJUnitAssertpackage.ButtheIDEwillcomplainthatitcannotresolvesymbolTestAppEnv.Nosurprisethere,sincewehaven’twrittenityet.
ButwearegoingtolettheIDEdothehardliftinghere,andhaveitcreatetheclassforus.
CreateaClassClickonTestAppEnvandpressthekeysalt+enter(IntelliJ’sIntentionActionsshortcutkey)andyoushouldseeasmallpopupmenuofquickfixoptions.Somethinglike:
Createlocalvariable'TestAppEnv'
Createclass'TestAppEnv'
Createfield'TestAppEnv'
Createinnerclass'TestAppEnv'
Createparameter'TestAppEnv'
etc.
TheimportantoneforusisCreateclass'TestAppEnv'
SelectCreateclass'TestAppEnv'thenweneedtotelltheIDEwherewewanttocreateit.
Wearegoingtouseadifferentpackage.
Weusepackagestoorganizeourcode,andjustbecauseour@Testmethodcodehasbeenorganizedintoapackageforthischapter,itdoesn’tmeanthatourdomainobjectneedstobeinthesamepackage.
I’mgoingtouseapackage:packagecom.javafortesters.domainobject;
Sincethisisclassispartofmyabstractionlayer,Idon’twantititinthesrc\test\javafolderstructure,Iwantitinmymaincodesrc\main\java.MakesureyouchangetheTargetdestinationfolderandcreateitinthemaincodebase.
Don’tworryifyoumessitupItisimportantthatwetrytochoosegoodpackagenames,butitisalsoimportantthatwedon’tgettoohunguponit,becausere-organizingthecodeintodifferentpackagesisprettyeasyoncethecodeisworking,andtheIDEhasalotofautomatedrefactoringtoolstomakethatsimple.
Samewiththetargetdestination.Ifyoumessitup,justdeleteitandtryagain,ordragdropthefilesintheProjecttreetogetitthewayyouwant.
Withthedomainobjectclasscreated,jumpbacktoyourJUnittestclass,andseewhatnewerrorexistsinthecode.
CreateamethodNowtheIDEshouldhavehighlightedgetUrl()ashavingaproblembecauseitCannotresolvemethod'getUrl()'
Again,wehaven’tcreatedthatmethod.AndwecanusetheIDEquickfixfunctionalitytohelpus.
ClickonthegetUrlcodeandpressthekeysalt+enterandselectCreatemethod'getUrl'
TheIDEwillcreatethemethodandmayevenaddareturnnull;inthereforustoo,tomakethecodevalid.1packagecom.javafortesters.domainobject;
2
3publicclassTestAppEnv{
4
5publicstaticStringgetUrl(){
6returnnull;
7}
8}
Addthecodetomakethe@TestmethodpassSinceour@Testmethodisbeingwrittentomatchourfictionalenvironment.WeneedthegetUrlmethodtoreturn"http://192.123.0.3:67".
Allwedothen,isreplacenullinthemethodbodycodeblock,withtheStringwewanttoreturn.publicclassTestAppEnv{
publicstaticStringgetUrl(){
return"http://192.123.0.3:67";
}
}
Ifwejumpbacktoour@Testmethodnow.
Weshouldhavenosyntaxerrorsandwecanrunthe@Testmethod.
AquickexplanationofthecodeTherearenonewconceptsinthe@Testmethodyouhavewritten,weareusingthesame
conceptsthatweusedinthepreviouschapter.
TheTestAppEnvclass,allowsustorevisitafewconceptsinmoredetail.
ThemethodgetURLwasdeclaredaspublicstaticString
publicthismethodisaccessibletoanyclassthatimportsTestAppEnvstaticthismethodcanbeusedandcalled,withoutinstantiatingaTestAppEnvobjectStringthismethodreturnsastring,tothecallingcode
BecausethemethodneedstoreturnaStringweaddareturnstatement.return"http://192.123.0.3:67";
ThisparticularreturnstatementpassesbackaStringliteral.WhichisthenusedintheassertEqualsstatementinthemethod.
Exercise:ExperimentwiththecodeReplacetheStringwithanint.Whathappens?ReplacetheStringliteral"http://192.123.0.3:67"[email protected]?
WhatwejustlearnedAgain,wehavecondensedawholebunchofconceptsintoafairlysmallpieceofworkingcode.
Youlearned:
HowtouseIntelliJQuickFixfunctionality“IntentionActions”(alt+enter)towritecodeThebasicsofTDD:
writeafailing@Testmethod,runit,watchitfail,writejustenoughcodetomakeitpass,runit,watchitpass,repeat.
HowtocreateastaticmethodHowtodeclareamethodthatreturnsavalueHowtoreturnavaluefromamethodHowtocallastaticmethodonaClassHowtouseamethod’sreturnedvalueinanassertstatement
NewRequirements
Nowthatwehaveaworking@Testmethod,wecanstarttorefactortheobjectandmakeitmoresuitableforourneeds.
Immediatelythough,ifwehadusedtheString"http://192.123.0.3:67"anywhereinourcode,wecouldreplaceitwithTestAppEnv.getUrl()andgainthebenefitsofabstractionandmaintenance.
I’mgoingtoaddafewmorerequirementssothatwecanlearnalittlemoreJavaandamendourclass.
Sometimesinourautomationcodewedon’talwayswanttogetthefullURL,sometimeswewant,justtheDomainorjustthePort.
Myinitialideaisthatwewanttobeabletodothefollowing:@Test
publicvoidcanGetDomainAndPortStatically(){
assertEquals("JusttheDomain",
"192.123.0.3",
TestAppEnv.DOMAIN);
assertEquals("Justtheport",
"67",
TestAppEnv.PORT);
}
Notice,thatagain,I’mthinkingthroughtheusageandthecodewithan@Testmethod.BywritingthecodeIwanttosee,Icanexperimentwithdifferentconceptsbeforeactuallywritinganyimplementationcodetomakethe@Testmethodpass.
AllwehavetodonowisimplementthetwonewConstantFieldsDOMAINandPORT.
Typeinthenew@Testmethodcode,andusetheIntelliJQuickfixfunctiontocreatetheseConstantFields.
FieldsAfieldisaJavavariablethatisattheclasslevelratherthanlocaltoamethod.
Constantmeansthatitwon’tchangeonceavaluehasbeenassigned.
Fieldsarelocatedwithintheclasscodeblock.And,byconvention,beforeanymethods.
YoushouldendupwithcodelikethefollowinginyourTestAppEnvobject.publicstaticfinalStringDOMAIN="192.123.0.3";
publicstaticfinalStringPORT="67";
public-thefieldcanbeaccessedbyanycodethatimportstheTestAppEnvclassstatic-TestAppEnvdoesnotneedtobeinstantiatedwithnewbeforeusagefinal-thevariablecannotchangeonceavaluehasbeenassignedString-declaresthevariableasaStringobjectDOMAIN,PORT-byconventionconstantsarewritteninuppercase,withmultiplewordsdelimitedby_underscore
IsettheconstantstothethestringvaluesthatwepassedbackoriginallyinthegetUrlmethod.
Ifwerunour@Testmethods,theyshouldpass.
NowRefactorAnimportantelementofTDD,andallprogramming,istorefactor.
Thismeansgoingback.Lookingatourcode.Identifyingwasteandimprovements.Andchangingthecode,suchthatthe@Testannotatedmethodscontinuetopass,andnoexternalinterfacetothecodeisamended.
Inourcase,thismeansthatwecanchangeanyofthecodeinourTestAppEnvsolongaswestillhavetwofieldsnamedDOMAINandPORTandamethodgetUrlwhichreturnsthesameStringobjectsasthatcheckedbytheassertions.
TheobviousthingtochangeisthatwehaverepeatedStringliteralsinourdomainobjectsinceourDOMAINstringandPORTstringarerepeatedaspartofthehardcodedStringingetUrl.i.e.thefollowinglinereturn"http://192.123.0.3:67";
AlittlestringconcatenationSincethevaluesoftheDOMAINconstantandthePORTconstantarepartofthehardcodedStringingetUrlwereallywanttobuildtheStringpassedbackfromgetUrlusingtheDOMAINandPORTconstants,thatwayiftheenvironmentdetailschangethenweonlyhavetoamendthefields,andnottheStringinthemethods.
Stringconcatenationissomethingwedoalotwhenbuildingautomationcodee.g.:
creatingmessagestosendtosystemsgeneratinginputdatacreatinglogmessagesetc.
I’mgoingtoquicklyshowthesimplestwayofconcatenatingStrings.Andinfactyou’vealreadyseenthecodeweneedtouse.+
Yes,the‘plus’signcanjointhevaluesofStringobjectstogether.
IcanamendthegetUrlmethodsothatitusesDOMAINandPORTreturn"http://"+DOMAIN+":"+PORT;
Bydoingthis,IhavereducedtheduplicatedcodeandonlyhavetochangeasinglelineofcodeintheabstractionlayerifIwanttochangetheenvironmentdetailsusedbythe@Testmethods.
RuntheJUnittestclassandmakesurethatthe@Testmethodsstillpass.
ThereismorethatIcoulddotothisclass,butfornowitisgoodenough,andwewillrevisititlater.
TheTestAppEnvcodeI’veincludedthesourcecodewebuiltinthischaptersoyoucancheckyourresults.LaterchapterswillnotincludethefullsourcecodesinceIrecommendthatyoudownloadandviewthefullsourceusedforthebook(seetheIntroductionchapterfordetails).
Afterallthechanges,yourTestAppEnvclassshouldlooklikethefollowing:1packagecom.javafortesters.domainobject;
2
3publicclassTestAppEnv{
4
5publicstaticfinalStringDOMAIN="192.123.0.3";
6publicstaticfinalStringPORT="67";
7
8publicstaticStringgetUrl(){
9return"http://"+DOMAIN+":"+PORT;
10}
11}
Sinceitisaverysimpleclass,wehavenothadtoaddanyadditionalimports.
AndthecodefortheTestAppEnvironmentTestclasswhichweusedtocreateTestAppEnvisshownbelow:1packagecom.javafortesters.chap005testwithourownclasses.domainobject.examples;
2
3importcom.javafortesters.domainobject.TestAppEnv;
4importorg.junit.Test;
5importstaticorg.junit.Assert.assertEquals;
6
7publicclassTestAppEnvironmentTest{
8
9@Test
10publicvoidcanGetUrlStatically(){
11assertEquals("ReturnsHardCodedURL",
12"http://192.123.0.3:67",
13TestAppEnv.getUrl());
14}
15
16@Test
17publicvoidcanGetDomainAndPortStatically(){
18
19assertEquals("JusttheDomain",
20"192.123.0.3",
21TestAppEnv.DOMAIN);
22
23assertEquals("Justtheport",
24"67",
25TestAppEnv.PORT);
26}
27}
StaticUsageversusStaticImport
Onethingtopointout,nowthatwehaveexamples,isthedifferencebetween‘StaticUsage’and‘StaticImport’.
YoucanseeexamplesofbothintheTestAppEnvironmentTestcode.
StaticUsage
WeusethestaticconstantsfromTestAppEnv.SoweimporttheTestAppEnvclass:importcom.javafortesters.domainobject.TestAppEnv;
AndeverytimewewanttousethestaticconstantsDOMAINorPORT,weprefixthemwiththeclassthattheyarefrom,i.e.TestAppEnv,asshowninthecodebelow:TestAppEnv.DOMAIN);
StaticImport
WestaticallyimporttheassertEqualsfromJUnit.importstaticorg.junit.Assert.assertEquals;
ThismeansthatwecantypeassertEqualsinourcodewithouthavingtoprefixitwithAssertinthesamewaythatwedofortheDOMAINandPORTconstantsfromTestAppEnve.g.assertEquals("ReturnsHardCodedURL",
"http://192.123.0.3:67",
TestAppEnv.getUrl());
Theonlydifferenceistheimport
BoththeassertEqualsmethod,andtheconstantsDOMAINandPORT,aredeclaredasstaticandpublic,intheirrespectiveclasses.
TheonlydifferenceinourJUnittestcode,ishowweimportedthem.
HadIimportedtheJUnitassertinanon-staticmanneri.e.thesamewayIimportedTestAppEnv:importorg.junit.Assert;
ThenIwouldnothavebeenabletowriteassertEqualsinmycode,IwouldhavetoprefixitwithAsserte.g.Assert.assertEquals("ReturnsHardCodedURL",
"http://192.123.0.3:67",
TestAppEnv.getUrl());
Similarly,IcouldhaveimportedtheTestAppEnvconstantsDOMAINandPORTstatically,andthenavoidedtheprefixTestAppEnvoneachusage.
IcouldeitherimportstatictheDOMAINandPORTasseparateimports,orjustimporteverythingfromTestAppEnv,andthenIwouldn’thavetoprefixcallstogetUrle.g.importstaticcom.javafortesters.domainobject.TestAppEnv.*;
Exercise:ConvertfromStaticUsagetoStaticImportExperimentwiththestaticimportinyourTestAppEnvironmentTest.
ConverttheassertEqualsimportstatictoanimportofjusttheAssertandamendthe@TestmethodsaccordinglysoyouprefixeachusageofassertEqualswithAssert.ConverttheimportofTestAppEnvtoanimportstaticoftheDOMAINandthePORT,andconvertthe@Testmethodssoyouusethemwithouttheprefix.ConverttheimportofTestAppEnvtoanimportstaticofeverythinginTestAppEnvandconvertthe@Testmethodssotheconstantshavenoprefix.
Asyoumakethechanges,reflecton:howdoestheautomationcodelook?isitmaintainable?etc.
Howtodecidewhattostaticimport
Decidingwhattoimportstaticallymightbemadeforyouthroughorganizationalcodingstandards.i.e.someteamsalwayswriteAssert.assertEquals
Iusuallymakethedecisionbasedonmystandardsofreadability,soIgenerallyimportstatictheassertmethodsIuse.ButIprobablywouldnotimportstatictheTestAppEnvconstantssinceIdon’tthinkthatseeingDOMAINorPORTinthe@TestmethodsreallygivesmeenoughinformationandI’dwonder“whichdomain?”and“whichport?”,butIrarelywonder“whichassertEquals?”.
Overuseofimportstaticcanmakeyourcodelessreadablebecausepeoplemightconfuseyourstaticallyimportedmethod,orconstant,asonewhichislocallydefined.
Theimportantpointatthemomentistoknowthatyou:
haveachoiceoverhowyoustaticallyimport.decidewhichapproachtouseonacasebycasebasis(orfollowyourorganizationalstandards).canmakecodelessreadableandmaintainableifyouimportstatictoomanymethodsandconstants,sousethispowersparingly.
SummaryAgain,I’vetriedtocondenseabunchoflearningintoasinglechapter.Ihopeyoumanagedtofollowalong.Ifnot,gobackthroughthischapterandtryagain,orcompareyourcodetothemainGithubsource(orincludedabove).
Wecoveredalotoffundamentalconcepts,andhavingactuallydonethework,bytypingitintoyourIDE,youwillhavelearnedmorethanyoumayrealize:
Wemanagedtomakeiteasiertoamendtheenvironmentlocation.Weabstractedthechangeawayfromthe@Testmethodssothatourabstractioncodecanchangewithoutrequiringanyothercodechangesinthetestbranch.Wenowknowhowtocreatestaticmethods.Wenowknowhowtocreatestaticconstantfields.Wenowknowalittlerefactoring.WeknowalittleStringconcatenation.
Weknowtokeepourabstractionsinsrc\main\javaandour@Testmethodsinsrc\test\java.Weknowthatwecanuseclassesfromotherpackages.Weknowthatwecanorganizeour@Testmethodcodedifferentlyfromourabstractioncode.
OurnextfewchaptersaregoingtoconcentrateonlearningsomeoftheJavaConceptsandlibrariesthatweneedtounderstandtohelpuswriteautomationcode.
ChapterSix-JavaClassesRevisited:Constructors,Fields,Getter&SetterMethods
ChapterSummaryInthischapteryouwilllearnhowto:
UnderstandwhataConstructorisCreateadefaultconstructorCreateaconstructorwithparametersCalloneconstructorfromanotherCreategetterandsettermethods
Thefirstfewchaptershavebeen‘throwinthedeepend’and‘tutorials’.
NowwearegoingtostepthroughJavaconceptsinmoredetail.
Wecandothatbecauseyoualreadyknowhowto:
createclasses,createmethods,annotatedmethodswith@TesttorunthemasJUnittests
ContextWhenmodelingapplicationsoneoftheDomainEntitiesIoftenendupcreatingisUser.Typicallysomeonewithanaccountonthesystemwhocanloginwitha‘username’and‘password’.Itmayhaveafewotherdetailsaswell.
FortheexamplesinthischapterweshouldimaginethatwewanttobuildaUserobjectforuseinourJUnittests.
Weneedtofollowthenormalprocesstogetusstarted:
createapackage'com.javafortesters.domainentities'createitundersrc.main.javasinceitisanabstraction,notaJUnittestclassinthepackagecreateaclassUser
1packagecom.javafortesters.domainentities;
2
3publicclassUser{
4}
NextcreateaJUnittestclasstoallowustoconstructtheclassusingTDD.
createapackage'com.javafortesters.chap006domainentities.examples'remembertocreateitundersrc.test.javainthepackagecreateaclassUserTest
1packagecom.javafortesters.chap006domainentities.examples;
2
3publicclassUserTest{
4}
Constructor
WhatisaConstructor?Aconstructorisaspecialmethodthatiscalledwhenaclassisinstantiatedwiththenewkeyword.
Writean@Testmethodwhichinstantiatesanewuser:@Test
publicvoidcanConstructANewUser(){
Useruser=newUser();
}
Hopefullynosyntaxerrors-remembertoimportorg.junit.Test.
YouwouldalsohavetoimporttheUserclass.
SharingthesamepackageIftheUserclassandtheUserTestclasswereinthesamepackagethenyouwouldbeabletousetheUserclasswithoutimportingit.
Theclasseswouldbeindifferentfolderstructures,butiftheywereinthesamepackagethenyoucoulduseanypublicclassesinthesamepackagewithoutimportingthem.
ExperimentwiththepackagestructureMovetheUserTesttoadifferentpackage,eitheraboveorinasiblingto.domainentities.CanyouusetheUserclasswithoutimportingit?
Watchout-dependingonhowyoumovedit,yourIDEmighthaveaddedtheimportforyouautomatically.
PackageScopingIfyoudeclareafieldormethodwithnomodifieri.e.missoutthepublic,thenonlyclassesinthesamepackagecanuseit,noteveryclassthatimportsit.
DefaultConstructorIfyourunthe@Testmethod-whatdoesitdo?
Well,nothingreally.
ItcreatesanewinstanceoftheclassUserandstoresitinthevariableuser.ButwedidnotcreateaconstructorontheUserclass,thereforenocodeintheUserclassisexecutedwhentheobjectisinstantiated.
Nowweshalladdsomecodethatexecuteswhentheclassisinstantiated,bywritingaconstructor,intheUserclass,thatdoesn’ttakeanyarguments,knownasano-argumentconstructor.
DefaultConstructorIfyoudon’twriteaconstructor,thenJavaautomaticallycreatesonewhichsetsallyourfieldstotheirdefaultvaluesandcallsthedefaultconstructorforanysuperclass.(wehaven’tcoveredsuperclassyet,sothiswillmakesenselater)
No-argumentConstructorIfwehaveparticulardefaultsinmindforfieldsontheclassthenagoodplacetoinitializethemisinano-argumentconstructor.
Iwanttohaveausernamefieldandapasswordfieldandhavethemdefaultto"username"and"password".
IcouldjustgointotheUserclassandcreatecodetosetthisup,butIwanttogetinthehabitofcreating@Testmethodsfirst.
Tohelpmemaintainthathabit,I’mgoingtocreatean@TestmethodwhichcreatesaUserobjectandthengetstheusernameandpasswordandassertstheyhavebeensettomydesireddefaultvalues.
Idothisbycreatingan@Testmethodwhichlookslikethis:@Test
publicvoiduserHasDefaultUsernameAndPassword(){
Useruser=newUser();
assertEquals("defaultusernameexpected",
"username",
user.getUsername());
assertEquals("defaultpasswordexpected",
"password",
user.getPassword());
}
ThegetUsernameandgetPasswordmethodsdon’texistsoIhavetocreatethem.
MyIDEcancreatethebasicmethodsforme,butIdon’thaveanyusernameorpasswordtoreturn.WhichmeansitisnowtimetoaddusernameandpasswordasfieldsinmyUserclass.
IcreateaconstructorinUserthattakesnoarguments.Andassigndefaultvaluestothefieldsusernameandpassword.Demonstratedbythefollowingcode:
privateStringusername;
privateStringpassword;
publicUser(){
username="username";
password="password";
}
Inthecodesnippet,youcanseethatIcreatedaStringvariableusernameandaStringvariablepassword.Becausethesevariablesaredeclaredinthebodyoftheclass,ratherthaninamethod,theyareknownasfieldsorfieldvariables.
IhavedeclaredthemprivatesothattheyareonlyaccessibletomethodsintheUserclassitself,andnotfromanyclassesthatimporttheUserclass.
TheconstructorIhavewrittentakesnoarguments.Youknowitisaconstructorbecauseitdoesnothaveareturntypeinthedeclarationandthenameisexactlythesameasthatoftheclass,completewithuppercaseletter.
Iassigndefaultvaluestotheusernameandpasswordinthebodyoftheconstructor.Anymethodinaclasscanamend,andaccess,thefieldvariablesdeclaredinthatclass.
Icanthenwritethemethodsthatreturntheusernameandpassword,[email protected](){
returnusername;
}
publicStringgetPassword(){
returnpassword;
}
Thecodeshouldpassnow.Writethecode,andrunthe@Testmethodtoseethisforyourself.
AfewnotesontheUserclass
ThegetUsernameandgetPasswordmethodsareknownasaccessororgettermethodsbecausetheyallowusto‘access’,or‘get’thevalueofafield.Theytakenoparameters,andreturnthevaluesofthefieldvariables.
Thecombinationofthefieldusername,andthegettermethodgetUsername,issometimesknownasa‘property’.
Becausewedeclaredthefieldvariablesasprivate,weneedtocreatemethodswhichallowotherclassestoaccessthevaluesofthosevariables.
Icouldhavemadethefieldvariablespublic,andthenIwouldnothaveneededtocreateanaccessormethod,butthenIreducetheamountofcontrolthatwehaveoverthevaluesbecauseotherclassescouldamendthevaluesofthosefieldsatanypoint.
ExperimentwithprivateandpublicfieldsTryitforyourself.Makethefieldspublicandinan@Testmethod,setusernameandpasswordtoanewvalue,andgetthevaluejustbyaccessingthefield.
e.g.Userauser=newUser();auser.username="bob";assertEquals("notdefaultusername","bob",auser.username);
AConstructorwithargumentsAtthemomentwehavenowayofchangingtheusernameandpasswordonaUser.SowewillwriteaconstructorwhichallowsustocreateaUserobjectandsettheusernameandpasswordatthesametime.
Asdemonstratedinthefollowingcode,youcanseethatIcreateaUserwithausernameof"admin"andapasswordof"pA55w0rD":@Test
publicvoidcanConstructWithUsernameAndPassword(){
Useruser=newUser("admin","pA55w0rD");
assertEquals("givenusernameexpected",
"admin",
user.getUsername());
assertEquals("givenpasswordexpected",
"pA55w0rD",
user.getPassword());
}
Tomakethis@Testmethodpass,wehavetocreateanewconstructorinUser,thistimeaconstructorwhichtakestwoparameters,theusernameandpasswordwewanttoassigntotheUser.Thisconstructorisshownbelow:publicUser(Stringusername,Stringpassword){
this.username=username;
this.password=password;
}
Notethattheconstructornowhastwoparameters:StringusernameandStringpassword.
Becausetheseparametershavethesamenameasthefields,Ihavetousethethiskeywordinthemethod,whenIwanttoaccesstheusernameandpasswordfieldonthecurrentobject.IfIdidnotaddthis.thenJavawouldnotbeabletodistinguishbetweenthefieldandtheparameter.
IcouldhaverenamedtheparametersaUsernameandaPasswordtoavoidanamingclash.ButIwanttominimizethedocumentationIhavetoproduce,andkeepingtheparameternamesself-documentinghelpslongtermmaintenance.Alsothisgivesustheopportunitytointroduceyoutothethiskeyword.
ExperimentwiththefieldandparameternamesWritetheconstructorcode,asshowninthetextwhichusesthethiskeyword.
Removethethis.fromtheconstructor,andwhathappens?
Changetheconstructorparameternamessothatthe@Testmethodpassesandyoudonotusethethiskeyword.Whenwouldyoudothis?
this
Thethiskeywordreferstothecurrentobject.
Youcanuseanymethodorfieldintheobjectwiththethiskeyword.
Thethiskeywordhelpsyoudistinguishbetweenlocalvariableswiththesamenameasfields.
Youcanalsousethethiskeywordtocallmethodsorconstructors.
ExplicitConstructorInvocationIfyoufollowedtheprevioussectionsthenyouwillnoticethatyouhaveduplicatedcodeintheUserclass,sincetheno-argumentconstructorhascodetoassignvaluestothefields,asdoestheconstructorwhichdoestakearguments.publicclassUser{
privateStringusername;
privateStringpassword;
publicUser(){
username="username";
password="password";
}
publicUser(Stringusername,Stringpassword){
this.username=username;
this.password=password;
}
Wecancalloneconstructorfromanother
Usingthethiskeywordwecancalltheargumentconstructorfromtheno-argumentconstructor,e.g:publicUser(){
this("username","password");
}
Byrefactoringtothiscode,we:
onlyhaveoneplacewheretheusernameandpasswordfieldsareassignedvalues,stillretaintheabilitytocallthedefaultconstructorandassigndefaultstothefields.
i.e.
publicUser(){
this("username","password");
}
publicUser(Stringusername,Stringpassword){
this.username=username;
this.password=password;
}
GettersandSetters
GettersYouhavealreadyseentwogetter(oraccessor)methodsintheUserclassi.e.getUsernameandgetPassword.publicStringgetUsername(){
returnusername;
}
publicStringgetPassword(){
returnpassword;
}
SettersWealsowanttheabilitytoamendorsetfieldvaluesinaclass.Wedothisthroughsettermethods.
Forourcodewewanttohavetheabilitytoamendthepasswordbutnottheusername.
Onceourusernamehasbeensetviaaconstructorinvocation,weneverwanttoallowanycallingclassestoamendtheusername,butwedowanttoallowamendingthepassword.
Toamendthepasswordwewillwriteasettermethod(setPassword),whichweuseasspecifiedinthiscode:@Test
publicvoidcanSetPasswordAfterConstructed(){
Useruser=newUser();
user.setPassword("PaZZwor6");
assertEquals("setterpasswordexpected",
"PaZZwor6",
user.getPassword());
}
AndtheactualsettermethodintheUserclasslookslikethis:publicvoidsetPassword(Stringpassword){
this.password=password;
}
AgainyoucanseetheuseofthethiskeywordtodistinguishbetweenthefieldandthelocalvariabledefinedbytheStringpasswordparameter.
Writethecode,andrunthe@Testmethodstomakesureallourassertionsstillpass.
WhySettersandGetters?Bycreatingasettermethodwegaintheabilitytocontrolthevaluesthatareassignedtothefieldse.g.
wecouldaddcodeforvalidationandmakesurewecan’tassignincorrectpasswordsifapasswordhadtobeminimumlengthwecouldwritecodetopadittothecorrectlengthifweneededto
Wecanusegettermethodstohidetheimplementation,e.g.wemight‘calculate’thereturnvalue,ratherthanalwaysreturnsomethingwhichhasbeenset.
Thereareoccasionallytimeswherewewanttoloosenupcontrolovertheobjectfieldsandmakethempublic,sopeoplecanamendthemandaccessthemwhenever,andhowevertheywant.Butwearemuchmorelikelytousesetterandgettermethodstocontrolaccessandallowustheflexibilityinthefuturetochangeimplementationdetails.
SummaryYoushouldnowknowhowto:
createano-argumentconstructorbycreatingapublicscopemethodwithnoreturntypewhichhasthesamenameastheclasscreateaconstructorthattakesparametershaveparametersnamedthesameasfields,andusetheminthesamemethodbodycallaconstructorfromanotherconstructorcreategettermethodswhichreturnvaluescreatesettermethodstoamendfieldvariablesusethethiskeywordtodistinguishbetweenobjectfieldsandmethodparameters
Andyoushouldalsounderstand:
thebasicsoffieldandmethodscopingpublic,privateandwithnoexplicitscope(package).
UserclasscodeForyourreferenceandcomparison,wecreatedthefollowingUserclass,inthischapter:packagecom.javafortesters.domainentities;
publicclassUser{
privateStringusername;
privateStringpassword;
publicUser(){
this("username","password");
}
publicUser(Stringusername,Stringpassword){
this.username=username;
this.password=password;
}
publicStringgetUsername(){
returnusername;
}
publicStringgetPassword(){
returnpassword;
}
publicvoidsetPassword(Stringpassword){
this.password=password;
}
}
ReferencesandRecommendedReading
AccessControldocs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
DefaultConstructordocs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.8.9
Constructorsdocs.oracle.com/javase/tutorial/java/javaOO/constructors.html
Java‘this’keyworddocs.oracle.com/javase/tutorial/java/javaOO/thiskey.html
ChapterSeven-BasicsofJavaRevisited
ChapterSummaryInthischapteryouwillreceiveanoverviewof:
JavaCommentsJavanamingconventionsWorkingwithpackagesScopeoffields,methodsandclassesthefinalkeywordDataTypes:boolean,integer,floatingpoint,characterandtheirwrapperclassesBigDecimal
Operators:Arithmetic,Assignment,Boolean,Conditional,TernaryandBitwiseOperatorPrecedenceStringconcatenationandstaticmethods
Thischapterwillquicklyreinforcethetopicscoveredintheprevioustutorialchapters.Youwillalsoseereferencetoconceptsyouhavenotyetcoverede.g.BigDecimal,wementionthesebecauseitmakessenseincontext,butwewillcoverthedetailslater.
Therearenospecificexercisesinthischapter,althoughyoushouldreadthroughtheexamplecodetomakesureyouunderstandit.Ialsorecommendthatyouwrite@Testmethodstoexperimentwithyourownexamplesandverifythestatementsmadeinthischapter.
Youcanusethisasareferencechapterforlaterstudy.Restassuredthatwecontinuetobuildonthisinformationinlaterchapters,sodon’tworryifyoudon’tabsorbitallonfirstreading.
CommentsCommentsarenon-executablestatementsinthecode.
Thereare3typesofcomments:
commentsthatruntotheendoftheline//commentsthatmarkoutblocksstarting/*andending*/JavaDoccommentsstartingwith/**andending*/
Whenwewantsmallcommentswecanaddthemafterstatementsandanythingafter//willbetreatedasacomment.Thesecommentsareusefulforquickexplanations.assertTrue(truthy);//commenttillendofline
Tocommentoutablockofcode,orhavealargerdescriptivetextweuseablockcommentwhichstartswith/*andendswith*/.Thesecommentscanspanlinesandstartandendinthemiddleoflines.
/*
Thiscodechecksthatthetrue
valuethattruthywassetto
istrue.Prettyobviousreally.
*/
booleantruthy=true;
assertTrue(truthy);
BlockCommentsdonotnestYoucannotnestblockcomments,i.e.ifyoutryandcommentoutablockoftextwhichalreadycontainsablockcommentthenyouwillgetasyntaxerror.
Youcancommentoutablockcommentbyputting//atthestartofeachline.
JavaDoccommentshelpwithcommunicationbecauseyoucanusetheIDEtoshowyoutheJavaDoconmethodsandclassesi.e.ifIpressctrl+q(ctrl+jonMac)ontheaddTwoNumbersmethodcallinaJavaDocCommentIwillseetheJavaDocdocumentationfromthecomment.
Thisisaveryusefulcommentingstyletouseonabstractionlayerclassesandmethods.e.g.@Test
publicvoidaJavaDocComment(){
assertTrue(addTwoNumbers(4,3)==7);
}
/**
*Addtwointegersandreturnanint.
*
*Thereisariskofoverflowsincetwobig
*integerswouldmaxoutthereturnint.
*
*@paramaisthefirstnumbertoadd
*@parambisthesecondnumbertoadd
*@returna+basanint
*/
publicintaddTwoNumbers(inta,intb){
returna+b;
}
Wewon’tcoverJavaDocindetailinthisbook,butyoucanreadthereferencestofindoutmore.
StatementAJavastatementisthesmallestchunkofexecutableJavacode.WeendaJavastatementwith;e.g.assertEquals(4,2+2);
Javastatementscanspanlines.Thisisusefultomakeyourcodemorereadableandlineupargumentsonmethodcalls.e.g.
assertEquals("2+2always=4",
4,
2+2);
PackagesJavaallowsustogroupourClassesintopackages.Eachclasshastobeuniquelynamedwithinapackage.Wecanhavemultipleclasseswiththesamename,providedtheyareallindifferentpackages.packagecom.javafortesters.chap007basicsofjavarevisited.examples;
Toaddaclasstoapackageyouwriteapackagedeclarationstatementliketheabove,veryoftenthefirstlineintheclass,andcertainlybeforethecodethatdeclarestheclass.
JavaClassesAllofourJavacodewillinvolveclassesinsomeform.Eitherusingclassesthatothershavewritten,writingabstractionlayersasclasses,orcreatingJUnittests(whichareactuallymethodsinaclassannotatedwith@Test).publicclassAnEmptyClass{
}
Thisexampleclassshowsmanyfeaturesofaclass:packagecom.javafortesters.chap007basicsofjavarevisited.examples;
publicclassClassExample{
publicstaticfinalStringCONSTANT="aconstantstring";
publicstaticStringaClassField="aclassfield";
protectedstaticStringproField="aclassfield";
publicStringpubField="apublicfield";
privateStringprivField="aprivatefield";
privateStringname;
publicClassExample(Stringname){
this.name=name;
}
publicStringgetName(){
returnthis.name;
}
publicvoidsetName(Stringname){
this.name=name;
}
}
Thefirstlineoftheclasshasthepackagedeclaration.Thisdoesn’tneedtobethefirstline,itjustneedstocomebeforetheclassdeclaration.packagecom.javafortesters.chap007basicsofjavarevisited.examples;
Here,theclassisdeclaredwiththenameClassExampleanddeclaredaspublic.publicclassClassExample{
Becausetheclassispublic,itcanbeusedbyanotherclass,solongastheyimportit,oriftheyareinthesamepackage.IfIdidn’taddthepublicthentheclasswouldhavepackagescopeandonlybeavailabletootherclassesinthesamepackage.
StaticmethodsandfieldsAclasscanexposestaticmethodsandfields,whichallowyoutousethemwithoutinstantiatinganewinstanceobjectoftheclass.
YouhaveseenthiswhenusinganyoftheassertsinJUnit,theseareallstaticmethodsontheAssertclass.
InstantiatingClassesMostclassesneedtobeinstantiatedbeforetheycanbeused.ClassExampleinstance=newClassExample("bob");
Whenweinstantiateaclass,weusethenewkeyword,andcalloneoftheclass’sconstructors.
FieldandMethodScopeThescopeofafieldormethodisdefinedbypublic,protected,privateorpackage-private(nomodifier).
publicaccessibletoanyclassthatimportstheparentclassprotectedaccessibletoanyclassinthesamepackage,oranysubclassprivateaccessibletomethodsintheclasspackage-private-whennomodifierisusedthenthefieldormethodisaccessibletotheclassandanyclassinthesamepackage(thisisthedefault)
Additionalfieldandmethodmodifiers:
static-thefieldormethodexistsattheclasslevel,nottheinstancelevel,soissharedbyallinstancesandcanbeaccessedwithoutneedingtohaveaninstantiatedclassvariable.
Fields&VariablesFieldsarevariablesthatareaccessiblebyanymethodintheclassand,dependingonthescope,possiblytootherclasses.
Fieldtypicallyreferstovariablesdeclaredattheclasslevelandlocalvariablereferstovariablescreatedinamethod.
Additionalfieldmodifiersare:
final-oncethefieldhasavalueitcannotbechanged
Examplesofcombinationsandnuancesofscopeandmodifiersareexplainedbelow.
Naming
Afieldorvariablenamemustbeginwithaletter,whichisanyUnicodecharacterthatrepresentsaletter:toplayitsafe,andkeepcodereadable,wenormallystickto‘A’to‘Z’,‘a’to‘z’,althoughsomepeoplealsousethesymbols‘_’and‘$’(andeven£).
Afterthisfirstletter,thevariablenamecancontainanyoftheletters,ordigits.
CaseissignificantsoaMountisnotthesameasAmount.
Namestendtousecamelcaseandstartwithalowercaseletter.Constantstendtobealluppercase,with‘_’todelimitwords.
Avariablenamecanbeverylong,andyoucanuseawiderangeofcharactersinthename,butdotryandkeepthenamesreadable,andcapableofbeingreadaloud.@Test
publicvoidvariableNaming(){
String$aString="bob";
float£owed=10F;
intaMount=4;
longAmount=5;
StringA0123456789bCd$f="ugh";
assertEquals(4,aMount);
assertEquals(5,Amount);
assertEquals(10.0F,£owed,0);
assertEquals("bob",$aString);
assertEquals("ugh",A0123456789bCd$f);
}
PublicStaticFinal
publicstaticfinalfieldsareoftenknownasconstants,becauseonceassignedavalue,thevaluecannotbechanged.Thismakesthemusefulforexposingconstantvaluestootherclasses.publicstaticfinalStringCONSTANT="aconstantstring";
Typicallyyouwillseethevalueassignmentinthedeclarationasaconstant,asshownintheexampleabove,butitcouldalsobesetfromamethodcall,whichallowsyoutoreadconstantsfromfilesorpropertyvalues.
FinalNotethatfinaldoesnothavetohavepublicstaticscope.Anyofthescopingkeywordscanbeusedwithfinale.g.privatefinal
finalsimplymeansthatonceassignedavalue,itcan’tbechanged.ButitissooftenusedaspublicstaticfinalthatIincludeditinthissection.
PublicStaticpublicstaticStringaClassField="aclassfield";
ApublicstaticfieldisavailabletoanyclasswhichimportstheClassExampleclass.Andbecauseitisstatic,thefieldisavailablewithouthavingtoinstantiatetheclassintoaninstancevariable.staticfieldsareoftenknownasclassfieldse.g.
assertEquals(ClassExample.aClassField,
"aclassfield");
Youcanaccessclassfieldsfrominstanceobjects,buttheIDEmaywarnyou,orthefieldmaynotshowupincodecompletion.instance.aClassField="changed";
Unlikeconstantsthesefieldscanhavetheirvalueschangedbyotherclasses.Thiscanmakeyourcodeerrorprone-sobecarefulifyoudothis.
PublicpublicStringpubField="apublicfield";
Apublicfieldisaccessibletoallclasseswhichinstantiateanewinstancevariableoftheclass.assertEquals(instance.pubField,"apublicfield");
instance.pubField="amendedpublicfield";
assertEquals(instance.pubField,"amendedpublicfield");
Becausethesefieldscanbechangedbyotherclasses,youshouldconsiderifyouneedtomakethempublic,orifitshouldbeaprivatefield,andtheclassshouldoffersetterandgettermethodsinstead.
Protected
protectedmeansthatthefieldcanbeusedbyanyclassinthesamepackage,oranyclasswhichextendsthisclass.(Youwilllearnaboutextendslaterinthisbook)
Package-Private(default)
Whennomodifierisaddedtothefielddefinitionthenitisonlyaccessiblebymethodsintheclassoranyclassesinthesamepackage.
ImportingClassesAclasscanuseanyclassesinthesamepackage.Andanyclassdeclaredaspublicinotherpackages,whenweimportthatclass.
Wecanimportspecificclassesbyspecifyingtheclassnameinthetheimportstatement.importcom.javafortesters.domainentities.User;
Wecanalsousewildcardtoimportalltheclassesfromapackagee.g.importcom.javafortesters.chap001basicsofjava.examples.classes.*;
Notethatyoudon’thavetoimport.Youcanuseclasseswithoutimportingthem,byprefixingtheclassnamewiththepackagepath.Butyourcodequicklybecomesverboseandhardertomaintain.e.g.@org.junit.Test
publicvoidnonImportTest(){
org.junit.Assert.assertEquals(3,2+1);
}
Thiscanbehelpfulifyouaretryingtousetwoclasseswiththesamenameinyourcode.Iftheyareindifferentpackagesthenprefixtheclass’snamewiththefullpackagewhen
youdeclareandinitialiseit.
StaticImportsYoucanimportspecificmethodsandfields,aswellasclasses.YouhavealreadyseenthiswiththeJUnitimports.e.g.importorg.junit.Assert;
importstaticorg.junit.Assert.assertEquals;
Aboveyoucanseetwoimports.AstaticimportfortheassertEqualsmethodandanimportfortheAssertclass.
WhenIusethestaticimportofassertEquals,IcanusetheassertEqualsmethoddirectlyinmycodee.g.assertEquals(6,3+3);
WhenIdonotusethestaticimport,Ihavetoaccessthestaticmethodfromtheclassitselfe.g.Assert.assertEquals(5,3+2);
DataTypesEveryvariableinJavamusthaveatypedeclared,eitherasaprimitive,oranobjectclass.
BooleanTypeAbooleanhastwoconstantstrueandfalse.
ThereisalsoanassociatedBooleanobject.@Test
publicvoidBooleanType(){
booleantruthy=true;
booleanfalsey=false;
assertTrue(truthy);
assertFalse(falsey);
truthy=Boolean.TRUE;
falsey=Boolean.FALSE;
assertTrue(truthy);
assertFalse(falsey);
}
IntegerTypes
byterange:-128to127shortrange:-32768to32767intrange:-2147483648to2147483647longrange:-9223372036854775808to9223372036854775807
EachprimitivehasanassociatedClasse.g.Byte,Short,Integer,Long.Thesecanbeusedforconversionsandhaveothersupportmethods.TheyalsohavetheMIN_VALUEandMAX_VALUEconstantsforeachprimitive.
VariousJavasyntaxexistsforrepresentingliteralsasspecificprimitives:
representanintegerliteralasalongbyaddingthesuffixLrepresentahexvaluewiththeprefix0x(zerox)representanoctalvaluewiththeprefix0(zero)representabinaryvaluewiththeprefix0b(zerob)(Java1.7)makenumbersreadablebyadding_e.g.9_000_000(underscore)(Java1.7)
Examplesoftheabove,canbeseenbelow:@Test
publicvoidIntegerTypes(){
byteaByteHas1Byte;
shortaShortHas2Bytes;
intanIntHas4Bytes;
longaLongHas8Bytes;
System.out.println(
"*`byte`range:"+
Byte.MIN_VALUE+"to"+
Byte.MAX_VALUE);
System.out.println("*`short`range:"+
Short.MIN_VALUE+"to"+
Short.MAX_VALUE);
System.out.println("*`int`range:"+
Integer.MIN_VALUE+"to"+
Integer.MAX_VALUE);
System.out.println("*`long`range:"+
Long.MIN_VALUE+"to"+
Long.MAX_VALUE);
aLongHas8Bytes=0L;//addsuffixLforlong
assertEquals(0,aLongHas8Bytes);
aByteHas1Byte=0xA;//addprefix0xforHex
assertEquals(10,aByteHas1Byte);
anIntHas4Bytes=010;//add'zero'prefixforOctal
assertEquals(8,anIntHas4Bytes);
aByteHas1Byte=0b0010;//Java1.7added0b'zerob'forbinary
assertEquals(aByteHas1Byte,2);
//Java1.7allowsunderscoresforreadability
aLongHas8Bytes=9_000_000_000L;//9000million
assertEquals(9000000000L,aLongHas8Bytes);
}
Floating-pointTypes
Floatingpointtypeshavetwodifferentprecisions,whichcontrolsthesizeofvaluetheycanstore:
float:singleprecision32bitnumberdouble:doubleprecision64bitnumber
Ranges:
floatrange:1.4E-45to3.4028235E38doublerange:4.9E-324to1.7976931348623157E308
Suffixes:
representafloatwiththesuffixFrepresentadoublewiththesuffixD,orifyouuseadecimalpointe.g.20.0thenthennumberwithdefaulttoadouble
Theofficialdocumentsrecommendtheusethejava.math.BigDecimalclassifyouwantprecisevaluese.g.currency.BigDecimalhelpsavoidroundingerrors.
TheseprimitivetypesalsohaveanassociatedClasse.g.FloatandDouble@Test
publicvoidFloatingPointType(){
floatsinglePrecision32bit;
doubledoublePrecision64bit;
System.out.println("*`float`range:"+
Float.MIN_VALUE+"to"+
Float.MAX_VALUE);
System.out.println("*`double`range:"+
Double.MIN_VALUE+"to"+
Double.MAX_VALUE);
singlePrecision32bit=10.0F;//suffixFtogetafloat
assertEquals(10F,singlePrecision32bit,0);
doublePrecision64bit=20.0;//defaulttodouble
assertEquals(20D,doublePrecision64bit,0);
}
CharacterTypeThechardatatypeisusedtorepresentanindividualcharactere.g.'a',itisa16bitUnicodecharacter.
AcharisnotaString.
Youcanrepresentaunicodecharacteras\u0026i.e.\ufollowedbythe4characterhexvalueoftheUnicodecharacter.\u0026is&
Javaalsohassomespecialcharactersrepresentedbyescapesequencese.g.
\t-atabcharacter
\b-backspace\n-anewline\r-acarriagereturn\'-asinglequote\"-adoublequote\\-abackslash
AllofthesespecialcharactersarealsoavailableforuseinString.
JavaalsohasanassociatedCharacterclasswithstaticmethodstohelpwhenworkingwithcharvariables.@Test
publicvoidCharacterType(){
charaChar='\u0026';
assertEquals(aChar,'&');
}
Operators
TraditionalJavahasthetraditionalarithmeticoperatorsthatyouwouldexpect:
+foraddition-forsubtraction*formultiplication/fordivision
AlloftheabovecanbeusedforIntegerandFloatingpointnumbers.AlthoughyoumaynotgettheresultyouexpectwithFloatingpointnumbers(duetorounding)-whichiswhyBigDecimalisoftenrecommended.
+canalsobeusedforStringconcatenation%forintegerremaindercalculations(i.e.modulus)e.g.9%2returns1
@Test
publicvoidtraditionalOperatorsExplored(){
assertEquals(4,2+2);
assertEquals(5L,10L-5L);
assertEquals(25.0F,12.5F*2F,0);
assertEquals(30.2D,120.8D/4D,0);
assertEquals("abcd","ab"+"cd");
assertEquals(1,9%2);
}
AssignmentOperatorsarealsousedforassignment,asyouhaveseenwhenyouinstantiateavariable.
=toassignthevaluetothevariable
Thetraditionaloperatorscanalsobeusedduringassignment:
+=toincrementthevariablebyvaluee.g.+=2wouldaddtwo-=todecrementthevariablebyvaluee.g.-=2wouldsubtracttwo*=tomultiplythevariablebyvaluee.g.*=2wouldmultiplybytwo/=todividethevariablebyvaluee.g./=2woulddividebytwo%=tocalculateandassignthemodulusbyvaluee.g.%=3wouldassignthevariablemodulusthevalue
@Test
publicvoidassignmentOperatorsExplored(){
Stringab="ab";
assertEquals("ab",ab);
intnum=10;
assertEquals(10,num);
num+=2;
assertEquals("+=incrementsby",12,num);
num-=4;
assertEquals("-=decrementsby",8,num);
num*=2;
assertEquals("*=multipliesby",16,num);
num/=4;
assertEquals("*=multipliesby",4,num);
num%=3;
assertEquals("%=modulusof",1,num);
}
IncrementandDecrementYoucanincrementanddecrementavariableusing++and--e.g.++numwouldreturnnumincrementedby1
Youcanput++and--beforeorafterthevariable.
Putting++or--beforethevariablemeansthatyouwanttoamenditafterusingit.(prefix)Putting++or--afterthevariablemeansthatyouwanttouseitandthenincrementit.(postfix)
e.g.@Test
publicvoidincrementDecrementOperatorsExplored(){
intnum=10;
assertEquals(11,++num);
assertEquals(10,--num);
assertEquals(10,num++);
assertEquals(11,num);
assertEquals(11,num--);
assertEquals(10,num);
}
BooleanOperatorsJavahasarangeofoperatorswhich,comparetwooperandsto,returntrueorfalse.
==testforequality!=testforinequality>greaterthan<lessthan<=lessthanorequalto>=greaterthanorequalto
Youcanalsonegateabooleanwith!(knownaslogicalcomplement);@Test
publicvoidbooleanOperatorsExplored(){
assertTrue(4==4);
assertTrue(4!=5);
assertTrue(3<4);
assertTrue(5>4);
assertTrue(6>=6);
assertTrue(7>=6);
assertTrue(8<=8);
assertTrue(8<=9);
assertTrue(!false);
booleantruthy=true;
assertFalse(!truthy);
}
ConditionalOperatorsYoucancreatecomplexbooleanstatementsbyusing&&and||
&&alogicaland||alogicalor
e.g.@Test
publicvoidconditionalOperatorsExplored(){
assertTrue(true&&true);
assertTrue(true||false);
assertTrue(false||true);
assertFalse(false||false);
assertFalse(false&&true);
}
Notethattheselogicalconditionaloperatorsshortcut,sotheyonlyevaluatethesecondoperandifrequired.e.g.true||falsewouldonlyneedtocheckthefirsttruevalue,butfalse||truewouldhavetoevaluateboth.
TernaryOperatorJavasupportsaternaryoperatorwhichperformsacheckonaconditionand:
iftrue,returnsthevalueofthefirstoperand,andiffalse,returnsthevalueofthesecondoperand.
condition?operand1:operand2;
Notethatyouonlyneedthe;ontheend,iftheternaryoperatorisontherightofastatement,ifitisevaluatedwithinastatementthenyoudon’taddthe;
e.g.@Test
publicvoidternaryOperatorsExplored(){
intx;
x=4>3?2:1;
assertEquals(2,x);
assertTrue(5>=4?true:false);
}
BitwiseOperatorsYoucanperformbinarybasedbitwiseoperationsonIntegerdatatypes.
&and|or^xor~bitwisetwo’scomplement(invertthebits)
@Test
publicvoidbitwiseOperatorsExplored(){
assertEquals(0b0001,
0b1001&0b0101);
assertEquals(0b1101,
0b1001|0b0101);
assertEquals(0b1100,
0b1001^0b0101);
intx=0b0001;
assertEquals("11111111111111111111111111111110",
Integer.toBinaryString(~x));
}
Thebitwiseoperatorscanalsobeusedduringanassignment.@Test
publicvoidbitwiseAssignmentOperatorsExplored(){
bytex=0b0001;
x&=0b1011;
assertEquals(0b0001,x);
x|=0b1001;
assertEquals(0b1001,x);
x^=0b1110;
assertEquals(0b0111,x);
}
BitShiftOperatorsYoucanperformbinaryarithmeticandshiftoperationsonIntegerdatatypes.
<<shifttothelefte.g.<<3shift3totheleft>>signedshifttotheright>>>unsignedrightshift(shiftazerointoleftmostposition)
Theshiftoperatorscanalsobeusedonassignment.@Test
publicvoidbitwiseShiftOperatorsExplored(){
intx=56;
assertEquals(x*2,x<<1);
assertEquals(x*4,x<<2);
assertEquals(x*8,x<<3);
x<<=3;
assertEquals(56*8,x);
x=Integer.MAX_VALUE;
assertEquals(Integer.MAX_VALUE/2,x>>1);
assertEquals(Integer.MAX_VALUE/4,x>>2);
assertEquals(Integer.MAX_VALUE/8,x>>3);
x=Integer.MIN_VALUE;//-ve
assertEquals((Integer.MAX_VALUE/2)+1,x>>>1);
}
OperatorprecedenceTheoperatorprecedenceislistedontheJavadocumentationpage:
docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
Whileitisworthunderstandingtheprecedenceorder,itisgenerallyeasiertoreadtheintentbehindacomplexstatementiftheorderofprecedenceismadeclearbyusingparenthesis,()sincenestedoperationsareexecutedfirst.
e.g.comparetheasserts:@Test
publicvoidoperatorPrecedence(){
assertEquals(8,4+2*6/3);
assertEquals(12,(((4+2)*6)/3));
}
Thereforetryanduseparenthesis,(),tocontroltheorderofprecedence,asitwillmakethecodeeasiertoreadandmaintain.
Thebasicrulesforprecedenceare:
Theoperatorswithhighestprecedenceareevaluatedfirst.OperatorswithequalprecedenceareevaluatedinlefttorightorderAssignmentoperatorsareevaluatedrighttoleft
Inthetablebelow,operatorsarelistedinprecedenceorder,andwheremorethanoneoperatorisonthesamerow,theyareofequalprecedence.
Operatorx++x--++x--x+x-x~!*/%+-<<>>>>><><=>===!=&
^
|
&&
||
?:
=+=-=*=/=%=&=^=|=<<=>>=>>>=
StringsAStringisaclassinjava.langsoyoudon’tneedtoimportittouseit.
Stringsareimmutablesotheycan’tchange.Allcommandsthatlookliketheychangethevaluesofstrings,actuallyreturnanewStringwithalltheamendments.
StringConcatenationStringscanbeconcatenatedusingthe+operator.@Test
publicvoidstringsConcatenated(){
assertEquals("123456","12"+"34"+"56");
}
StringmethodsTheStringclassprovidesstaticmethodsthatcanbeusedwithoutinstantiatingaStringobjectvariable:
lengththenumberofcharactersinthestringcharAtreturnsthecharacterataspecificindexcontainsreturnstrueifasubstringiscontainedetc.
@Test
publicvoidsomeStringMethods(){
StringaString="abcdef";
assertEquals(6,aString.length());
assertTrue(aString.compareToIgnoreCase("ABCDEF")==0);
assertTrue(aString.contains("bcde"));
assertTrue(aString.startsWith("abc"));
//stringindexingstartsat0
assertEquals('c',aString.charAt(2));
assertEquals("ef",aString.substring(4));
}
Formethodswhichuseindexese.g.substringorcharAttheindexstartsat0sothefirstcharacterisatindex0
Stringswillbeexploredinmoredetaillaterinthebook.
SummaryThiswasintendedtobeafairlyheavychapter,butIintersperseditwithalotofcodeexamples.
Makesureyouworkthroughtheexamplesandunderstandthem.
Recreatetheminyourowncodeandexperimentwiththem,ifyouwanttodeepenyourknowledge.
Don’tworryifyoudidn’tunderstanditall.Wewillcoversomeofthetopicsinthischapterinmoredetaillater,sincethisisthefirsttimeyouhaveseensomeofthetopicshere.
ReferencesandRecommendedReading
JavaDocCommentsDocumentationoracle.com/technetwork/java/javase/documentation/index-137868.html
WikipediaJavaDocen.wikipedia.org/wiki/Javadoc
MethodScope:public,private,protected,packagedocs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
JavaPrimitiveDataTypesdocs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
Unicodecharactersen.wikipedia.org/wiki/List_of_Unicode_characters
Javacharactersdocs.oracle.com/javase/tutorial/java/data/characters.html
Two’sComplementen.wikipedia.org/wiki/Two%27s_complement
OperatorsandPrecedencedocs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html
ChapterEight-SelectionsandDecisions
ChapterSummaryInthischapteryouwilllearn,howtouseselectionsandconditionsinyourcode:
Howtousetheternaryoperatorif/elsestatementsTheswitchstatement
WhenIwaslearningtoprogram,alongtimeago.Iwastaughtthatprogrammingwasmadeupof:
SequenceSelectionIteration
Sequence,iswhatwe’vebeendoing:onestatement,followinganotherstatement.
Selection,ismakingdecisions,andchoosingtodoonething,oranother,dependingonaparticularcondition.
Iteration,wherewerepeatactionsuntilwehavedonewhatweneeded.
ThischapterisgoingtolookatSelection.OrConditionalStatements
TernaryOperatorsYouhavealreadyseentheTernaryoperator.x=4>3?2:1;
xissetto2,if4isgreaterthan3,otherwisexissetto1
Intheternaryoperator,theconditionisevaluatedand:
iftheconditionistrue,thevalueofthefirstoperandisreturned,iftheconditionisfalsethevalueofthesecondoperandisreturned.
e.g.@Test
publicvoidmoreTernary(){
Stringurl="www.eviltester.com";
url=url.startsWith("http")?url:addHttp(url);
assertTrue(url.startsWith("http://"));
assertEquals("http://www.eviltester.com",url);
}
privateStringaddHttp(Stringurl){
return"http://"+url;
}
Peopleoftenusethisforsimple,in-line,decisionmakingorquickchecks.Ipersonallyfindithardertoread,sowhenIcodeIgenerallywriteifstatements.
Exercise:CatorCats?TernaryOperatorWritean@Testmethodthatusesaternaryoperatortoreturn"cat"ifanumberOfCatsequals1.Andreturn"cats"ifthenumberOfCatsisnot1
Rewriteyourcodesothattheternaryoperatorisusedinamethodwhichreturns"cat"or"cats"dependingonthenumberOfCatsparameteritiscalledwith.e.g.
assertEquals("2==cats","cats",catOrCats(2));
ifstatementTheifstatementtakestheforms:
if(condition)statement;
or
if(condition){statement1;statement2;}
Whenonlyonestatementisusedintheifthenyoudon’tneedtoaddthe{}blockdelimiters.Whenmultiplestatementsareusedthenyouneedtoaddthestatementsinthecodeblockdelimitedwith{}.
Thestatementsareonlyexecutedwhentheconditionevaluatestotrue
CodingStyle
Itendtoadd{}regardlessofthenumberofstatements.
Ithinkitmakesthecodeeasiertoread.AndI’mlesslikelytoforgettoaddtheblockdelimitersinlater,whenIaddmorestatementstotheifclause.
Butthesearepersonalstyleissuesandarelikelytobedictatedbyyourpersonalstyle,orthestyleofcodingenforcedinyourworkplace.
Example:@Test
publicvoidifAddHttp(){
Stringurl="www.seleniumsimplified.com";
if(!url.startsWith("http")){
url=addHttp(url);
}
assertTrue(url.startsWith("http://"));
assertEquals("http://www.seleniumsimplified.com",url);
}
Exercise:AssertTrueiftrueGivenavariable:booleantruthy=true;
Writean@Testmethodthatusesanifstatementwithoutasetofbraces{}toassertTrueontruthy,iftruthyistrue.
Writean@Testmethodthatusesanifstatementthatwhentruthyistrue,assertsTrueontruthy,andassertsFalseon!truthy
elsestatementSincethestatementblockaftertheifonlyexecuteswhentheconditionevaluatestotrue,wealsoneedtheabilitytoexecutecodeiftheconditionevaluatestofalse.
Andthisiswheretheelsekeywordcomesin.
if(condition)statement;else
statement;
or
if(condition){statement1;statement2;}else{
statement3;statement4;}
Againyoucanseethatwhenthereisnodelimitedblockthentheelseexecutesasinglestatement,butwhentheelsehasadelimitedblockthenallthestatementsinthatblockwillexecute.
Example:@Test
publicvoidifElseAddHttp(){
Stringurl="www.seleniumsimplified.com";
if(url.startsWith("http")){
//donothingtheurlisfine
}else{
url=addHttp(url);
}
assertTrue(url.startsWith("http://"));
assertEquals("http://www.seleniumsimplified.com",url);
}
CompoundStatement
Asetofstatementsinablockisoftencalleda‘compoundstatement’.
Andasinglestatementreferredtoasa‘simple’statement.
Exercise:AssertTrueelseAssertFalseGivenavariable:booleantruthy=true;
Writean@Testmethodthatusesanifstatementwithoutasetofbraces{}toassertTrueontruthy,iftruthyistrue,otherwiseitusesassertFalseontruthy.
Writean@Testmethodthatusesanifstatementthatiftruthyistrue,assertsTrueontruthy,andassertsFalseon!truthy,otherwiseitusesassertFalseontruthy
Makesureyourunthemethodswithtruthy=false,soyouseetheeffectwithbothvalues.
NestedifelseBecauseifandelsearestatementstheycanbenestedintheifandelsestatementblocklikeanyotherstatement.
e.g.@Test
publicvoidifElseNestedAddHttp(){
Stringurl="seleniumsimplified.com";
if(url.startsWith("http")){
//donothingtheurlisfine
}else{
if(!url.startsWith("www")){
url="www."+url;
}
url=addHttp(url);
}
assertTrue(url.startsWith("http://"));
assertEquals("http://www.seleniumsimplified.com",url);
}
Codeformattingbecomesveryimportantwhenusingnestedifandelse:
indentyourcodelineupstatementslineupbraces{}
AlsonotethatthecodingstyleIadopthastheopeningbrace{attheendoftheiforelsestatementonthesameline,otherpeopleprefertoputtheopeningbraceundertheiforelsebutinlinewithit.
e.g.if(url.startsWith("http"))
{
//donothingtheurlisfine
}else
{
if(!url.startsWith("www"))
{
url="www."+url;
}
url=addHttp(url);
}
Ipersonallythinkthattheabovestyletakesuptoomuchspace,andthattheopeningbrace{addsnoinformation,buttheclosingbrace}doesaddinformationaboutscopewhenIreadthecode.
Experimentanddecideonastylethatsuitsyou.Lookatthecodeinuseinyourorganizationandadopttheinhousestyle.
Exercise:NestedIfElseHorrorWritethefollowingpseudocodeasJavainan@Testmethod:
Givenavariabletruthywhichissettotrueandavariablefalseywhichissettofalse:
IftruthythenIf!falseythen
Iftruthyand!falseythenIffalseyortruthythen….asserttruthyistrue,and….assertfalseyisfalse
Elseasserttruthyistrueassertfalseyistrue
ElseIf!truthythen
iffalseythenassertfalseyistrueasserttruthyisfalse
elseassertfalseyisfalseasserttruthyisfalse
Tryitwithdifferentcombinationsofvaluesontruthyandfalseytomakesureyouhavecoveredallpaths.
switchstatementWhenyourcodehasalotofifelsestatementsthenitmightbeappropriatetouseaswitchstatementinstead.
Theswitchstatementallowsyoutohaveanumberofcasesforasingleconditioncheck.@Test
publicvoidswitchExample(){
assertEquals("M",likelyGenderIs("sir"));
assertEquals("M",likelyGenderIs("mr"));
assertEquals("M",likelyGenderIs("master"));
assertEquals("F",likelyGenderIs("miss"));
assertEquals("F",likelyGenderIs("mrs"));
assertEquals("F",likelyGenderIs("ms"));
assertEquals("F",likelyGenderIs("lady"));
assertEquals("F",likelyGenderIs("madam"));
}
publicStringlikelyGenderIs(Stringtitle){
StringlikelyGender;
switch(title.toLowerCase()){
case"sir":
likelyGender="M";
break;
case"mr":
likelyGender="M";
break;
case"master":
likelyGender="M";
break;
default:
likelyGender="F";
break;
}
returnlikelyGender;
}
Theswitchstatementtakesanexpressiontocheck.Theswitchblockhasaseriesofcasestatements.Thebreakstatementisimportanttoendeachcase.Thelastcaseshouldbeadefaultwhichisexecutedifnoothercasematches.defaultdoesnotrequireabreak,butIusuallyaddone
Note:youneedtouseJava1.7oraboveifyouwanttohavestringliteralsinyourcasestatements.
BeCareful.Ifyouforgetthebreakthenthecasewillfallthroughtothenextone.e.g.
Icouldhavewrittentheswitchlikethis:switch(title.toLowerCase()){
case"sir":
case"mr":
case"master":
likelyGender="M";
break;
default:
likelyGender="F";
break;
}
Whenwrittendeliberately,thefallthroughcanmakecodeeasytoread.Bewarehoweverthatitisasimplemistaketomakeandforgetthebreakstatementanditcaneasilyintroducebugsintoyourcode.
Exercise:SwitchonShortCodeCreateamethodwhichusesaswitchstatementtoreturnaStringdependingontheshortCodepassedinasaparametertothemethod:
given“UK”return“UnitedKingdom”given“US”return“UnitedStates”given“USA”return“UnitedStates”given“FR”return“France”given“SE”return“Sweden”givenanyothervalue,return“RestOfWorld”
Forbonuspoints,maketheshortcodecaseinsensitivei.e.“uK”,“UK”,“Uk”,“uk”shouldallreturn“UnitedKingdom”
Exercise:SwitchonintCreateamethodwhichusesaswitchstatementtoreturnaStringrepresentingtheintpassedinasaparametertothemethod:
given1return"One"given2return"Two"given3return"Three"given4return"Four"givenaninteger>4,return"Toobig"givenaninteger<1,return"Toosmall"
Asanexperiment,alsowritethemethodsuchthateverycaseintheswitchisimplementedasareturnsonovariablesorbreakstatementsareused.
SummaryYouhaveseenthatyoucanwritecodewithoutallthe{}andbreakstatements.ButIfindthataddingthemallthetime,makesmycodemorereadableandmaintainable.
Itendnottouseternaryoperatorsverymuch,butsomepeopleusethemallthetime.Soitisimportanttobeabletoreadthem.
Eventhoughthiswasashortchapter.Youdoneedtomasterconditionalflowsinyourcodeandmakedecisionsaboutwhichconditionaloperatoryouuse.
ReferencesandRecommendedReading
if-then-elseJavatutorialdocs.oracle.com/javase/tutorial/java/nutsandbolts/if.html
switchJavatutorialdocs.oracle.com/javase/tutorial/java/nutsandbolts/switch.html
ChapterNine-ArraysandForLoopIteration
ChapterSummaryInthischapteryouwilllearn,asimplewayofcollectingthings,accessingthem,andloopingoverthemusing:
Arrays-afixedsizecollectionof‘things’Arrayindexing-accessindividualitemsinanarrayForEachLoop-iterateovereachindividualiteminthearrayForLoop-iteratethroughaloopusingindexesArraysofArrays-ArrayscancontainotherarraysRaggedArrays-Anarrayofarrayswithdifferentsizesjava.utils.Arrays-AutilityclassforworkingwithArrayse.g.fill,sort,copy
Inpreviouschaptersyouhaveseenhowtocreateindividualvariablestostoreobjectsandstrings.
IfyouwantedtocreateacollectionofDomainObjectsatthemoment,thenyouwouldhavetocreateanindividualvariableforeachone:e.g.user1,user2,user3,etc.
Ideally,wewantsomesortofobjectthatcollectsallthesetogetherforusandallowsustoaccesseachitemindividually.Wealsowanttoloopthroughthemtoprocesseachindifferentways.
Arrays,provideuswithasimplewayofdoingexactlythis.
ArraysArraysarethefirstcollectiondatatypewearegoingtolearn.
Anarrayrepresentsacollectionofitems,allofthesametype.
Arraysarefixedsize.Infuturechapterswewilllearnaboutcollectionsthatcanadjusttheirsizedynamicallyasweaddmoreitems.But,becausearraysareafixedsize,itmakesthemsimpletounderstand.
Asaquickexample:@Test
publicvoidsimpleArrayExample(){
String[]numbers0123={"zero","one","two","three"};
for(StringnumberText:numbers0123){
System.out.println(numberText);
}
assertEquals("zero",numbers0123[0]);
assertEquals("three",numbers0123[3]);
}
Theabovecode:
createsanarraycallednumbers0123whichwillholdStringobjectscreatesthearraywithfourstrings"zero","one","two",and"three"iteratesoverthearrayprintingouteachstringinthearraysotheconsolewoulddisplay
zero
one
two
three
assertsthatthefirstvalueinthearrayequals"zero"assertsthatthelastvalueinthearrayequals"three"
Therestofthischapterwillexplainarraysinmoredetailandyouwillwriteyourowncodeusingarrays.
CreateanArrayThereareanumberofwaystocreateanewarray:
DeclareandcreateanarrayoffixedsizeDeclareandcreatearraywithactualvaluesDeclareanemptyarrayDeclareanarrayforlaterinitialization
DeclareandCreateanArrayofFixedSizeYoucandeclareanarrayofafixedsize:int[]integers=newint[10];
int[]moreInts=newint[10];
intevenMore[]=newint[10];
Youcanseethetypedeclaration(int),whichmeansthatthisarraycanonlystoreintvalues.Youcanalsoseethatthe[]canbebeforeorafterthevariablename.
Iprefertoputthe[]afterthetypedeclaration,asinthefirstintexampleabove.Ithinkitisfastertoreadthedeclarationandseethatitisanarray.
Icreatethearraywiththecode:
newint[10]
Thiscreatesanintarrayofsize10,soitcanstore10intvalues.
Icancreateanddeclareanarrayofdifferenttypes,sothefollowingcodeshowsthecreationofaStringarrayofsize10,tohold10Stringvalues.Stringstrings[]=newString[10];
DeclareandCreateanArraywithActualValues
Youcanalsodeclareanarraywiththevaluesinthedeclaration:int[]ints1to10={1,2,3,4,5,6,7,8,9,10};
DeclareanEmptyArray
Youcandeclareanarrayofzerolength,usingthesyntaxpresentedbelow:int[]zeroLength={};
int[]moreZeroLength=newint[0];
DeclareanArrayforLaterInitialization
Ifyouwantto,youcandeclareanarrayandinitializeitlater.Forexample,thiscodedeclaresanarraybutdoesnotinitializeit.int[]uninitializedArray;
Iprefertoinitializeitatdeclaration,orinitializeitasanemptyarray.
Ifyouwanttoallocateanewarraytoanexistingarrayvariablethenyoucanusethesyntaxyousawinthedeclarationi.e.uninitializedArray=newint[10];
Oryoucanalsousethefollowingsyntax,whichcreatesananonymousarrayandallocatesittoanexistingvariable:uninitializedArray=newint[]{100,200,300};
AccessitemsinanarrayYoucanaccesstheitemsinanarraybyusingthe[i]notation,whereiistheindexyouwanttoaccess.
Arraysareindexedstartingat0sothefirstiteminanarrayisat[0].String[]workdays={"Monday","Tuesday","Wednesday",
"Thursday","Friday"};
assertEquals("Monday",workdays[0]);
assertEquals("Friday",workdays[4]);
Exercise:CreateanArrayofUsersUsingtheUserdomainobjectthatyoucreatedpreviously.
Createanarraycontaining3Userobjects.
IteratethroughanarrayWecaniteratethroughanarraywithaforeachloopandaforloop.
Theiterationexamplesbelow,allusethefollowingworkdaysarray:String[]workdays={"Monday","Tuesday","Wednesday",
"Thursday","Friday"};
ForEachloop
Aforeachloop,iteratesthrougheachiteminthearray.for(variable:collection){
//dosomething
}
Thevariableisautomaticallyassignedthenextitemfromthecollection,anditeratesovereachiteminthearrayautomatically.
e.g.Stringdays="";
for(Stringworkday:workdays){
days=days+"|"+workday;
}
assertEquals("|Monday|Tuesday|Wednesday|Thursday|Friday",days);
for-createaforloopwithavariabledeclaration:arrayinthiscasethevariableisaStringcalledworkdaythecollectionisthearrayworkdays
thecodeiteratesthroughthearray,andeachiteminthearrayisassignedtothevariableworkdaysothefirsttimethroughtheloopthevariableworkdayisassignedthe[0]indexedvaluefromthearrayworkdayswhichis"Monday"thesecondtimethroughtheloopthevariableworkdayisassignedthe[1]indexedvaluefromthearrayworkdayswhichis"Tuesday",etc.theloopiteratesovereveryiteminthearraytheloopstopswhentherearenomoreitemsinthearraytoiterateover
Thisloopingconstructmeansthatwecaniterateovereveryiteminthearrayandnotmissany.Therebyavoidingtheoffbyoneerrorsthattraditionalboundaryvalueanalysisissofondoftryingtodetect.
Exercise:IterateovertheArrayofUsersUsingyourarrayofthreeUserobjectscreatedinthepreviousexercise.
IterateoverthearrayandSystem.out.printlnthenameofeachUser.
Forloop
Theforloopgivesusmorecontroloverthelooping.Wesetuptheinitialvariablewewanttouseforlooping,thenhaveaconditionwhichdecidesifweendtheforloop,thenwehaveastatementwhichsetsupthenextiterationoftheloop.for(variable;loop_condition;iterator){
//dosomething
}
e.g.thetraditionaluseofaforloopStringdays="";
for(inti=0;i<5;i++){
days=days+"|"+workdays[i];
}
assertEquals("|Monday|Tuesday|Wednesday|Thursday|Friday",days);
forcreatesaforloopinti=0declaresanindexvariablewithaninitialvalueof0i<5theloopwillcontinuewhiletheloopconditionismet,inthiscasewhilewearestillaccessinganiteminthearray-thereare5itemsinthearray.Rememberarrayindexesstartat0sothelastitemis4.Index5wouldbeoutofbounds,soweuse<5.i++incrementthevalueoftheindex
Themoregenericexplanationofaforloopisactually:
for(initializestatementexecutedonce;loopcondition;executedaftereachloop){//dosomething}
SoIcouldhavewrittentheloop:inti=0;
for(;i<5;i++){
days=days+"|"+workdays[i];
}
Wherethevariableisinitializedoutsidetheloopandmyinitializestatementisempty.
Also:inti=0;
for(;i<5;){
days=days+"|"+workdays[i];
i++;
}
Andeven:inti=0;
for(;;){
days=days+"|"+workdays[i];
i++;
if(i>=5)break;
}
IntheabovecodeI’musingthebreakstatementwhichwesawintheswitchsection,tobreakoutoftheloop.
breakbreakisagenerickeywordtoendcontrolstatementexecution.breakcanexitanif,switch,forandlateriterationconstructswhile,do…while
Generally,keepingtothetraditionalexampleshownatthestartofthissectionmakesyourcodemorereadableandmaintainable.e.g.for(inti=0;i<5;i++){
days=days+"|"+workdays[i];
}
Youcanseefromeachofthevariantsthatevenwhenoneofthestatementsinthefor(...)aremissing,youstillneedtohavethe;inplace.
Usingfortoiteratethroughanarray,canleaveyouopentooffbyoneerrors,sobecareful.Butitdoesmeanthatyouhaveanindexcounteasilyavailabletouseintheloop.
e.g.inthefollowingexampleIaddtheloopindextotheoutputString@Test
publicvoidforLoopUsingIndexFixedCondition(){
Stringdays="";
for(inti=0;i<5;i++){
days=days+"|"+i+"-"+workdays[i];
}
assertEquals(
"|0-Monday|1-Tuesday|2-Wednesday|3-Thursday|4-Friday",
days);
}
Indexinaforeachloop
Ifyouwantanindexinsideaforeachloopthenyoucandoiteasilyenoughbycreatingavariableoutsidetheloop,andincrementingthevariablevaluewithintheloop.e.g.inthefollowingexampleIusedayindexastheindexvariable:intdayindex=0;
for(Stringworkday:workdays){
days=days+"|"+workday;
System.out.println("found"+workday+
"atposition"+dayindex);
dayindex++;
}
Whichwouldoutput:1foundMondayatposition0
2foundTuesdayatposition1
3foundWednesdayatposition2
4foundThursdayatposition3
5foundFridayatposition4
Exercise:Createanarrayof100usersCreateanarraywhichcanhold100Userobjects.UseaforlooptofillthearraywithUserobjectshavingthefollowingusername,passwordcombinations:
user1,password1user2,password2etc.
Findawaytocheckthearraywascreated.
Forbonuspoints,writesomecodetoassertthatthearraywasfilledproperly.
CalculateSizeofanArraywiththelengthmethod
length-returnsthelengthofthearray
Oncedeclared,youcanfindthesizeofanarrayusingthelengthmethod:assertEquals(5,workdays.length);
Thetypicaluseforthelengthmethodisinaforloopconditione.g.for(inti=0;i<workdays.length;i++){
days=days+"|"+workdays[i];
}
Sincethelengthofanarrayisalwaystheindexofthenextitemtoaddinthearray,wemakesurethatweuse<array.lengthintheloopcondition.
UsefulmethodsintheArraysclassJavaprovidesanArraysclassinjava.utils.
InordertouseArrays,youneedtoimportit.importjava.util.Arrays;
TheArraysclassprovidesanumberofusefulstaticmethods.
Wewillcoverasubsetofthemethodshere.Youcanseethefullrangeofmethodsintheofficialdocumentation.
copyOf-createacopyofanarray,andresizeifdesiredcopyOfRange-createacopyofpartofthearrayfill-fillthearray,orpartofthearraywithasinglevaluesort-sortthearray
Thesectionsbelowrefertotheworkdaysarray:String[]workdays={"Monday","Tuesday","Wednesday",
"Thursday","Friday"};
UsecopyOftocopyandresizeanArrayString[]weekDays;
weekDays=Arrays.copyOf(workdays,7);
UsingthestaticmethodcopyOfonArraywecancreateacopyofanarray,andoptionallyresizeit.
ThecopyOfmethodtakestwoarguments:
Arrays.copyOf(arrayToCopy,length);
Thisistypicallyusedtocreateacopyandincreasethesize.Whenweincreasethesize,thevaluesinthearray,whichwerenotintheoriginalarray,aresettothedefaultvalueforthatdatatypee.g.0forintegerandnullforString.
Inourexampleifwecreateacopyofworkdaysandresizeitfrom5to7thenthelasttwoindexeswillcontainnull.assertEquals(null,weekDays[5]);
assertEquals(null,weekDays[6]);
Thereforeweshouldsetthevaluesonthenewarrayifwewanttocontrolthecontents.
weekDays[5]="Saturday";
weekDays[6]="Sunday";
WecanalsousecopyOftotruncatethearrayandmakeitshorter:String[]weekDays;
weekDays=Arrays.copyOf(workdays,3);
assertEquals(3,weekDays.length);
assertEquals("Monday",weekDays[0]);
assertEquals("Tuesday",weekDays[1]);
assertEquals("Wednesday",weekDays[2]);
UsecopyOfRangetocopyasubsetofanArray
ThecopyOfRangecopiesasubsetofanarrayintoanewarrayofthesizeofthesubset.
Assert.copyOfRange(arrayToCopy,startIndex,endItemCount);
ThestartIndexisthefirstiteminthearraythatyouwanttocopy.
TheendItemCountistheindex+1thatyouwanttocopy.
e.g.ifIwanttocopyitems3to5inclusive(“Wednesday”,“Thursday”,“Friday”),thenIwouldstartthecopyfrom2(theindexofthethirditem),andendthecopyon5(eventhoughtheindexofthefifthitemis4).
Examplecodemighthelp:String[]weekDays=Arrays.copyOfRange(workdays,2,5);
assertEquals(3,weekDays.length);
assertEquals("Wednesday",weekDays[0]);
assertEquals("Thursday",weekDays[1]);
assertEquals("Friday",weekDays[2]);
assertEquals(weekDays[0],workdays[2]);
assertEquals(weekDays[1],workdays[3]);
assertEquals(weekDays[2],workdays[4]);
WecanalsousecopyOfRangetoincreasethesizeofthearray,muchlikewedidwithcopyOf.TodothiswejustuseanendItemCountgreaterthanthearraysize.e.g.String[]weekDays=Arrays.copyOfRange(workdays,2,7);
assertEquals(5,weekDays.length);
assertEquals("Wednesday",weekDays[0]);
assertEquals("Thursday",weekDays[1]);
assertEquals("Friday",weekDays[2]);
assertEquals(null,weekDays[3]);
assertEquals(null,weekDays[4]);
UsefilltopopulateanArraywithdata
Arraysprovidesastaticmethodcalledfillwhichwecanusetofillanarraywithaspecificvalue,orfillarangeofindexesinthearray.
Tofilleveryiteminthearraywiththesamevaluewemakeasimplecalltofill
Arrays.fill(array,value);
e.g.tofillanarrayofintegerswiththevalueminusone(-1),Icandothefollowing:
int[]minusOne=newint[30];
Arrays.fill(minusOne,-1);
Imightchoosetofillpartofanarray-possiblyifIhavejustdoneacopy,orcopyOfandresizedthearraylarger.
Arrays.fill(array,startIndex,endItemCount,value);
Again,thestartoftherangeistheindexnumberoftheitemwewanttostartat,andtheendoftherangeistheindex+1e.g.ifwewantedtostoponthe10thiteminanarray,whichisatindex‘9’wewouldusethevalue‘10’:int[]tenItems={0,0,0,0,0,1,1,1,1,1};
//fillcells5-9with'2'
Arrays.fill(tenItems,5,10,2);
//0-4areuntouched
assertEquals(0,tenItems[0]);
assertEquals(0,tenItems[4]);
//5-9nowequal2
assertEquals(2,tenItems[5]);
assertEquals(2,tenItems[6]);
assertEquals(2,tenItems[7]);
assertEquals(2,tenItems[8]);
assertEquals(2,tenItems[9]);
UsesorttoQuickSortanArray
JavaprovidesanimplementationofQuickSort.Toquicklysortanarray.
Arrays.sort(array);
e.g.IfIhaveanarrayofintegersinthewrongorder,thenIcanquicklysortthem.int[]outOfOrder={2,4,3,1,5,0};
Arrays.sort(outOfOrder);
assertEquals(0,outOfOrder[0]);
assertEquals(1,outOfOrder[1]);
assertEquals(2,outOfOrder[2]);
assertEquals(3,outOfOrder[3]);
assertEquals(4,outOfOrder[4]);
assertEquals(5,outOfOrder[5]);
YoucanalsosortString,orotherobjects.AlthoughwithstringsrememberthatuppercaselettershavelowerUnicodevaluesthanlowercaseletters,soyoumightwanttomakethestringsconsistentwithcaseusagebeforeyousortthem.
Exercise:SortWorkdaysArrayandAssertResultCreatean@Testmethodwhichinstantiatesaworkdaysarray,asshownintheexamplespreviously.String[]workdays={"Monday","Tuesday","Wednesday","Thursday","Friday"};
ThensortitusingArrays.sort
Assertthattheorderofvaluesinthearrayareasyouexpect.
Createanother@Testmethodsothattheworkdayshavemixedcase,andasserttheresulti.e.{"monday","Tuesday","Wednesday","thursday","Friday"}
ArraysofArraysRegularMultidimensionalArrays
Amultidimensionalarrayisanarrayofarrays.
Aregularmultidimensionalarrayhasallthenestedarraysofequallength.
SoIcoulddefinea2dimensionalintmultidimensionalarrayas:int[][]multi=newint[4][4];
Thiscreatesamultidimensionalarraycalledmulti.Whichis4by4,andsinceIhaven’tinitializedit,allthevaluesaredefaultof0.0,0,0,0,
0,0,0,0,
0,0,0,0,
0,0,0,0,
Whereeachiteminmultiisanarrayoflength4.e.g.multi[0]assertEquals(4,multi[0].length);
AndIcanaccessthevaluesinthatarraybyaddinganotherindexe.g.accessthefirstvalueinmulti[0]withmulti[0][0]assertEquals(0,multi[0][1]);
Aswiththeonedimensionalarrays,Icandeclareandinitializeanarrayinasinglestatement:int[][]multi={{1,2,3,4},
{5,6,7,8},
{9,10,11,12},
{13,14,15,16}};
Theabovearraywouldbepopulatedasfollows:1,2,3,4,
5,6,7,8,
9,10,11,12,
13,14,15,16,
Andwewouldaccessthevalueswiththe[0][0]multiindexnotation:assertEquals(1,multi[0][0]);
assertEquals(7,multi[1][2]);
assertEquals(12,multi[2][3]);
assertEquals(14,multi[3][1]);
IcouldcreateadditionaldimensionsifIwantede.g.a3dimensionalarrayof3by4by5int[][][]multi3d=newint[3][4][5];
Wheremulti3disanarrayoflength3,andeachitemisanarrayoflength4,
whereeachitemisanarrayoflength5whereeachitemisanint
assertEquals(3,multi3d.length);
assertEquals(4,multi3d[0].length);
assertEquals(4,multi3d[1].length);
assertEquals(4,multi3d[2].length);
assertEquals(5,multi3d[0][1].length);
assertEquals(5,multi3d[0][2].length);
assertEquals(5,multi3d[1][3].length);
Andwecanaccessindividualintitemsusingthefull[0][0][0]multiindexnotation:assertEquals(0,multi3d[0][0][0]);
RaggedArrays
Sinceweknowthatamultidimensionalarrayisactuallyanarray,ofarrays,of…
Wecanseehoweasyitistocreateraggedarrays,whereeacharrayhasdifferentlengths:int[][]ragged2d={{1,2,3,4},
{5,6},
{7,8,9}
};
Whichwouldcreatethefollowingarray:1,2,3,4,
5,6,
7,8,9,
Eachofthearrayshasadifferentlength:assertEquals(4,ragged2d[0].length);
assertEquals(2,ragged2d[1].length);
assertEquals(3,ragged2d[2].length);
Andwewouldaccessthearrayvaluesusingthenormalnotation:assertEquals(4,ragged2d[0][3]);
assertEquals(6,ragged2d[1][1]);
assertEquals(7,ragged2d[2][0]);
Wecandefineraggedarraysdynamically,byleavingtheraggeddimensionsblankwhenwecreateit:int[][]ragged2d=newint[10][];
Theabovecodecreatesa2dimensionalarrayof10xundefined,wherewehaven’tdefinedthelengthofeachofthe10arrays,wewoulddothatwhenweinitializetheme.g.
ragged2d[0]=newint[10];
ragged2d[1]=newint[3];
Theabovecodeinitializesthefirst2itemsinragged2dasanarraywith10items,andanarraywith3items,alltheremainingitemsinragged2dwillremainontheirdefaultofnull.e.g.0,0,0,0,0,0,0,0,0,0,
0,0,0,
null
null
null
null
null
null
null
null
Exercises
Understandhowprint2DIntArraymethodworksIusedThefollowingcodewhenwritingthebooktoprintoutthe2Darraysyou’veseeninthischapter.
Havealookthroughthecodeandmakesureyouunderstandit.
publicvoidprint2DIntArray(int[][]multi){
for(int[]outer:multi){
if(outer==null){
System.out.print("null");
}else{
for(intinner:outer){
System.out.print(inner+",");
}
}
System.out.println("");
}
}
CreateaTriangleCreatearaggedarray,suchthatwhenyoupassthearraytoprint2DIntArrayasanargumentyououtputatriangletotheconsolethatlookslikethefollowing:
0,
0,1,
0,1,2,
0,1,2,3,
0,1,2,3,4,
0,1,2,3,4,5,
0,1,2,3,4,5,6,
0,1,2,3,4,5,6,7,
0,1,2,3,4,5,6,7,8,
0,1,2,3,4,5,6,7,8,9,
0,1,2,3,4,5,6,7,8,9,10,
0,1,2,3,4,5,6,7,8,9,10,11,
0,1,2,3,4,5,6,7,8,9,10,11,12,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
SummaryArraysareafastandeasywayofcollectingobjects.
Theyrequirealittleworktodefinethesizeofthearrayinadvance,butyou’veseenthatyoucanusethecopyutilitymethodsinjava.util.Arraytohelpresizeanarray.
Remembertobecarefulwheniteratingthrougharrayssothatyoudon’tintroduceoffbyoneerrors.Ifyouareinanydoubtthenusingtheforeachformofaforloopcanhelpavoidintroducingthiserror.
ReferencesandRecommendedReading
JavaForLoopdocs.oracle.com/javase/tutorial/java/nutsandbolts/for.html
Branchstatementdocs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
JavaArraysdocs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
Java1.7Arraysdocumentationdocs.oracle.com/javase/7/docs/api/java/util/Arrays.html
ChapterTen-IntroducingCollections
WehavealreadyseenthebasiccollectionconceptinactionwithArrays.IpresentedArraysfirstsothatyouwouldunderstandtheconceptandthebasicsofiteratingoveracollection.
Collectionsareagoodplacetoconsiderotherloopingconstructslikewhile,dowhile.AndwewillalsointroducetheconceptofInterfaces.
ChapterSummaryInthischapteryouwilllearnthemaincollectionclasses.Theseoffermoreflexibilityandpowertoyouinyourdevelopmentwork.
ForEachLoop-iterateovereachindividualelementinacollectionConversion-convertingcollectionstoarraysandarraystocollectionswhileanddo…while-additionalloopingconstructsyoucanuseInterfaces-CollectionsareorganizedbyinterfacesandeachinterfacehasmultipleimplementationsGenerics-youwilllearnthebasicsofGenericstohelpyoudeclarecollectionsCoreCollections-Corecollectioninterfaces:List,Set,MapCoreImplementations-Corecollectionimplementations:ArrayList,HashSet,HashMap
Thisisoneofthelongestchaptersinthisbook.AndIknowitcanseemoverwhelming.SoIwillstartthechapterwithasimpleintroduction,comparingarraystoaspecifictypeofcollectioncalledaList,thencoverloopingovercollections,andthenthedifferentinterfacesandimplementationsforcollections.
ASimpleIntroductionTointroducecollections,IwillshowyouasimpleexamplecomparinguseofaCollectiontouseofanArray.@Test
publicvoidsimpleArrayExample(){
String[]numbers0123={"zero","one","two","three"};
for(StringnumberText:numbers0123){
System.out.println(numberText);
}
assertEquals("zero",numbers0123[0]);
assertEquals("three",numbers0123[3]);
}
Theaboveisarraycodeyouhaveseenbefore.
Thefollowingistheabovecode,rewrittentouseaCollection.@Test
publicvoidsimpleCollectionExample(){
String[]numbers0123Array={"zero","one","two","three"};
List<String>numbers0123=Arrays.asList(numbers0123Array);
for(StringnumberText:numbers0123){
System.out.println(numberText);
}
assertEquals("zero",numbers0123.get(0));
assertEquals("three",numbers0123.get(3));
}
IntheabovecodeyoucanseethatIconvertedthearraytoaListusingtheasListmethodonthejava.util.Arraysclass.
IiterateovertheListinthesamewaythatIiterateoverthearray.
IaccessspecificelementsintheListusingthesameindexnumberingschemeasanarray,i.e.0isthefirstelementintheList,3isthefourthelementintheList.
IdeclaretheListusingadifferentsyntax.i.e.List<String>.Thisuses‘Generics’notation,whichIwillexplaininthischapter,butessentiallyI’msaying“aListofStrings”.
CollectionsaredynamicOneadvantagecollectionshave,overarrays,isthattheyaredynamic,sowedon’thavetodeclaretheirsizeinadvance.
IcanrewritetheexampleyouhaveseensuchthatIbuildtheListdynamically.@Test
publicvoidsimpleDynamicCollectionExample(){
List<String>numbers0123=newArrayList<String>();
numbers0123.add("zero");
numbers0123.add("one");
numbers0123.add("two");
numbers0123.add("three");
for(StringnumberText:numbers0123){
System.out.println(numberText);
}
assertEquals("zero",numbers0123.get(0));
assertEquals("three",numbers0123.get(3));
}
Intheaboveexample,youcanseethatIhaveanewdeclarationsyntax.AndIaddtheStringvaluesintotheListwithoutworryingaboutthesizeoftheListbecauseIknowthattheListwillresize.List<String>numbers0123=newArrayList<String>();
IntheabovedeclarationListisaninterfacewhichdeclaresthetypeofCollectionIamusing.
ArrayLististhespecificimplementationofListthatIamusing.
Iwillexplaininterfaceinmoredetailinthischapter.Butforthemoment,aninterfaceisatypeofclasswhichspecifiesthemethodsthatanobjectwillimplement.SowhenIdeclare
mynumbers0123tobeaListIknowthatIhaveaccesstothegetmethod,andthattheelementsintheListwillbeaddedinorder.
SoaListisequivalenttothebehaviourofanarray,butisdynamic.IndeedanArrayListisatypeofListwhichisimplementedusinganArray.
Iteratingwithwhileanddo…whileInadditiontotheforloop,Javaalsoprovidesthewhileloop.Thisallowsustoloop‘while’aparticularconditionismet.
Itendtousetheforloopforiteratingaroundacollection.Butsometimeswedon’twanttoprocesseveryelementorwanttoiterateuntilaparticularconditionismet.
Therearetwoforms:
while(condition){...}
do{...}while(condition)
Withawhileloop,thebodyoftheloopmightneverbeexecuted,becausetheconditionmaynotbesatisfied.
Withado…whileloop,thebodyoftheloopisalwaysexecutedatleastonce.
AsanexamplecomparisonIwillcreateasimplelistofdays.String[]someDays={"Tuesday","Thursday",
"Wednesday","Monday",
"Saturday","Sunday",
"Friday"};
List<String>days=Arrays.asList(someDays);
Iwillwritesomesimplecodeusingeachoftheloopconstructs:
foreach
for
dowhile
while
AndwewillseethedifferentapproachesItakeforfindingthepositionof"Monday"intheList.
Withtheforeachloop,IcaniterateovereveryelementintheListandwhenIfind"Monday"Iwillhavetobreakoutoftheloop.intforCount=0;
for(Stringday:days){
if(day.equals("Monday")){
break;
}
forCount++;
}
assertEquals("Mondayisatposition3",3,forCount);
Withtheforloop,IwilliterateoverthesizeoftheListandbreakwhenIfind"Monday":
intloopCount;
for(loopCount=0;loopCount<=days.size();loopCount++){
if(days.get(loopCount).equals("Monday")){
break;
}
}
assertEquals("Mondayisatposition3",3,loopCount);
Withthewhileloop,Icanmakethecheckfor"Monday"theloopexitcondition,soIonly‘do’thebodyoftheloop,‘while’Ihavenotfound"Monday":intcount=0;
while(!days.get(count).equals("Monday")){
count++;
}
assertEquals("Mondayisatposition3",3,count);
Withthedo…whileloop,IneedtosettheindexoutsidethevalidboundaryofthelistbecauseIincrementitinthebodyoftheloop,andagainIonly‘do’thebodyoftheloop‘while’Ihavenotfound"Monday":intdocount=-1;
do{
docount++;
}while(!days.get(docount).equals("Monday"));
assertEquals("Mondayisatposition3",3,docount);
Theforeachloopisanexcellentchoicewhenyouwanttolooparoundeveryelementinacollection.Youdon’thavetoworryaboutoffbyoneindexerrorsoroutofboundsexceptions.Butyouhavetobreaktofinishtheloopearly.
Theforloop,isaverypowerfulconstruct,butcanbecomehardtoreadiftheconditionislong,orthesetuporendofloopactionsarecomplicated.
Thewhileanddo…whileloopareanexcellentchoiceiftheloopneedstoterminatebasedonanarbitraryorcomplexcondition.Choosingbetweenwhileanddo…whileisdoneonthebasisof:
usedo…whileifyouwantthelooptorun1ormoretimesusewhileifyouwantthelooptorun0ormoretimes
Exercise:UseaforloopinsteadofawhileloopUsethecodeabovetocreatethedaysoftheweekArray,convertittoalist,anditerateoveritwithawhileloop.Thenconvertthewhileloopintoaforloop.Hint:Usetheconditioninthewhileloopasaforloopconditionstatementanddemonstratethattheforloopcanbeusedasawhileloop.
e.g.for(…;addwhileconditionhere;…)
InterfacesArraysareasimplecollectionmechanismbuttheydon’tofferthesameinterfaceascollections.
Javahasaconceptofaninterface.Byinterface,ImeanthemethodstheyexposeandtheAPIthatweusetoworkwiththeclasses,i.e.aninterfacedefineswhatyoucando.
Aclasscanimplementanumberofinterfaces,inwhichcaseitmustimplementthemethodsthataredefinedinallofthoseinterfaces.
Javaprovidesanumberofinterfacesforcollections:
Collection-agenericcollectionthatyoucanaddobjectstoSet-acollectionthatdoesnotallowduplicatesList-acollectionyoucanaccessandaddelementsatspecificindexpositionsMap-a“key,value”pairwhereyoustoreanobjectinthecollection,butcanaccessitwithauniquekey
TheCollectioninterfacesareallinjava.util
ImportantInterfacesIhaveonlylistedabove,whatIconsiderthemostimportantinterfacesabove,i.e.theonesthatIusemostoften.
Thisdemonstratesmybiases,andtheneedsofthecodeIwrite.
Overtimeyouwillidentifytheinterfaces,andimplementationthatyouusealot.Learnthoseindetailsothatyouunderstandthemwell.Butmakesurethatyoulearnthecapabilitiesoftheotherinterfacesandimplementationssothatyouknowwhentousethem,anddon’ttryanduseasinglecollectiontype,whenanotherwouldfityourneedsbetter.
DeclareasInterfaces,InstantiateImplementationsAnInterfaceonitsowncannotbeusedtodoanything.Otherclassesimplementinterfacesandsowedeclarevariablesastheinterfacebuthavetoinstantiatethemwithimplementations.e.g.Collectionworkdays;
workdays=newArrayList();
HereIhavedeclaredavariablecalledworkdaysasaCollectionbecauseIonlyneedtousethemethodsthattheCollectioninterfaceprovides.ButIhavetoinstantiateitasanArrayListwhichisaclassthatimplementstheCollectioninterface.
TheArrayListclassexposesmanymoremethodsthantheCollectioninterface.HadIdeclaredthevariableworkdaysasanArrayListIwouldgainaccesstomethodslikeindexOf,trimToSize,andget.
WhenIonlyneedaccesstothemethodsonCollectionthenIshoulddeclaremyvariablesattheminimumleveloffunctionalityneeded.
Bycodingtointerfaceslikethis,wehavetheabilitytoswapinandouttheimplementationclass;ifwediscoverthatoneimplementationisfasterthananother,ortakeslessmemory.Butwedon’thavetochangethebodyofthemethodcodewhenweswapadifferentonein.
e.g.IcoulduseArrayListorLinkedListorHashSetasmyimplementationforCollectionbecauseeachimplementtheCollectioninterface.ButIneedtounderstandtheimplementationincaseoneofthemimposesconstraintsonmycodethatIdon’twant,forexampleaHashSetdoesnotallowduplicateelements,butanArrayListdoes.
Thismaynotmakesenseyet,butitisanimportantconceptandIwilltrytoillustrateitthroughalltheexamplesinthischapter.
CoreCollectionInterfacesTheofficialdocumentationliststhefollowingastheCoreCollectioninterfaces:
Collection
List
Set
SortedSet
Queue
Deque
Map
SortedMap
InthischapterwewillcoverList,SetandMapandleavetheothercollectionsuntillaterinthebook.
InheritanceHierarchyThisisaninheritancehierarchy;soaSetisaCollection,aListisaCollection,butbothSetandListhavenuancesthatmakethemunique.
Therearetwomaincollectionconcepts:CollectionandMap
Collectionprovidesawayofgroupingobjects.Mapprovidesawayofassociatingobjectswitha‘key’forlaterretrievalandaccessing.
ThefollowingtableprovidesasummaryofthemainmethodsontheInterfaces:
Collection List Set Map
add(e) get(i)AllinCollection
put(k,v)
remove(e) remove(i) remove(k)
removeAll(c) add(i,e) entrySet
retainAll(c) addAll(i,c) get(k)
clear indexOf(e) clear
contains(e) lastIndexOf(e) containsKey(k)
containsAll(c) set(i,e) containsValue(v)
size subList(i1,i2) size
isEmpty isEmpty
toArray AllinCollection values
toArray(a) keySet
addAll(c) putAll(m)
where:e==element,c==collection,a==array,i==index,k==key,v==value,m==map
CollectionInterfaceACollectionisagroupofobjects.Whereeachobjectisreferredtoasanelement.TheCollectioninterfaceprovidesthebasicsupersetofmethods.
add-toaddanelementtoacollectionremove-toremoveanelementfromacollectionsize-toreturnthenumberofelementsinthecollectionisEmpty-checkifacollectionisemptyaddAll-toaddeveryelementofanothercollectionintothecollectionremoveAll-removeeveryelementofanothercollectionfromthecollectionretainAll-removeeveryelementinthecollectionwhichisnotinanothercollectionclear-toremovealltheelementsfromthecollectioncontains-tocheckifanobjectisinthecollectioncontainsAll-tocheckthatonecollectioncontainsalltheelementsofanothertoArray-toconvertacollectiontoanarray
Instantiatingacollection
WecannotinstantiateaCollectionbecauseaCollectionisaninterface.Thereareclasseswhichimplementtheinterface,e.g.ArrayList.SowedeclareourvariablesasCollectionandinstantiatethemasclasswhichimplementstheinterface.Collectionworkdays;
workdays=newArrayList();
Intheabovecodewehaveausablevariablecalledworkdays.Butacollectioncancontainanyobject,andsincewedidn’tspecifywhatthecollectionwillcontainitdefaultstoobject.ThiswillbecomeanannoyancelaterwhenwetryanditeratethroughthecollectionandhavetocasttheelementsfromobjecttoString.
Asarecommendation,whenyouworkwithacollection,andtheobjectstobestoredinthecollectionareallofthesametypethendeclarethecollectionasacollectionoftypee.g.Collection<String>weekendDays=new<String>ArrayList();
Collection<String>daysOfWeek=new<String>ArrayList();
IntheabovecodeIdeclaretheCollectionasacollectionof<String>.WhichIinstantiatewithanArrayListthatwillonlycontain<String>.
Thisprovidesanumberofbenefits:
ItmakesthecodeclearastothecontentsofthecollectionItmakesthecollectionsstronglytypedwhichhelpswithcodecompletionlater
Trytogetinthehabitofdeclaringthetypeofthecontentsofthecollectionwhenyouknowthatthecollectionwillonlycontainonetypeofelement.
GenericsThe<String>notation,isausageofJavaGenericswhichisawayofdeclaringclassestouseaparticulartypeofobject,butonlydefiningthetypeatcompiletime.
Afulldiscussionofgenericsisbeyondthescopeofthisbook,butitisimportanttorecognizetheusageofit,andknowhowtotakeadvantageofitwiththeclassesyouuse.AtthemomentyouhaveonlyseenGenericsinthecontextofcollections.
Readthereferencesongenericsifyouwanttoself-studygenericsinmoredetail.
Fornow,understandthat<String>declaresthetypeofelementsintheCollectionandimplementationClass.
GenericSyntaxInmostoftheexamplesinthisbookIwillusethesyntaxlikethefollowing:Collection<String>weekendDays=new<String>ArrayList();
Itisalsopossibletoleaveoutthe<String>ontheArrayListanduse<>andtheJavacompilerwillusetheGenericvaluefromtheinterfacedeclaratione.g.Collection<String>weekendDays=newArrayList<>();
ThenewersyntaxisshorterandsometimesyourIDEwillcodecompleteintheaboveformatforyou.
ThereasonIdon’tuseit,issimplybecauseI’mnotusedtousingit,IthinkitonlyarrivedinJava1.7
ThefollowingsyntaxforusingGenericsareequivalent:Collection<String>cola=newArrayList<String>();
Collection<String>colb=new<String>ArrayList();
Collection<String>colc=newArrayList<>();
addingelementstoacollection:add,addAll,size,containsAll
Wecanaddelementstoacollectionwiththeaddmethod.
workdays.add("Monday");
workdays.add("Tuesday");
workdays.add("Wednesday");
workdays.add("Thursday");
workdays.add("Friday");
assertEquals(5,workdays.size());
WecanusethesizemethodtocountthenumberofelementsintheCollection.
AndwecanusetheaddAllmethodtoaddalltheelementsfromoneCollectionintoanother:daysOfWeek.addAll(workdays);
assertEquals(workdays.size(),daysOfWeek.size());
assertTrue(daysOfWeek.containsAll(workdays));
IntheabovecodeweaddalltheelementsinworkdaystoanemptycollectiondaysOfWeek.
ThecontainsAllmethodcanhelpuscheckifaCollectioncontainsalltheelementsofanothercollection.TheCollectionthatwecallthecontainsAllmethodon(i.e.daysOfWeek)cancontainmoreelementsthantheargumentCollection(i.e.workdays),butinorderforcontainsAlltoreturntrue,alloftheelementsoftheargumentcollection,mustbepresent.
removingindividualelements:remove,contains
IfIaddsomeelementstoweekendDays.weekendDays.add("Saturday");
weekendDays.add("Funday");
ThenyoucanseethatImadeamistakebyspellingSundayincorrectlyasFunday.
IcanfixthaterrorbyremovingFundaywiththeremovemethod:weekendDays.remove("Funday");
IcanusethecontainsmethodtocheckifaCollectioncontainsaspecificelement.IfIcheckforFundaycontainsshouldreturnfalse:assertFalse(weekendDays.contains("Funday"));
OfcourseIcanaddthecorrectvalueintotheCollection,andcheckitspresence.weekendDays.add("Sunday");
assertEquals(2,weekendDays.size());
assertTrue("BugFixed,Sundayisinthecollectionnow",
weekendDays.contains("Sunday"));
Iterateoveracollection
ACollectionactuallyimplementstheIterableinterface.Whichformsthebackboneoftheforeachfunctionalitythatwesawearlier.
So,assumingthatIhaveaddedalltheworkdaysandweekendDaysintodaysOfWeek,Icaniterateoveritwiththeforeachconstruct.for(StringdayOfWeek:daysOfWeek){
System.out.println(dayOfWeek);
}
Togeneratethefollowingoutputtotheconsole:Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
IteratingovertheCollectionprovidesagoodillustrationofwhywewanttodeclarethetypeofelementthatthecollectionholds.Forthedeclarationofworkdaysthatwepresentedearlier:Collectionworkdays;
workdays=newArrayList();
WhenIiterateoverthis,IgetanObjectratherthanaspecifictype:for(Objectworkday:workdays){
StringoutputDay=(String)workday;
System.out.println(outputDay);
}
IntheabovecodeIhadtodeclareworkdayasanObjectandwhenIuseditwithintheloop,IhadtocastittoStringusingthe(String)notation.
Whenwewanttorefinethetypeofanobjectthenwecancastittoaspecifictype.Wecandothatwhentheobjectsupportstheinterfaceforthattype,orisofthattype.
WeusedtohavetocastobjectsalotinJava,butnowthatthecollectionssupportGenericswecanspecifythetypeinthedeclarationandavoidcastinglater.
EmptyaCollection:clear,isEmpty
Theclearmethodallowsustoemptyacollection.Collection<String>daysOfWeek=new<String>ArrayList();
daysOfWeek.addAll(workdays);
daysOfWeek.addAll(weekendDays);
assertEquals(7,daysOfWeek.size());
daysOfWeek.clear();
assertEquals(0,daysOfWeek.size());
assertTrue(daysOfWeek.isEmpty());
WecanusesizeandisEmptytoverifythatithasnoelements.
RemovingAllofonecollectionfromanother:removeAll
AssumingthatmydaysOfWeekCollectioncontainsalltheweekendDaysandworkdays.
IcanremovethecontentsoftheweekendDaysCollectionfromdaysOfWeekwiththeremoveAllmethod:Collection<String>daysOfWeek=new<String>ArrayList();
daysOfWeek.addAll(workdays);
daysOfWeek.addAll(weekendDays);
assertEquals(7,daysOfWeek.size());
daysOfWeek.removeAll(weekendDays);
assertTrue(daysOfWeek.containsAll(workdays));
assertEquals(5,daysOfWeek.size());
assertFalse(daysOfWeek.containsAll(weekendDays));
IcanusethecontainsAllmethodtocheckthattheremovaltookplace.
Removeallbutonecollectionfromanother:retainAll
SotoretainonlytheweekendDaysindaysOfWeekIwoulddothefollowing:daysOfWeek.retainAll(weekendDays);
UsetheretainAllmethodtoremoveallbutonecollectionfromanother.Orinotherwords,retainonlytheelementsfromtheargumentcollection,inthecollectionIcallthemethodon.Collection<String>daysOfWeek=new<String>ArrayList();
daysOfWeek.addAll(workdays);
daysOfWeek.addAll(weekendDays);
assertTrue(daysOfWeek.containsAll(workdays));
assertTrue(daysOfWeek.containsAll(weekendDays));
daysOfWeek.retainAll(weekendDays);
assertEquals("onlyweekenddaysnow",2,daysOfWeek.size());
assertTrue(daysOfWeek.containsAll(weekendDays));
assertFalse(daysOfWeek.containsAll(workdays));
Convertacollectiontoanarray
UsethetoArraymethodtoconvertaCollectiontoanarray.
Thismethodcanbeusedintwoforms.
toArray()
toArray(anArray)
WhenwecalltoArraywithoutanargument,itwillreturnanarrayofObjectObject[]daysOfWeekArray=daysOfWeek.toArray();
assertEquals(7,daysOfWeekArray.length);
IfwesubsequentlywantedtouseelementsfromthearraywewouldhavetocastthemasString.i.e.(String):assertEquals("Monday".length(),
((String)daysOfWeekArray[0]).length());
ThetoArray(anArray)call,wherewepassasargumentaninitializedarray,avoidstheseproblems:
String[]anotherArray=newString[daysOfWeek.size()];
daysOfWeek.toArray(anotherArray);
assertEquals("Monday".length(),
anotherArray[0].length());
IntheabovecodeIdeclareaStringarray,andinitializethearrayatthecorrectsizetoholdthecollectioncontents.ThencallthetoArraymethodwiththatarrayastheargument.
CollectionDocumentation
YoucanfindthedetailsofCollectionontheofficialdocumentationsite.
Interface:
docs.oracle.com/javase/tutorial/collections/interfaces/collection.html
Implementations:
docs.oracle.com/javase/tutorial/collections/implementations
ItypicallyuseaListimplementationwhenIwantjustagenericCollection,butwewillcoverotherimplementationslaterinthischapter.
Exercise:CreateandmanipulateaCollectionofUsersCreateaCollectionofUsersAssertthatthesize()==0andisEmpty()==trueCreatetwoUserobjectsAddtheUserobjectstothecollectionAssertthatthesize()==2andisEmpty()==falseCreateasecondcollectionwithtwodifferentusersaddAllthesecondcollectiontothefirstcollectioncheckthatthefirstcollectionnowcontainsobjectsfromthesecondcollectionremoveAlltheUserobjectsfromthesecondcollectionclearthefirstcollection
Ensureyouassertaftereachstep
ListAListbuildsontheCollection,soallCollectionmethodsareavailable.
AList:
allowsstoringofduplicateelements,retainselementsintheorderadded.allowsaddingelementsinspecificplacesinthelist
ItendtouseaListinpreferencetoanArray.Arraysareclearlyatalowerlevelandfaster.ButIonlyuseanArraywhenI’mworkingwithafixedsetofobjectsthatIknowarenevergoingtochange.
IfmycodeneedstobeparticularlyfastthenImightoptimizedowntoanArray.ButifI’mworkingonanycodedynamically,thenaListwilloftenbemyfirstchoiceasitisaverysimplecollection.
AListoffersallthemethodsfromCollectionandadds:
get(i)toretrieveanelementfromaspecificindexremove(i)toremovetheelementatanindexadd(i,e)toaddataspecificindex,anelementaddAll(i,c)toadd,ataspecificindex,allelementsinacollectionindexOf(e)toreturntheindexofanelementlastIndexOf(e)toreturnthelastindexofanelementset(i,e)tosettheelementataparticularindexsubList(i1,i2)toreturnasublistfromindex1toindex2
InalloftheexamplesIwilldeclareaListthatwillcontainString,andwillinstantiateasanArrayList,whichyoualsosawintheCollection@Testmethods.ItendtodefaulttoArrayListforbothCollectionandList.e.g.List<String>days=newArrayList<String>();
getanelementatindex
AListexposesanarraystyleinterfacewhereeachelementinthelisthasapositionalindex,whichlikeanarraystartsat0.@Test
publicvoidgetAnElementAtAnIndex(){
List<String>days=newArrayList<String>();
days.add("Monday");
days.add("Tuesday");
days.add("Wednesday");
assertEquals("Monday",days.get(0));
assertEquals("Tuesday",days.get(1));
assertEquals("Wednesday",days.get(2));
}
Intheabovecode,theListguaranteesthattheelementsIaddwillbeaccessibleintheorderthatIaddthemsothatthefirstelementaddedcanbeaccessedwithindex0,thesecondelementaddedcanbeaccessedwithindex1etc.
removeanelementatindex
Inadditiontohavingtheabilitytoremoveanelement,wecanalsoremoveelementsbasedontheirindex.@Test
publicvoidremoveAnElementAtAnIndex(){
List<String>days=newArrayList<String>();
days.add("Monday");
days.add("Tuesday");
days.add("Wednesday");
days.remove(1);
assertEquals(2,days.size());
assertEquals("Monday",days.get(0));
assertEquals("Wednesday",days.get(1));
}
WhenIremoveanelementbasedonitsindex,thelistresizesandelementsaftertheoneremovedhavetheirindexesadjusted.SoifIremovetheelementatindex1,theelementthatwasatindex2cannowbefoundatindex1.
addanelementataspecificindex
WithaCollectionwecanaddelements,buttheyarejustinthecollection,theycouldbeanywhere,wedon’tcare.
Withanarray,wehavetoresizethearrayifwewanttoaddnewelements.
WithaListwecanaddelementsatspecificpointsintheList.
Inthisexample,Istartwithapartiallistofdays.List<String>days=newArrayList<String>();
days.add("Tuesday");
days.add("Thursday");
days.add("Saturday");
Ineedtoaddafewdaystothislist:days.add(0,"Monday");
days.add(2,"Wednesday");
days.add(4,"Friday");
days.add(6,"Sunday");
Iadd“Monday”tothestartofthelist,then“Wednesday”and“Friday”intothemiddleofthelist,and“Sunday”attheendofthelist.
YoucanseethatwhenIaddanelementinthemiddleorthestart,thatitdoesn’toverwritetheelementthatisalreadythere,itinsertstheelementandmoveseverythingelseinthelisttoanewindex.
AddingtotheendWhenaddingtotheendoftheListyoucanonlyaddtotheend,youcan’taddwaybeyondthesizeoftheListandexpectittoresize.
i.e.ifIhave3elementsinmyListthenIcanaddanotheroneatindex3.Index3doesn’texistuntilIaddit(Ican’tget(3)),butIcanincreasethesizeofthelistbyaddingtotheend.Icannotaddanelementtoindex20,JavawouldthrowanIndexOutOfBoundsException.
Icouldalsousetheadd(e)method,becauseaddinganelementtoaListaddsittotheendoftheList.
addAllelementsinacollectionataspecificindex
WithaCollectiontheaddAlladdstheelementssomewhereinthecollection.WithaListwecancontrolexactlywhereweinserttheelementsinthecollection.
Forexample,ifIcreatedaListfordays:
days.add("Monday");
days.add("Friday");
IcouldcreateanothercollectionwiththemissingDaysandinsertthem,intothemiddleofthedayscollection.days.addAll(1,missingDays);
Thiswouldinsertthecollectionatindex1,andmove“Friday”toposition4.Itwouldnotoverwritetheelementexistingatindex1,theaddAllatanindexperformsaninsertList<String>days=newArrayList<String>();
List<String>missingDays=newArrayList<String>();
days.add("Monday");
days.add("Friday");
missingDays.add("Tuesday");
missingDays.add("Wednesday");
missingDays.add("Thursday");
days.addAll(1,missingDays);
assertEquals(5,days.size());
assertEquals("Monday",days.get(0));
assertEquals("Tuesday",days.get(1));
assertEquals("Wednesday",days.get(2));
assertEquals("Thursday",days.get(3));
assertEquals("Friday",days.get(4));
CanInsertatStartandEndAswithaddtheaddAll(i,c)methodcaninsertthecollectionatthestartoftheListbyusingindex0,orattheendoftheListbyusingthe‘nextindex’orthe‘size’.
AddingtotheendoftheListwithanindexisequivalenttousingtheaddoraddAllmethodwithoutanindex.SincetheaddmethodsonaListaddtotheendoftheList.
indexOffindtheindexofanelement
WhenwehaveaListandwedon’tknowtheindexoftheelementinthelistthenwecanusetheindexOfmethodtotelluswhereintheListtheelementcanbefound.List<String>days=newArrayList<String>();
days.add("Tuesday");
days.add("Thursday");
days.add("Saturday");
assertEquals(1,days.indexOf("Thursday"));
IfindexOfisusedonaListwithduplicatesthenitwillreturnthefirstindexoftheelement.
lastIndexOfthethelastindexofanelement
AListallowsduplicateelements,sowemaywanttofindthepositionofthelastoftheduplicates.InwhichcasewewouldusethelastIndexOfmethodtodothis.
List<String>days=newArrayList<String>();
days.add("Tuesday");
days.add("Thursday");
days.add("Saturday");
days.add("Thursday");
days.add("Thursday");
days.add("Sunday");
assertEquals(4,days.lastIndexOf("Thursday"));
IflastIndexOfisusedonaListwithnoduplicatesthenitreturnsthesameasindexOf.
settheelementatanindex
Whenusinganarray,thearray[1]="NewElement"wouldoverwritetheexistingcontentsatindex1.Wecandothesamethingwithsetwhichallowsustosetthevalueofaparticularindex.
Forexample:List<String>days=newArrayList<String>();
days.add("Monday");
days.add("Thursday");
days.add("Wednesday");
days.set(1,"Tuesday");
assertEquals("Tuesday",days.get(1));
Intheabovecode,Ioriginallyadd"Thursday"intoindex1,butthenoverwriteitto"Tuesday"withthesetmethod.days.set(1,"Tuesday");
Andbecausesetperformsanoverwrite,thesizeoftheListdoesnotchangeandnore-orderingtakesplace.assertEquals(3,days.size());
assertEquals("Monday",days.get(0));
assertEquals("Tuesday",days.get(1));
assertEquals("Wednesday",days.get(2));
subListtocreateaportionofthelist
TocreateanewListwithaselectionofelementsfromaparentListweusethesubListmethod.
subListtakestwoarguments,thefromIndex,andthetoIndex.ThetoIndexis1morethantheindexyouwant.
Forexample,ifIcreatealistofdaysandwantasubListofjusttheworkdays"Monday"through"Friday"."Monday"willbeatindex0,and"Friday"isatindex4,butifIwanttoinclude"Friday"inthenewsub-listthenIhavetouse5asmytoIndex:List<String>days=newArrayList<String>();
days.add("Monday");
days.add("Tuesday");
days.add("Wednesday");
days.add("Thursday");
days.add("Friday");
days.add("Saturday");
days.add("Sunday");
List<String>workdays=days.subList(0,5);
assertEquals(5,workdays.size());
assertEquals("Monday",workdays.get(0));
assertEquals("Tuesday",workdays.get(1));
assertEquals("Wednesday",workdays.get(2));
assertEquals("Thursday",workdays.get(3));
assertEquals("Friday",workdays.get(4));
ListDocumentation
YoucanfindthedetailsofListontheofficialdocumentationsite.
Interface:
docs.oracle.com/javase/tutorial/collections/interfaces/list.html
Implementation:
docs.oracle.com/javase/tutorial/collections/implementations/list.html
Exercise:CreateandmanipulateaListofUsersWritean@Testannotatedmethod,andcreateaListofUserobjects.
CreatetheListCreatetwoUserobjectsAddaUsertothelistAddaUsertothefrontofthelistAssertontheindexOfpositionsoftheUserobjectsremovethefirstUserobject
RemembertoassertaftereachactionontheList
SetASetbuildsontheCollection,soallCollectionmethodsareavailable.
ASet:
doesnotallowstoringduplicates,soaddingaduplicateisignored.orderingisnotguaranteed,soifyouiteratethroughasetitmaynotbringbacktheelementsintheorderyouexpect
@Test
publicvoidsetDoesNotAllowDuplicateElements(){
Setworkdays=newHashSet();
workdays.add("Monday");
workdays.add("Monday");
workdays.add("Monday");
workdays.add("Monday");
workdays.add("Monday");
assertEquals(1,workdays.size());
}
ItendtouseaHashSetfromjava.utilasmydefaultSetimplementation.
SetsofCustomObjectsBecarefulifyouwanttocreateaSetofyourownobjectsandhaveJavaidentifytheduplicatedelements.TheduplicationcheckisbasedonahashandyouneedtoimplementyourownhashCodemethodwhichgeneratesauniquehashforeachuniqueobject.
Youshouldalsoimplementyourownequalsmethod.
IhavedecidedtomakethisoutofscopeforthisbookbecauseIthinkmostofyouareunlikelytoexperiencethis.I’massumingthatyouaremainlylikelytocreateaSetcontainingbuiltinclasses.
Iveryoftenavoidthisproblembycreatingsetsof‘keys’forobjectsstoredinaMapandthekeystendtobeString.
HoweverifyoudoneedtocreateaSetofcustomobjectsthenthereferencesinthe“NextSteps”chapter,orattheendofthischapter,shouldhelp.
SetDocumentation
YoucanfindthedetailsofSetontheofficialdocumentationsite.
Interface:
docs.oracle.com/javase/tutorial/collections/interfaces/set.html
Implementation:
docs.oracle.com/javase/tutorial/collections/implementations/set.html
Exercise:CreateandmanipulateaSetofUsersWritean@Testannotatedmethod,andcreateaSetofUserobjects.
CreateaUserAddtheUsertotheSetAddtheUsertotheSetagainCheckthattheUserhasonlybeenaddedtotheSetonce
MapAMapisacollectionwhereeachelementisavalue,anditisstoredwithanassociatedkey.
TheMapisacollectionofkeyvaluepairs.
Eachkeymustbeunique.Andeachkeymapstoonlyonevalue
MaphassomemethodsincommonwithCollection:
sizeclearisEmpty
Whichmeansyoualreadyknowwhatthosemethodsdo.
Andsomemethodsthathaveaverysimilarcounterpart:containsKeyandcontainsValuearesimilartotheCollectionmethodcontains.
put(k,v)toadd“key,value”pairstothemapremove(k)toremovetheelementwiththatkeyentrySettoreturnaSetofallelementsasMap.Entryobjectsget(k)toreturntheelementbasedonthekeycontainsKey(k)returnstrueifthekeyisintheMapcontainsValue(v)returnstrueifthevalueisintheMapvaluesreturnsaCollectionofallthevalueskeySetreturnsaSetofallthekeysputAll(m)addsaMap(m)totheMapobject
ItendtouseHashMapasmydefaultimplementation.Andbelowyoucanseeexamplesofthedeclarationandinitializationcode:Map<String,User>mapa=newHashMap<>();
Map<String,User>mapb=newHashMap<String,User>();
Map<String,User>mapc=new<String,User>HashMap();
IntheabovecodeyoucanseethataMapisdeclaredwithtwovaluesMap<Key,Value>sointheabovecodeIdeclaretheMapvariablesashavingaStringkey,andaUservalue.SoIwouldusetheMaptostoreUserobjects.put(k,v)
Add“key,value”pairstoaMapwiththeputmethod.Map<String,String>map=newHashMap<>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
assertEquals(3,map.size());
Thekeycanbeanobject,ascanthevalue.ThedeclarationoftheMapdetermineswhatobjectswecanputintotheMap.
IfIputa“key,value”pair,wherethekeyalreadyexistsintheMapthentheoldvaluewillbeoverwrittenwiththenewvalue:map.put("key1","newvalue1");
assertEquals("newvalue1",map.get("key1"));
get(k)toretrieveavaluefromtheMap
IcangetvaluesfromtheMapusingthekeythatIputthevalueintotheMapwith.
assertEquals("value1",map.get("key1"));
assertEquals("value2",map.get("key2"));
assertEquals("value3",map.get("key3"));
IfIattempttogetavaluewithakeythatdoesnotexistthennullwillbereturned.assertEquals(null,map.get("key4"));
remove(k)toremovea“key,value”pair
IcanremoveavaluefromaMapbycallingtheremovemethodwithanexistingkey.map.remove("key1");
assertEquals(2,map.size());
IfthekeydoesnotexistthennoexceptionisthrownandnothinghappenstotheMap,themethodcallhasnoimpact.
EmptyaMapwithclear,checkwithsize,isEmpty
JustaswecouldwiththeCollection,wecanemptytheMapbycallingtheclearmethod.map.clear();
assertEquals(0,map.size());
assertTrue(map.isEmpty());
IcancheckthattheMapisemptyusingthesizeandtheisEmptymethods.
CheckcontentsofMapwithcontainsKey(k)andcontainsValue(v)
ThecontainsKeymethodreturnstrueorfalse.truewhensomethingwiththekeyhasbeenputintheMapandfalsewhennothingusingthatkeyhasbeenputintheMapMap<String,String>map=newHashMap<>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
assertTrue(map.containsKey("key1"));
assertFalse(map.containsKey("key23"));
assertTrue(map.containsValue("value2"));
assertFalse(map.containsValue("value23"));
putAll(m)toaddaMaptotheMap
IcanputoneMapinsideanotherMapwiththeputAllmethod:map.putAll(mapToAdd);
IfItryandaddaMapthatcontainsakeyduplicatinganexistingkey,thenthevaluefromthenewMapwillbeused:e.g.inthefollowingcodethekey“key1”isduplicatedacrossbothMapobjects:map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
mapToAdd.put("key1","keyvalue1");
mapToAdd.put("key4","value4");
WhenIputmapToAddintomap:map.putAll(mapToAdd);
Theexistingvaluefor“key1”isoverwrittenwiththevaluefrommapToAdd:assertEquals(4,map.size());
assertEquals("keyvalue1",map.get("key1"));
values
valuesreturnsaCollectioncontainingallthevaluesintheMap:Collection<String>values=map.values();
EachvaluewillbeofthetypedeclaredfortheMapkeySet
keySetreturnsaSetwhereeachelementisakeyfromtheMap:Set<String>keys=map.keySet();
entrySettoworkwith“key,value”pairs
entrySetreturnstheSetofEntryobjectsfromjava.util.Map.
AnEntryisthe“key,value”pair.
Entryexposesthemethods:
getValuetoreturnthevaluegetKeytoreturnthekeysetValuetosetthevalue
ThefollowingcodeiteratesthroughtheentriesintheMapandsetsallthevaluesto"bob":Set<Map.Entry<String,String>>entries=map.entrySet();
for(Map.Entry<String,String>entry:entries){
entry.setValue("bob");
}
MapDocumentationYoucanfindthedetailsofMapontheofficialdocumentationsite.
Interface:
docs.oracle.com/javase/tutorial/collections/interfaces/map.html
Implementation:
docs.oracle.com/javase/tutorial/collections/implementations/map.html
Exercise:CreateandmanipulateaMapofUserobjectsWritean@Testannotatedmethod,andcreateaMapofUserobjects.
CreateaMapofUserobjectsCreatetwoUserobjectsAddbothUserobjectstothemapusingthesamekeyCheckthatonlyoneUserobjecthasbeenadded
SummaryInthischapteryoulearnedthebasicsofCollections.
ACollectionisthemostgenericcollectioninterfacewhichsupportsadding,removinganditeratingoveracollectionofobjects.
CollectionsusetheGenericssyntaxtodefinethetypeofobjectinthecollectione.g.List<String>tocreateaListofStringobjects.
ThebasicCollectioninterfacesare:
Collection-abasiccontainerList-toallowaccessingbyindexSet-toavoidduplicatesMap-tostore“key,value”pairs
Eachinterfacecanhavemultipleimplementations,theimplementationsweusedinthischapterwere:
Collection&List:ArrayList
Set:HashSet
Map:HashMap
Collectionsofferustheabilitytocreatedynamicandre-sizablecontainers,ratherthanfixedsizearraycontainers.
ReferencesandRecommendedReading
Programtoaninterface,notanimplementationartima.com/lejava/articles/designprinciplesP.html
JavaInterfaceTutorialdocs.oracle.com/javase/tutorial/java/concepts/interface.html
JavaCollectionsTutorialsdocs.oracle.com/javase/tutorial/collections
JavaCollectionInterfaces
docs.oracle.com/javase/tutorial/collections/interfaces/index.htmlJavaGenerics
docs.oracle.com/javase/tutorial/java/genericsJavaCollectionImplementations
docs.oracle.com/javase/tutorial/collections/implementationsHashCode
docs.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode%28%29List
Interfacedocs.oracle.com/javase/tutorial/collections/interfaces/list.html
Implementationsdocs.oracle.com/javase/tutorial/collections/implementations/list.html
SetInterface
docs.oracle.com/javase/tutorial/collections/interfaces/set.htmlImplementations
docs.oracle.com/javase/tutorial/collections/implementations/set.htmlMap
Interfacedocs.oracle.com/javase/tutorial/collections/interfaces/map.html
Implementationsdocs.oracle.com/javase/tutorial/collections/implementations/map.html
ChapterEleven-IntroducingExceptions
ChapterSummaryInthischapteryouwilllearnaboutexceptions:
anexceptionisanunexpectedeventwhichcaninterruptourcodeexecutionunderstandthestacktraceonanexceptionhowtohandleanexceptionusingtryandcatchandfinallytriggeraNullPointerExceptionandhowtocatchthemthrowingexceptionsfromyourowncodeusingmethodsontheexceptione.g.getMessage,getStackTracecatchingmultipleexceptionsJUnit’sexpectedparameteron@Test
Anexceptionissomethingthathappenstoyouwhenyouleastexpectit.Oftenbecauseyouhavewrittencodewhichcompiles,buthasanerroratruntimee.g.youtrytoaccessafilethatdoesnotexist,oraccessavariablethathasnotbeenset.Andsometimesbecausesomethinguntowardhappenedonthemachineyourcodewasexecutinge.g.thesystemrunsoutofmemory.
Averyimportantpartoflearningtowriteautomationinvolveshandlingandprocessingexceptions.
WhatisAnexception?Anexceptionisanobjectraisedwhichinterruptstheflowofexecutioninanapplication.
Becauseweareusingautomationtosupportourtesting,weshouldexpectourautomationcodetotriggeranomalousandexceptionalbehaviour.Ourautomationcodewillencounterbugsandunexpectedsituationsandwehavetobeabletohandlethem.
Wealsouseexceptionsinourabstractionstoletthecallingautomationcodeknowthatsomethingunexpectedhashappened.
Automationcodeisverydifferentfromapplicationcodeinthatweoftenwantexceptionstoshowthemselvesandcauseour@Testmethodstofail.
Inapplicationcodewerarelywantexceptionstomanifestbecausetheyslowthewholesystemdownandcreateapooruserexperience.
Whatisanexception?NormallyJavacodeproceedsfromonestatementtothenexte.g.StringageAsString=age.toString();
StringyourAge=
"Youare"+ageAsString+"yearsold";
IntheabovecodeJavawould:
callthemethodtoStringontheagevariableassignthereturnvaluefromtoStringtotheageAsStringvariablebuildaStringfromtheconstant"Youare",thevariableageAsString,andtheconstant"yearsold"assignthatStringtotheyourAgevariable
Alloftheabovecodewouldexecutioninsequence.
Anexceptionisawayofinterruptingthenormalflowofexecutionwhensomethinggoeswrong.
Whenanexceptionoccursthecurrentstatementisterminatedandtheexecutionflowstops.Ifthereisnoprogramcodetocatchandhandletheexceptionanywhereinthesequenceofcallingcodethentheexceptionwillterminatetheprogram.
Whatdoesanexceptionlooklike?Thesimplestwayofunderstandinganexceptionistoseeoneinaction.
Ihavecreatedapackageinsrc\test\javacalled:packagecom.javafortesters.chap011exceptions.examples;
AndaddedaJUnittestclasscalledExceptionsExampleTest.
Iwilladdallmy@Testannotatedmethodsintothisclass.
Thefollowingcode,whenannotatedwith@Test,willcauseaNullPointerExceptiontobethrown.
Runitandsee:publicvoidthrowANullPointerException(){
Integerage=null;
StringageAsString=age.toString();
StringyourAge=
"Youare"+ageAsString+"yearsold";
assertEquals("Youare18yearsold",yourAge);
}
Intheabovecode,youcanseethatIforgottoassignavaluetotheIntegerage,anditissettonull.SowhenItrytocallthetoString()methodonage,JavathrowsaNullPointerException.
Inthiscasethethrownexceptionisgoodforus,becauseweseethatwemadeamistakeinourcoding,andwecanfixitbyassigningavalue,i.e.18,totheagevariable.
Theexceptionreportiswrittentotheconsole:
1java.lang.NullPointerException
2atcom.javafortesters.exceptions.ExceptionsExampleTest.
3throwANullPointerException(ExceptionsExampleTest.java:15)
4atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)
5...
6atorg.junit.runners.ParentRunner.run(ParentRunner.java:309)
7atorg.junit.runner.JUnitCore.run(JUnitCore.java:160)
8atcom.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs
9(JUnit4IdeaTestRunner.java:77)
10atcom.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart
11(JUnitStarter.java:195)
12atcom.intellij.rt.execution.junit.JUnitStarter.main
13(JUnitStarter.java:63)
14atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)
15atsun.reflect.NativeMethodAccessorImpl.invoke
16(NativeMethodAccessorImpl.java:57)
17atcom.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Intheaboveexceptionmessageyoucanseethecallstacktrace.Iremovedafewlinestoavoidclutteringthepage(representedby...inthelisting).
Eachoftheatlinesrepresentsacallandisanestedstepintheexecutionofthecode.Themostrecentcallisatthetop(lines2and3inthelisting).TheselinestellusthataNullPointerExceptionwasthrownonline15ofExceptionsExampleTest.java.throwANullPointerException(ExceptionsExampleTest.java:15)
Theneachoftheloweratlinesisanotherlevelwherethecodewasexecuted.BecauseweareusingJUnitandIranthecodefromtheIDE,therearealotofstepsinvolved.
Workingfromthebottomupyoucanseethat:
line17:anapplicationmainmethodwascalledfromIntelliJAppMain.java:120
lines14-16:variousreflectionmethodswerecalledtostartthecodeNativeMethodAccessorImpl.java:57
lines10-13:JUnitwascalledJUnitStarter.java:63
lines8&9:JUnitstartedaJUnitrunnertorunthe@TestmethodJUnit4IdeaTestRunner.java:77
lines5-9:thentherewereabunchoflinesallrelatedtostartingandexecutingthemethodlines1-3:beforeourcodefailedonline15
ExceptionsExampleTest.java:15
Tobehonest,Idon’tfullyunderstandallthelinesinthatstacktrace.ButIcanlookatthemandmakearoughguesswhatishappeningandIcanseethemostimportantparts.
Thestacktraceisusefulbecauseitshowsthelinenumbersthatwereinvolvedincallingthecode,andforusthemostimportantisline3inthelisting.Wheretheline(15)inExceptionsExampleTest.javaisdescribedasthesourceoftheexception.Thishelpsusdebugthecodewhenanexceptionisthrown.
Exercise:FixtheNullPointerExceptioninthecodeAmendthecodetoassign18totheageandcheckthecoderunssuccessfullywithoutthrowinganexception.
CatchingExceptionsTherearesituationswhereweknowinadvancethatanexceptionmighthappen,andwewanttocatchtheexceptionandtakeactiontohandletheexception.e.g.wetrytoopenafile,butitdoesn’texist,sowecatchtheexceptionandthencreatethefile.
ThisiswherethetryandcatchkeywordsinJavahelpus.Integerage=null;
StringageAsString;
try{
ageAsString=age.toString();
}catch(NullPointerExceptione){
age=18;
ageAsString=age.toString();
}
Imadeafewchangestothecodetousethetrycatch:
declareStringageAsString;beforethetrydeclarethetypeofexceptiontocatch,inthiscaseaNullPointerException.takeactiontohandletheexceptioninthecatchblock.i.e.IassignedavaluetotheIntegerage.
IhavetodeclareStringageAsString;beforethetry.Youcanseethattryhasacodeblockdelimitedwith{and}.IfIdeclaredageAsStringwithinthatcodeblockitwouldonlybeaccessibleforcodewithinthetrycodeblock’s{and},andnotavailabletocodeinthecatchblockorafterthetryandcatchblocks.
InthecatchIhavetodeclarewhattypeofexceptionIwillcatch.InthiscaseIonlywanttocatchNullPointerExceptionssodeclareavariableeasaNullPointerException.
Inthecatchblock,IassumethatIhavereachedthiscodebecauseagewasnull,soIassignitavalueandrepeattheIntegertoStringconversion.SoIusethecatchblocktofixthecauseoftheexceptionandtakeactiontoallowtherestofthecodetoruntocompletion.
trycatchNotesCodeinthetryblockwillalwaysrun.Thecatchblockwillexecuteonlyifthedeclaredexceptionisthrown.Exceptionsthatarethrowninthecatchblockwillpropagateupthestacki.e.tocallingmethods.
Thecodeinthetryblockwillalwaysberun.
Ifanexceptionisthrown,anditisofthetypedeclaredbythecatchblockthenthecodeinthecatchblockwillberun.
Ifanexceptionisthrownwithinthecatchblock.Thenitwon’tbere-caughtbecausethereisnotrycatchstatementsurroundingit.
IfadifferentexceptionisthrownthenitwillnotbecaughtbecauseIhavespecifiedthatonlyNullPointerExceptionwillbecaught.
Myfullcodelookslikethis:@Test
publicvoidcatchANullPointerException(){
Integerage=null;
StringageAsString;
try{
ageAsString=age.toString();
}catch(NullPointerExceptione){
age=18;
ageAsString=age.toString();
}
StringyourAge=
"Youare"+age.toString()+"yearsold";
assertEquals("Youare18yearsold",yourAge);
}
Exercise:UseadifferentexceptioninsteadofNullPointerExceptionReplaceNullPointerExceptionwithArithmeticException.
Whathappens?
Exercise:Don’tfixthecauseoftheexceptionRemovetheage=18;statementfromwithinthecatchblock.
Runthe@Testmethodandseewhathappens.
Exercise:CatchaCheckedExceptionUseNoSuchMethodExceptioninsteadofNullPointerException.
Whathappens?
AnExceptionisanobject}catch(NullPointerExceptione){
age=18;
ageAsString=age.toString();
}
YoucanseeinmycatchblockthatIdeclaredaparametereasaNullPointerException.
ThismeansthatwithinthecatchblockIhaveaccesstoalocalvariablee.Youcouldcallthisvariablewhateveryouwant,alotofpeoplestickwitheasaconvention.
eisanobjectoftypeNoSuchMethodExceptionsoIhaveaccesstoavarietyofmethodsonthisexception.Afewusefulmethodsare:
getMessage-showsmetheerrormessageassociatedwiththeexceptionsoIcanlogitgetStackTrace-anArrayofStackTraceElementobjectwithmethodcallsthatrevealthelinesofcodewhichleduptothethrowingoftheexception,whichcanhelpwithdebuggingprintStackTrace-whichprintsthestacktracetotheerroroutputstream-typicallyyourconsoleorcommandline
Exercise:UseExceptionasanobjectAddthefollowingcodeinyourcatchblock,runthe@Testmethod,andseewhatinformationyougetfromtheexceptionitself.
ThegetStackTracemethodreturnsanarrayofStackTraceElementobjects,investigatewhatthemethodsonthisobjectreveal.
System.out.println("getMessage-"+
e.getMessage());
System.out.println("getStacktrace-"+
e.getStackTrace());
System.out.println("printStackTrace");
e.printStackTrace();
CatchmorethanoneexceptionInthetrycatchcodeabove,Ionlycheckedforasingletypeofexception.
Thecatchblockcanberepeatedtowritecodethatcatchesmultipleexceptions.Integerage=null;
StringageAsString;
try{
ageAsString=age.toString();
}catch(NullPointerExceptione){
age=18;
ageAsString=age.toString();
}catch(IllegalArgumentExceptione){
System.out.println("IllegalArgument:"+
e.getMessage());
}
Intheabovecodesnippet,thecatchblockswillhandleeitheraNullPointerExceptionoranIllegalArgumentException.
JUnitandExceptionsJUnithasahandyfeaturetoallowustocheckforthrownexceptions.@Test(expected=NullPointerException.class)
Wecantellthe@Testannotationtoexpectanexceptionofaparticularclasstobethrown.
TheabovecodetellsJUnittoexpecttohaveanexceptionoftypeNullPointerExceptionthrownduringtheexecution.
IfnoNullPointerExceptionisthrownthenthemethodwillfail.
IfaNullPointerExceptionisthrownthenthemethodwillpass.
Forexample,thefollowingmethodpassesbecauseaNullPointerExceptionisthrown:@Test(expected=NullPointerException.class)
publicvoidnullPointerExceptionExpected(){
Integerage=null;
age.toString();
}
Becarefulwiththisparameterastheexceptioncouldbethrownanywhereinthemethodcodeandyourmethodwouldstillpass,sowhenyouusethisparametermakesurethatyourcodeisassmallaspossibletotriggertheexceptionandyouhaveother@Testmethodswhichensurethatthesetupcodeworks.Afterall,ifyoursetupcodethrewaNullPointerExceptionthenthemethodwouldpass,butwouldnothavecheckedwhatyouwanted.
ThrowinganExceptionWearenotlimitedtocatchingtheexceptionsfromcodethatotherpeoplehavewritten.Wecanalsothrowexceptionswhenweneedto.
AsanexampleofthisIwillrevisittheabstractionlayerwehaveforusers,wherewewereabletoconstructauserbypassingintheusernameandpassword.
Iwillamendthissothatthepasswordischeckedandtheconstructorwillthrowanexceptionifthepasswordislessthan7charactersinlength.
I’llre-usethesetPasswordmethodintheconstructorwithparameterssothatIonlyhavetoaddthevalidationrulecheckinginthesetPasswordmethod.publicUser(Stringusername,Stringpassword){
this.username=username;
setPassword(password);
}
ThenfinallyIwritecodetoimplementthepasswordvalidationlengthchecking.publicvoidsetPassword(Stringpassword){
if(password.length()<7){
thrownewIllegalArgumentException("Passwordmustbe>6chars");
}
this.password=password;
}
Toexplainthisinmoredetailwewilllookatthepasswordlengthcheck.if(password.length()<7){
thrownewIllegalArgumentException("Passwordmustbe>6chars");
}
TovalidatethelengthofthepasswordIcheckthelengthoftheString.Ifthelengthis<7(lessthanseven).thrownewIllegalArgumentException("Passwordmustbe>6chars");
Sinceanexceptionisanobject,IhavetocreateanewinstanceofanIllegalArgumentException.Andthethrowkeywordisimportantbecausethisiswhatcausestheexceptiontointerrupttheflowofexecution.
AlsonotethatwhenIcreatethenewexceptionIaddanexplanatorymessage.Thisaddsadditionalinformationtothestacktracetohelpanyonedebugthecode.Theerroroutputforthisexception,ifitwasnotcaughtandhandledlooksasfollows:java.lang.IllegalArgumentException:Passwordmustbe>6chars
atcom.javafortesters.domainentities.interim.exceptions.User.setPassword
(User.java:29)
atcom.javafortesters.domainentities.interim.exceptions.User.<init>
(User.java:19)
atcom.javafortesters.exceptions.UserPasswordExceptionsTest.
passwordMustBeGreaterThan6Chars(UserPasswordExceptionsTest.java:22)
...
YoucanseefromtheaboveerrormessageoutputthatthefirstthinginthestacktraceistheexplanatorytextthatIaddedwhenIthrewtheexception.
Throwingexceptionsinyourabstractionlayersisausefulwaytokeepthecodesimpleandclean,andhelpavoidmakingsimpleerrorsinyour@Testmethods.
finally
Sometimeswewanttotryanddosomething,catchandhandleanyexceptions,andthenfinally,alwaysexecutesomecode.try{
//tryanddosomething
}catch(NullPointerExceptione){
//handletheexceptionhere
}finally{
//performthecodehere
//regardlessofwhetheran
//exceptionwasthrownornot
}
Inthefollowingcode,thefinallyblockisusedtoassignavaluetotheyourAgevariable:@Test
publicvoidtryCatchFinallyANullPointerException(){
Integerage=null;
StringageAsString;
StringyourAge="";
try{
ageAsString=age.toString();
}catch(NullPointerExceptione){
age=18;
ageAsString=age.toString();
}finally{
yourAge="Youare"+age.toString()+"yearsold";
}
assertEquals("Youare18yearsold",yourAge);
}
Thefinallyblockismainlyusedwhenwewanttore-throwanexception,butbeforewelosecontroloverthecodeexecutionwewanttotidyupresources.
Inthefollowingcode,insteadoffixingtheage,Ire-throwtheNullPointerExceptionasanIllegalArgumentException.
IfIdidnotaddthefinallyblock,assoonasIthrowtheIllegalArgumentException,nomorecodeinthismethodwouldbeexecuted.BecauseIaddedthefinallyblock,theIllegalArgumentExceptionisthrown,butbeforecontrolispasseddownthecallstack,thecodeinthefinallyblockisexecuted:@Test(expected=IllegalArgumentException.class)
publicvoidexampleTryCatchFinally(){
Integerage=null;
try{
System.out.println("1.generateanullpointerexception");
System.out.println(age.toString());
}catch(NullPointerExceptione){
System.out.println("2.handlenullpointerexception");
thrownewIllegalArgumentException
("NullpointerbecameIllegal",e);
}finally{
System.out.println("3.runcodeinfinallysection");
}
}
Whichgeneratesthefollowingoutput:11.generateanullpointerexception
22.handlenullpointerexception
33.runcodeinfinallysection
4
5java.lang.IllegalArgumentException:NullpointerbecameIllegal
6atcom.javafortesters.exceptions.ExceptionsExampleTest.
7exampleTryCatchFinally(ExceptionsExampleTest.java:144)
8atsun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethod)
9...26more
Youcanseefromtheabovethat:
thetryblockexecuteswecatchtheNullPointerExceptionwethrowanIllegalArgumentExceptionsinceweareabouttolosecontroloftheexecutionduetotheIllegalArgumentException,thefinallyblockexecutestheIllegalArgumentExceptionistriggeredandtheflowofexecutionisinterrupted.
SummaryYouwillhavetohandleexceptionswhenyouwriteautomationcodebecausemanyofthelibrariesyouusewillthrowexceptionstoalertyouofunexpectedevents.
Wewillrevisitexceptionsinafuturechaptersoyoulearnhowtocreateyourownexceptions.
WhenwritingabstractionlayersforautomationItrynottoputassertsinmyabstractionlayers,ratherIthrowexceptionssothatthe@Testannotatedmethodcaneitherpropagatethem,orcatchandhandlethem.
ReferencesandRecommendedReading
Exceptionsdocs.oracle.com/javase/tutorial/essential/exceptions
OfficialDefinitionofanExceptiondocs.oracle.com/javase/tutorial/essential/exceptions/definition.html
StackTraceElementdocs.oracle.com/javase/7/docs/api/java/lang/StackTraceElement.html
ChapterTwelve-IntroducingInheritance
ChapterSummaryInthischapteryouwilllearnabriefoverviewofInheritance:
AnObjectcaninheritfromanotherObjectstoreusecodeAnObjectcanre-implementinheritedmethodsYoucanre-usecodethroughcomposition,aswellasinheritanceusethekeywordextendsinJavatoinheritfromaClass
BeforeweprovidemoreinformationaboutExceptionswehavetoprovideanoverviewofInheritanceandhowyouuseJavatoextendotherclasses.
InheritanceInheritanceisanObject-orientedDesignconcept.Javaprovidesanimplementationofsomeinheritancefeatures.Inthischapteryouwillreceiveaverybriefoverviewofinheritance,mainlysothatyouunderstandsomeofthemechanismsthatJavaprovides,andtohelpyouunderstandsomeofthemoreadvancedsectionsasweworkthroughthebook.
Ihavecoveredinheritancelateinthebookbecauseyoudon’treallyneeditfortheearlypartsofthisbook.Thebookstartedbyhavingyou‘use’Java.Youdidn’treallyneedtoextendanyclasses.
WhenwestartcreatingourownExceptionclasses,thenwewillneedtoextendotherclasses,soweneedtounderstandtheJavaconceptofInheritance.
YouhaveseenthatJavaClasseshavemethodsandfields.Andthatthosemethodsandfieldscouldbemadepublicorprivate.
Inheritanceprovidesonewayofallowingustore-usethosemethodsinotherclasses.
Wemakeoneobjectinheritfromanotherbyuseoftheextendskeyword.importcom.javafortesters.domainentities.User;
publicclassEmptyUserextendsUser{
}
Intheaboveexample,theEmptyUserobjectinheritsfromtheUserobject.
AnypublicmethodsontheUserobject,are‘inherited’bytheEmptyUserobject,soyou,asaprogrammer,donothavetowritethosemethods.
IfyouwanttheEmptyUsertohaveadifferentimplementationofanyofthosemethodsthenyoucanimplementthemethodinEmptyUserandoverridethemethodinheritedfromUser.
YoucanseefromthepreviouscodethatEmptyUserhasnocodeinthebodyoftheclass,butIcanuseitinan@Testmethod,becauseit‘inherits’themethodsfromtheUserobject.@Test
publicvoidemptyUserExampleTest(){
EmptyUserenu=newEmptyUser();
assertEquals("username",enu.getUsername());
assertEquals("password",enu.getPassword());
}
AtthispointtheEmptyUseroffersthesamefunctionalityastheUser.
InheritanceorCompositionInheritanceisanObject-orientedDesigntechnique,andrepresentsan‘isa’relationship.Sowhenweextendanobjectwearereallysayingthatthenewobject‘isa’typeofobjectthatweareextending.
CompositionisanObject-orientedDesigntechnique,andrepresentsa‘hasa’relationship,sooneobject‘has’someotherobject(s)e.g.abottlehasatop.
Object-orientedDesignisbeyondthescopeofthisbook(seethereferencessectionformoredetail).ButitisimportanttounderstandthatsomeofJavafunctionality,implementsObject-orientedconcepts.
Inheritance
InheritanceisanObject-orientedDesigntechnique,andrepresentsan‘isa’relationship.Whenweextendanobjectwearereallysayingthatthenewobject‘isa’typeofobjectthatweareextending.
e.g.SuperWidget‘isa’Widget,EmptyUser‘isa’User
Ifweuseinheritanceonlybecausewewanttore-usecodethenweruntheriskthatwemakeourcodehardertore-use,maintainandunderstand,becauseJavasupportssingleinheritancei.e.youcanonlyextendoneobject.Ifyoulaterwantto‘change’thesuperclass(theclassweextend)thenthiscanbehardtodowithoutextensivechangesinyourcode.
Note,thefollowingexampleisaterribleexample,nevereverdosomethinglikethefollowinginyourcode.WhileitisfunctionallypossibletoextendprettymuchanyotherClass,thatdoesnotmeanweshoulddoso.Seethelatersectionsinthischapterforguidance.Butjusttoreiterate-neverdothefollowing:
Forexample:ImaydecidethatIwanttheUsertobeabletoreturntheURLthattheyareusing,currentlyIhavethisintheTestAppEnvobject.Icouldre-usethecodeinTestAppEnvbyhavingtheUserobjectextendtheTestAppEnv.ThentheUserobjectinheritsagetUrlmethod.
UnfortunatelyaUserisnotaTestApplicationEnvironment,sowhilethismightseemlikeausefulshortcuttore-usesomecode,Idonotconsideritagoodideainpractice.
BecauseaUserisnotaTestAppEnv,extendingTestAppEnvtore-usecodewillleadtocodewhichreliesonunrelatedObjects,andifyoudothisthroughoutyourcodebase,it
willeventuallybecomeunmaintainable,andunreadable,andchangesinoneareaofthecodewillhaveunexpectedconsequencesinotherareasofthecode.
Composition
VeryoftenIdon’tuseInheritanceinmycode.Icodeusing‘composition’and‘interfaces’.Thisbasicallymeans,implementinginterfaces,andembeddingotherobjectswithinmycodeandgainingre-usebyusingtheirmethods.
Forexample,:IfIdidwantagetUrlmethodinmyUserthenImightfindawaytore-useaTestAppEnvobjectinmyUserobject.IftheTestAppEnvobjectrequiredinstantiationthenIwouldinstantiateitintheUserconstructor.ThenIwouldaddagetUrlmethodtomyUser,butthemethodactuallycallsthegetUrlontheTestAppEnv.
Exercise:CreateaUserthatiscomposedofTestAppEnvTryandimplementtheaboveUserobject,sothattheUser‘isa’Userobject,whichalsohasagetUrlmethod,wheretheimplementationofthatmethodisachievedbydelegatingtoaTestAppEnvobject.
UsingInheritanceAbetterexamplefortheuseofinheritance,givenourcurrentsmallnumberofdomainabstractionobjects,mightbetocreateanAdminUser.
Assumingthatthesystemundertesthasdifferenttypesofusers,andthatAdminusershavedifferentpermissionsfromanormalUser.IcouldaddagetPermissionleveltotheUser.
Thefollowingcodewouldcheckforthis:@Test
publicvoidaUserHasNormalPermissions(){
UseraUser=newUser();
assertEquals("Normal",aUser.getPermission());
}
ThenIcouldimplementthegetPermissionmethodonUser.publicStringgetPermission(){
return"Normal";
}
TocreatetheAdminUserIwoulddeclaretheAdminUserclassasaclasswhichextendsUser.publicclassAdminUserextendsUser{
Andre-implementthegetPermissionmethodinAdminUser,toreturnadifferentvalue.publicStringgetPermission(){
return"Elevated";
}
IalsohavetocreatetheconstructorsformyAdminUser:publicAdminUser(){
this("adminuser","password");
}
publicAdminUser(Stringusername,Stringpassword){
super(username,password);
}
NotethatIcallthesuperconstructor,whichcallstheconstructoronUser(thesuperclass)
IcouldchecktheAdminUserasfollows:@Test
publicvoidanAdminUserDefaultConstructor(){
AdminUseradminUser=newAdminUser();
assertEquals("adminuser",adminUser.getUsername());
assertEquals("password",adminUser.getPassword());
assertEquals("Elevated",adminUser.getPermission());
}
@Test
publicvoidanAdminUserHasElevatedPermissions(){
AdminUseradminUser=newAdminUser("admin","Passw0rd");
assertEquals("admin",adminUser.getUsername());
assertEquals("Passw0rd",adminUser.getPassword());
assertEquals("Elevated",adminUser.getPermission());
}
Inalloftheabovenotethat,Ididn’thavetorewritethegetUsernameorgetPasswordmethods,sinceweinheritedthosefromUserwhenweextendedit.
Onelastthingtonote.Ishouldreallyaddthe@OverrideannotationtothegetPermissionmethod.ThistellsthecompilertocheckthatthegetPermissionmethodisreallyontheUserobjectandisstillthesamedeclaration.Thishelpsfindanysimpleerrorsatcompiletime,ratherthanruntime.
SomyfinalAdminUserclasslooksasfollows:publicclassAdminUserextendsUser{
publicAdminUser(){
this("adminuser","password");
}
publicAdminUser(Stringusername,Stringpassword){
super(username,password);
}
@Override
publicStringgetPermission(){
return"Elevated";
}
}
Exercise:CreateaReadOnlyUserCreateaReadOnlyUserwhichhasthepermissionReadOnly,withthesamedefault“username”and“password”fromUser.
InheritfromInterfacesandAbstractClassesInproductionJavacode,acommonrecommendationistocodetoInterfaces.RatherthanInheritance.
Wehaven’treallycoveredInterfacesindetailinthisbook,becauseI’mtryingtogetyouupandrunningfast.
ButyousawthisconceptwhenusingCollections.
Collectionsarebasedaroundinterfaces.
TheCollectionsthemselvesimplementinterfaces,andextendAbstractClasses.
Sinceyoudon’treallyneedtoworryaboutthisuntilyouhavealargercodebase,andhavemorefamiliaritywithJava,Ihavedelegateddiscussionofthisintothe“AdvancingConcepts”chaptertowardstheendofthebook.
SummaryInheritancecanbeusedasa‘codere-use’tool,butitisbetterusedtoconstructobjectswhichhavean‘isa’relationship.
Whenwere-implementamethodfromthe‘super’classthatweextendthenweannotatethemethodwith@Overridetomakeitcleartootherpeoplewhatwehavedone,andwegainsomecompiletimecheckingofouractions.
Wecanaddnewmethodsintotheclasswhichisinheritingandthesewillnotbeaddedtothesuperclass.
Anynewmethodsinthesuperclasswillautomaticallybemadeavailabletotheextendingclass.
Privatemethodsandfieldsarenotaccessiblethroughinheritance,onlythesuperclass’sprotectedandpublicfieldsandmethodsareaccessiblethroughinheritance.
ReferencesandRecommendedReading
ObjectOrientedDesignConceptsdocs.oracle.com/javase/tutorial/java/concepts
InheritanceorCompositionDiscussionen.wikipedia.org/wiki/Composition_over_inheritance
ObjectOrientedProgrammingConceptsen.wikipedia.org/wiki/Object-oriented_programming
ChapterThirteen-MoreAboutExceptions
ChapterSummaryInthischapteryouwilllearnmoreaboutexceptions:
UncheckedExceptionCheckedExceptionTheExceptionInheritancehierarchyHowtocreateyourownException
Afterthischapteryouwillbeabletousecodethatotherpeoplehavewrittenwhichthrowexceptionsandcreateyourownexceptionstoaddintoyourownabstractionlayers.
UncheckedandCheckedExceptionsAlltheexamplesyouhaveseensofarinthebookhavebeenuncheckedexceptions.
AnUncheckedexceptionisonethatcanbethrown,byamethod,withouthavingtodeclarethattheexceptionwillbethrown.Acheckedexception,hastobedeclared,andgenerallyrepresentsaparticularusecasethat,while‘exceptional’stillhastobeexplicitlyhandled,ordeliberatelyignoredbythecallingcode.
UncheckedExceptionsUncheckedexceptionscanbitewithoutyouknowingtheywilloccur.YousawanexampleofthisintheearlierchapterswiththeNullPointerException.
AnUncheckedExceptionisalsoknownasaRuntimeException,asyouareonlymadeawareofthematruntime.
IfyouwanttocreateanUncheckedexceptionyouextendRuntimeExceptionoranyoftheclasseswhichalreadyextendit.
e.g.
IllegalArgumentException
ArithmeticException
NoSuchElementException
etc.
Idon’tthinkIhaveevercreatedacustomexceptionthatextendedanUncheckedexception.GenerallywhenIcreatecustomexceptionsIwantpeopletobeawareofthemandhandlethemintheircode.
IfIdowanttothrowanuncheckedexceptionIwillfirstofalltryanduseoneofthestandardjava.languncheckedexceptions.
Forexampleyousawtheuseofajava.languncheckedexceptionwhenweaddedtheexceptiontothepasswordvalidationinUserIusedtheIllegalArgumentExceptionbecauseIwasvalidatingaparametertoamethod.
ItmightbeappropriatetocreatemyownuncheckedexceptionsifIwanttoallowcodetodistinguishbetweenexceptionsthattheabstractionlayerhasthrownatruntime,andthoseexceptionsthrownbytheJavaruntime.
CheckedExceptionsYouwillbeinformedabouttheneedtohandlecheckedexceptionsatcompiletimebecauseacheckedexceptionwillbedeclaredasbeingthrownbythemethoddeclaration.
Forexample,IcoulddeclarethesetPasswordmethodonUserasthrowinganInvalidPasswordexception(assumingthatInvalidPasswordexceptionexisted,whichitdoesn’t,butitwillwhenwecometothe‘CreateyourownExceptionclass’sectionlaterinthischapter):publicvoidsetPassword(Stringpassword)throwsInvalidPassword{
Then,anywhereinthecodethatIusethesetPasswordmethodIeitherhaveto:
handletheexception,aswesawbeforeinatrycatchblock,orignoretheexceptionandallowittopropagateupwards
IgnoringCheckedExceptions
Thewaythatweallowanexceptiontopropagateupwardsistodeclarethemethodthatweare‘ignoring’themethodin,asthrowingthatparticularexception.
Forexample,sincetheUserconstructorcallssetPassword,Ieitherhavetohandletheexceptionor,asshownbelow,allowittopropagateupwards:publicUser(Stringusername,Stringpassword)throwsInvalidPassword{
this.username=username;
setPassword(password);
}
Handlingcheckedexceptionsindefaultconstructor
IfIcallaconstructorfromanotherconstructore.g.this("username","password");
Thenthefirststatementintheconstructorhastobethethiscall.WhichmeansthatIcannotwrapthatcallwithatrycatch.
Ihavetofindadifferentwayofdelegatingtheconstructioncall.InthiscodeIchosetochangethedefaultconstructorsothatitcallsaprivateconstructor.publicUser(){
this("username","password",false);
}
privateUser(Stringusername,Stringpassword,booleanb){
//onlycallthisbecausewedon'twanttothrowtheexception
this.username=username;
try{
setPassword(password);
}catch(InvalidPassworde){
thrownewIllegalArgumentException(
"Defaultpasswordincorrect",e);
}
}
ThiswayIensurethatanyoneusingtheno-argumentconstructordoesn’thavetohandleanInvalidPasswordexceptionforahardcodedpassword.@Test
publicvoidcanCreateDefaultUserWithoutHandlingException(){
UseraUser=newUser();
assertEquals("username",aUser.getUsername());
assertEquals("password",aUser.getPassword());
}
Buttheystillhavetohandletheexceptioniftheyusetheconstructorwheretheusernameandpasswordarepassedinbytheprogrammer.@Test
publicvoidhaveToCatchIllegalPasswordForParamConstructor(){
try{
UseraUser=newUser("me","wrong");
fail("Anexceptionshouldhavebeenthrown");
}catch(InvalidPasswordinvalidPassword){
assertTrue("Theexceptionwasthrown",true);
}
}
NotethatintheabovecodeIusedfailfromJUnittocausethe@Testmethodtofailifwedidnotthrowanassertionaftercreatingtheuser.Withoutthefailcall,themethodwouldhavepassedifanexceptionhadnotbeenthrown,eventhoughthemethodhadactuallyfailed.Beverycarefulwhenworkingwithexceptionsasyouneedtomakesurethatyoudon’thave‘falsepositives’i.e.an@Testmethodpassing,whenitshouldhavefailed.
DifferencebetweenException,ErrorandThrowableJavahasanExceptionhierarchy:
Throwable
Error
Exception
RuntimeException
TherootobjectisThrowable,andbothErrorandExceptionextendthis.
ErrorisreservedforseriousJavaplatformerrors.ThegeneralguidanceprovidedtoJavaprogrammersis“nevercatchaJavaError”,whichalsomeansweshouldnevercatchaThrowable.
IfwewanttocatchagenericruntimeexceptionthenweshouldcatchRuntimeExceptionbecauseanyruntimeexceptionsweraisewillderivefromRuntimeException.
MostofourExceptionswillderivefromeitherExceptionoraclassthatalreadyextendsException.WewillrarelyderivefromThrowableandneverderivefromError
CreateyourownExceptionclassThroughoutthischapteryouhaveseenreferencetoacustomexceptioncalledInvalidPassword.
ThereisnomagicaroundthisclassanditisaverysmallpieceofcodewhichimplementsaclassthatextendsException.publicclassInvalidPasswordextendsException{
publicInvalidPassword(Stringmessage){
super(message);
}
}
CreatingyourownexceptionallowsyoutoaggregatemultipleJavaexceptionsintoasinglecontextspecificexception.
Forexample,IcouldcatchIllegalArgumentException,NullPointerException,etc.andthrowanIllegalPasswordexceptionsothatcodeusingmyabstractionlayeronlyhastohandleasmallsetofexceptions.
Exercise:CreateanInvalidPasswordexceptionTohelppeopleusetheUserdomainobject:
createtheInvalidPasswordexceptionmaketheInvalidPasswordexceptiondescribethevalidationrulesaroundpasswordi.e.“Passwordmustbe>6chars”write@Testmethodsthatcheck:
theInvalidPasswordexceptionisthrownonsetPasswordtheInvalidPasswordexceptionisthrownintheconstructortheInvalidPasswordexceptionisnotthrowninthedefaultconstructortheerrormessagethrownbytheexceptioncontainsthetext“Passwordmustbe>6chars”
SummaryInthischapteryousawhowtocreateandthrowacustomexception.Customexceptionsareusefulwhencreatingabstractionlayersbecausewedonotneedtocreatealotofreturncodes,wecanthrowtheexceptionsinstead.
Customexceptions‘help’peopleusingourclasses,toalertthemtovalidationandexceptionsthattheymightencounterusingtheclass.Wecandothisthroughdocumentation,andwecandothisthroughcustomCheckedexceptions.
Bycreatingacustomcheckedexceptionwealertpeopleastheywritethecode,tothevalidationandusagerulesofourclass.IfwecreateacustomRuntimeExceptionthenweneedtorelyondocumentationtoalerttheuser.
Thefailmethodisveryusefulwhenwritingchecksforcustomexceptionsbecauseweneedtomakesurethatchecksdonotpassbecausetheexceptionwasnotthrowninour
@Testmethod.
ReferencesandRecommendedReading
JavaExceptionsdocs.oracle.com/javase/tutorial/essential/exceptions
AlistofUncheckedExceptionsinJavalist4everything.com/list-of-unchecked-exceptions-in-java.html
ChapterFourteen-JUnitExplored
ChapterSummaryInthischapteryouwilllearnmoreaboutJUnitfeatures:
@Test-annotateamethodasaJUnitTestassertEquals-assertthattwovaluesareequal@Test(expected=...)-expectaspecificexceptionclassthrownfail-forceamethodtofail@RuleforExpectedExceptiontocheckforexceptions@BeforeClass-runonce,beforeany@Testmethodsarerun@AfterClass-runonce,afterall@Testmethodshaverun@Before-runbeforeeach@Testmethod@After-runaftereach@Testmethod@Ignore-preventan@TestmethodfromrunningMoreJUnitassertions:
assertEquals-checkexpectedandactualareequalassertFalse-checkactualisfalseassertTrue-checkactualistrueassertArrayEquals-checkexpectedandactualarraysareequalassertNotNull-checkactualisnotnullassertNotSame-checkexpectedandactualaredifferentassertNull-checkactualisnullassertSame-checkexpectedandactualarethesame
Hamcrestmatchersforliterateassertions:assertThat-literateassertionusingHamcrestMatcheris-truewhenassertThat(x,is(y))equalTo-truewhenassertThat(x,equalTo(y))not-truewhenassertThat(x,is(not(y))containsString-truewhenassertThat(x,containsString(y))endsWith-truewhenassertThat(x,endsWith(y))startsWith-truewhenassertThat(x,startsWith(y))nullValue-truewhenassertThat(x,is(nullValue()))
WiththenewJUnitfeaturesyouwilllearninthischapteryouwillgaintheabilitytorefactorandremovecodeduplication,anduseagreaterrangeofassertionmethods.
@Test
WehavealreadyseenthatinorderforamethodtoberecognizedasaJUnittest,ithastobeannotatedwith@Test.@Test
publicvoidthisTestWillNeverFail(){
}
Amethodwillfailifanassertionfails,oranexceptionisthrowninthebodyofthemethodcode.
Youdonotneedtoadd‘test’intothenameofthemethod.UsuallyIdon’t,since‘Test’issomewhereintheclassname,andthisgivesmetheabilitytomakemymethodnamesas
expressiveaspossible.
CheckingforExceptionsBecauseamethodwillfailifanexceptionisthrown.JUnitgivesustheabilitytocheckforexceptions,andmakean@Testmethodpass,onlywhentheexceptionisthrown.@Test(expected=...)
IfIwanttocheckthataparticularexceptionisthrownthenIcandeclareitintheexpectedparameter.@Test(expected=InvalidPassword.class)
publicvoidexpectInvalidPasswordException()throwsInvalidPassword{
Useruser=newUser("username","<6");
}
Notethatyour@Testmethodwillpassifanexceptionmatchingtheexpectedclassisthrownanywhereduringtheexecution.
WecanusetheExpectedExceptionruletobemorespecificabouttheexceptionswecountasapass.
ExpectedExceptionrule
JUnithastheconceptof‘rules’toextendandenhanceJUnit.Wewon’tcovermanyoftherulesavailableinthisbook.
TheExpectedExceptionruleallowsyoutobemorespecificabouttheexceptionandonlycountaparticularexceptionasapasswhen:
aparticularclassofexceptionisthrownanexceptionhasaparticularmessageanexceptionhasaparticularcauseanycombinationoftheabove
Thefollowingcodewouldhavethesameeffectasaboveannotatingwiththeparameterexpected:@Rule
publicExpectedExceptionexpected=ExpectedException.none();
@Test
publicvoidinvalidPasswordThrown()
throwsInvalidPassword{
expected.expect(InvalidPassword.class);
Useruser=newUser("username","<6");
}
YoucanseethatIaddan@Ruleasafieldintheclass,instantiatedwiththestaticnonemethodonExpectedException.@Rule
publicExpectedExceptionexpected=ExpectedException.none();
Inthe@TestmethoditselfIconfiguretheruletoexpectanInvalidPassword.class,bycallingtheexpectmethodontheExpectedExceptionobject.expected.expect(InvalidPassword.class);
Icanmakethecheckmorespecificbyspecifyingasubstringoftheexpectedmessage.Bydoingthis,mymethodwon’tpassifanInvalidPasswordexceptionisthrown,butwithadifferentmessage.expected.expect(InvalidPassword.class);
expected.expectMessage(">6chars");
Useruser=newUser("username","<6");
Thesubstring,canalsobeaHamcrestmatcher:expected.expectMessage(containsString(">6chars"));
Before&AfterJUnitprovidesannotationsforexecutingcodebeforeandafteranytestsarerun,andbeforeandaftereachtest.Thisallowsforsetupandcleanupofdataorenvironmentconditions.
@BeforeClass-runonce,beforeany@Testmethods@AfterClass-runonce,afterall@Testmethods@Before-runbeforeeach@Testmethod@After-runaftereach@Testmethod
Anymethodannotatedwith@BeforeClassor@AfterClasshastobedeclaredasastaticmethod:@BeforeClass
publicstaticvoidrunOncePerClassBeforeAnyTests(){
System.out.println("@BeforeClassmethod");
}
Methodsannotatedwith@Beforeand@Afterdonotneedtobestatic:@Before
publicvoidrunBeforeEveryTestMethod(){
System.out.println("@Beforeeachmethod");
}
Allmethodsneedtobepublic.
@Afterand@AfterClassarerun,regardlessofwhethertheprecedingmethodpassedorfailed.
@Ignore
Wecanannotatemethodswith@Ignoreandthe@Testannotatedmethodwillnotberun.@Ignore
@Test
publicvoidthisTestIsIgnored(){
No@Beforeor@Aftermethodwillbecalledfor@Ignoreannotatedmethods.
Wecanalsoaddatextparametertothe@Ignoretoprovideareasonforitsignoredstate.@Ignore("Becauseitisnotfinishedyet")
Whenyou@Ignoreamethod,Irecommendyouaddatextparametertodescribewhy,otherwisepeoplewillforget,andthemethodislikelytobedeleted.
JUnitAssertionsJUnithasitsownassertionsbuiltin:importstaticorg.junit.Assert.*;
JUnitassertionsmostlytaketheformofamethodname,withaparameterfortheexpectedresultandthenaparameterfortheactualresult,someonlytakeanactualvalueastheexpectedisinthenameoftheasserte.g.assertNull:assertEquals(6,3+3);
WithJUnitassertsyoucanalsoaddanoptionalmessagetodescribetheassertion:assertEquals("3+3=6",6,3+3);
Iftheassertionfailsthenthemessageiswrittenaspartofthemessagetomakeiteasiertoidentifytheprobleme.g.java.lang.AssertionError:3+3=6expected:<7>butwas:<6>
JUnitprovidesthefollowingassertions:
assertEquals-checkexpectedandactualareequalassertFalse-checkactualisfalseassertTrue-checkactualistrueassertArrayEquals-checkexpectedandactualarraysareequalassertNotNull-checkactualisnotnullassertNotSame-checkexpectedandactualaredifferentassertNull-checkactualisnullassertSame-checkexpectedandactualarethesame
IfIuseJUnitassertsinmyautomationcode,ImainlyuseassertEquals,assertFalseandassertTrue.
Exercise:Createan@TestmethodwhichusesalloftheassertsExperimentwiththeJUnitassertsbycreatingan@Testannotatedmethodwhichpasses,withalloftheaboveassertsinit.
JUnitalsoprovidesanassertThatassertionforusewithmatchers.
AssertingwithHamcrestMatchersandassertThatYoucanusetheassertThatmethodinconjunctionwithmatchers,e.g.fromHamcrest,tomakeyourcodemorereadable.
assertThat
assertThat(3+3,is(6));
WhenanassertThatwithoutareasonfails,thentheoutputlookslikethefollowing:java.lang.AssertionError:
Expected:is<7>
but:was<6>
assertThatcanalsobegivena‘reason’message.assertThat("3+3=6",3+3,is(6));
IfanassertThatwithareasonfails,thentheoutputlookslikethefollowing:java.lang.AssertionError:3+3=6
Expected:is<7>
but:was<6>
SinceassertThatissoreadableinthecode,Itendnottoaddareason,andjustusethestacktracetofindthelinewiththeerrorinit.Youcanchooseyourownstyle.
HamcrestCoreMatchers
JUnithasadependencyonHamcrestcore,sowhenyouaddJUnitasadependencyintoyourprojectyoualsogetaccesstoHamcrestcore.
Hamcrestcoreprovidesasetof‘matchers’whichhelpuswriteliterateasserts,sothatourcodebecomesmorereadable.
Hamcrestcoreprovidesmatcherssuchas:
is-truewhenassertThat(x,is(y))equalTo-truewhenassertThat(x,equalTo(y))not-truewhenassertThat(x,is(not(y)))containsString-truewhenassertThat(x,containsString(y))endsWith-truewhenassertThat(x,endsWith(y))startsWith-truewhenassertThat(x,startsWith(y))nullValue-truewhenassertThat(x,is(nullValue()))
Thematcherscanbechainedtomakeliteratestatementse.g.assertThat("",is(not(nullValue())));
Exercise:ReplicatealltheJUnitAssertsusingassertThatCopythe@Testmethodyouwroteforalltheasserts.ThenrewritealltheassertstobeassertThatwithHamcrestMatchers.e.g.assertEquals(x,y)becomesassertThat(y,is(x))
Dotheaboveforalloftheassertsbelow:
assertEquals-checkexpectedandactualareequalassertFalse-checkactualisfalseassertTrue-checkactualistrueassertArrayEquals-checkexpectedandactualarraysareequalassertNotNull-checkactualisnotnullassertNotSame-checkexpectedandactualaredifferentassertNull-checkactualisnullassertSame-checkexpectedandactualarethesame
Exercise:UsealloftheHamcrestmatcherslistedCreatean@TestmethodwhichusesalloftheHamcrestmatcherslisted,tryandusethemincombinationwhereyoucantomaketheassertionsliterate.
is-truewhenassertThat(x,is(y))equalTo-truewhenassertThat(x,equalTo(y))not-truewhenassertThat(x,is(not(y)))containsString-truewhenassertThat(x,containsString(y))endsWith-truewhenassertThat(x,endsWith(y))startsWith-truewhenassertThat(x,startsWith(y))nullValue-truewhenassertThat(x,is(nullValue()))
HamcrestprovidesmorematcherswhichyoucanaccessifyouincludethefullHamcrestasadependencyinyourpom.xmlfile.e.g.<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<version>1.3</version>
</dependency>
ForinformationonthefullsetofHamcrestmatchersseetheHamcrestTutoriallinkinthereferencesforthischapter.
fail
JUnitprovidesafailmethodwhichcanbeusedtodeliberatelycauseamethodtofail.
Thiscanbecalledwithoutadescription:fail();
Orwithadescriptionparameter:fail("failalwaysfails");
Whenafailisissued,thenanAssertionErroristhrown.
staticimportingThemainwayyouhaveseenJUnitassertionsusedsofarisbystaticallyimportingthemethodfromJUnit:importstaticorg.junit.Assert.assertEquals;
Sothatinthemain@Testmethodcodewecanwritetheassertiondirectly:@Test
publicvoidcanAddTwoPlusTwo(){
intanswer=2+2;
assertEquals("2+2=4",4,answer);
}
AnotherstyleofwritingJUnitassertionsthatyoumightsee,orchoosetoadopt,Assert.assertEquals("2+2=4",4,answer);
IntheaboveusageIhaveimportedtheAssertclassratherthanasinglemethod.importorg.junit.Assert;
Inthecontextofthe@Testmethoditwouldlookasfollows:@Test
publicvoidcanAddTwoPlusTwo(){
intanswer=2+2;
Assert.assertEquals("2+2=4",4,answer);
}
Yourpreferencemayvary.
IthinkthefirstapproachwithouttheAssert.prefixisoftenmorereadable.ButusingtheAssert.prefixoftenaidsmewhencodingbecauseIcanseethefullrangeofassertionsavailabletomewhenIuseIDEcodecompletion.
SummaryJUnitoffersmultipleassertionmethods.Trytousetherangeavailabletomakeyourassertionsexpressive,althoughitisoftenpossibletowriteallyourassertionsasassertTrueandassertFalse.Butthismeanspeoplereadingyourcodehavetoparsetheentireassertioncondition,ratherthanusetheassertmethoditselftohelpthemunderstandyourintent.
WecanstickwiththoseassertionsofferedbydefaultJUnit,orwecanchoosetousethoseprovidedbytheHamcrestimportsviatheassertThatassertion.
Hamcrestoffersmorematchersthanthoselistedinthischapter,soonceyouarefamiliarwiththeuseofassertThatinyourcode,readthroughtheHamcrestwebsiteandexperimentwiththeadditionalfeaturesinHamcrest.
Ideallywewouldwritecodewhichdoesmorethansimplyassert.Itshouldalsomaketheintentbehindthoseassertionseasytoreadandunderstandfromthecode.Andwecandothisbyusingacombinationofassertionandmatchermethods.
YouwillgainalotofvaluefromexperimentingwiththeBeforeandAfterannotationstohelpyoustructureyourcodeandmovesetupandteardowncodetothecorrectlevel:
classlevel(@BeforeClassand@AfterClass),ormethodlevel(@Beforeand@After).
ReferencesandRecommendedReading
JUnithomepagejunit.org
JUnitExceptionCheckinggithub.com/junit-team/junit/wiki/Exception-testing
JUnitAssertionsgithub.com/junit-team/junit/wiki/Assertions
JavaHamcresthomepageithub.com/hamcrest/JavaHamcrest
HamcrestTutorialcode.google.com/p/hamcrest/wiki/Tutorial
ChapterFifteen-StringsRevisited
ChapterSummaryInthischapteryouwillrevisitwhatyoualreadyknow,andlearnmoreaboutstrings:
Stringisanobjectwithmanyusefulmethod,notjustacontainerforcharactersSystem.out.println-printaStringtoconsoleSpecialcharactersencodedinstringusing\e.g.\t,\b,\n,\',\",\\Stringconcatenationusing+andtheconcatmethodConverttoaStringwiththetoStringmethodofmostobjectsConvertfromaStringtootherobjectsusingthevalueOfmethodConstructStringfromchar[],byte[],StringBuffer,StringBuilderandStringStringobjecthasmanycomparisonmethods:
.compareTo-returns0ifStringsareequal
.compareToIgnoreCase-sameascompareTo,butignoringcase
.contains-returnstrueifparameterisinString
.contentEquals-returnstrueifStringcontentequalstoparameter
.equals-returnstrueifcontentisequalandtheparameterisaString
.equalsIgnoreCase-sameasequalsbutignoringcase
.endsWith-returnstrueifendofStringequalsparameter
.startsWith-returnstrueifstartofStringequalsparameter
.isEmpty-returnstrueiflengthofStringis0
.indexOf-returnstheindexpositionofasubstring
.lastIndexOf-returnsthelastindexpositionofasubstring
.regionMatches-comparearegionofthesubstringtoaregionoftheString.matches-easytouseregularexpressionStringmatchingReplacesectionsofaStringwith.replace,.replaceAll,.replaceFirstCaseconversionusing.toUppercaseand.toLowercase.trim-toremovewhitespacefromString.substring-toreturnaportionofaString.format-tousesimplestringtemplates.split-toparseastringStringBuilder-buildstrings:append,delete,insert,replace,reverse
YouhavealreadyseentheuseofStringobjectsthroughoutthebook.
ThischapterwillpullallthatinformationtogetherintoasinglechapterbecausetheStringisanessentialobjecttousewhenbuildingour@Testmethodsandabstractionlayers.
Alotoffieldsonourobjectswillstartasstringse.g.username,password.Atsomepointwemightchoosetomakethemobjectsintheirownrightbecausethenwecanmakethemresponsiblefortheirownvalidation.
StringSummaryJustaquicksummaryofwhatwehavealreadylearned.
AStringisanobject,injava.langsowedon’thavetoworryaboutimportingit.StringaString="abcdef";
AStringliteralisalsoanobject,sowecancallmethodsonaStringliteral.assertThat("hello".length(),is(5));
Wecanconcatenatestringswiththe+operator.assertEquals("123456","12"+"34"+"56");
AStringisimmutable.OnceaStringiscreated,wecan’tamendit,itmightlooklikeweareamendingit,butreallywearecreatinganewStringobject.
ThismeansthatJavacanre-usethesameStringvaluethroughoutourcode,soevenifwetypeaStringinmultipleplaces,itdoesn’ttakeupanymorememory.Ofcourse,weshouldnotusethisasanexcusetoduplicateStringliteralsthroughoutourcodeasthatcanmakeourcodehardertomaintain.
System.out.println
YouhaveseenSystem.out.printlnusedinearliercode,thisstatementallowsustowriteStringobjectstotheconsole.
Itisveryusefulwhentryingtogaininsightintoasectionofcodeandtogenerateadhocfilesorstringstopasteintoapplications.
Itcanbeusedasasimpleloggingtoole.g.forprintingoutprogressofexecutiontotheconsole,orprintingthevariablesusedasinputdata.
Thefollowingexampleshowsthisinaction:inti=4;
System.out.println("Printaninttotheconsole"+i);
Notethatintheexampleabove,theintisautomaticallyconvertedintoaStringandconcatenatedtothestringliteralwhenoutputas:Printaninttotheconsole4
SpecialcharacterencodingWeencounteredtheescapesequencesinanearlierchapter.
\t-atabcharacter\b-backspace\n-anewline\r-acarriagereturn\'-asinglequote\"-adoublequote\\-abackslash
Whenbuildingstringswehavetomakesureweescapethecharacterslike",and\otherwiseourstringswillfailtobuild.System.out.println("Bobsaid\"hello\"tohiscat'sfriend");
System.out.println("Thisisasinglebackslash\\");
Willoutput:
Bobsaid"hello"tohiscat'sfriend
Thisisasinglebackslash\
Exercise:TryusingtheotherescapecharactersExperimentwithsome@Testmethodswhichusetheotherescapecharactersinastringe.g."\t","\b","\n","\r"andseetheeffectwhenyouuseSystem.out.printlntoprinttotheconsoleoutput.
StringConcatenationWehavealreadyseen+asamethodofconcatenatingstrings.The+isalsousefulasawayofaddingprimitivesandotherobjectsontotheString.Stringps1="Thisis"+"String2";
assertThat(ps1,is("ThisisString2"));
Stringps2="Thisis"+4;
assertThat(ps2,is("Thisis4"));
TheStringclasshasaconcatmethodwhichallowsustoconcatenateotherstrings.ThisdoesnotallowustoconcatenateotherobjectsontotheString.StringthisIs="Thisis";
Strings1=thisIs.concat("String1");
assertThat(s1,is("ThisisString1"));
Convertingto/fromaString
ConvertingtoaStringwithtoStringMostclassesoverridethetoStringmethodtoprovideawayofcreatingaStringrepresentationoftheobject.
ThisprovidesausefulwayofconvertingtoaString,andthisisthemethodcalledwhenyouconcatenateaStringwithadifferenttypeusing+.
Forprimitivetypes,theassociatedobjectversionisusede.g.forinttheInteger.toStringisused.StringintConcatConvert=""+1;
assertThat(intConcatConvert,is("1"));
StringintegerIntConvert=Integer.toString(2);
assertThat(integerIntConvert,is("2"));
TheStringclassitselfhasthevalueOfmethodwhichtakesobjectsandprimitivesandconvertsthemtoaString.Forobjects,theobject’stoStringmethodisusedfortheconversion.StringintegerStringConvert=String.valueOf(3);
assertThat(integerStringConvert,is("3"));
Inadditionyoucanconvertfrombyte[]andchar[](andotherobjects)toaStringusingtheStringconstructor.
ConvertingfromaString
ManyobjectshaveavalueOfmethodwhichcanconvertthevalueoftheStringtotheassociatedobject.e.g.Integer,Float,etc.assertThat(Integer.valueOf("2"),is(2));
TheStringobjectalsohasatoCharArraytoconverttoaCharacterarray.char[]cArray={'2','3'};
assertThat("23".toCharArray(),is(cArray));
WecanconvertaStringtoabytearrayusingthegetBytesmethod.byte[]bArray="hellothere".getBytes();
Convertingtobytesfromstringscanbeproblematicifwewanttomoveourcodebetweendifferentmachinesastheymayhaveadifferentdefaultcharactersetorcharacterencoding.
WhenweconvertbetweenbyteandStringwemayneedtocontroltheencoding.IfweuseanincorrectencodingthenanUnsupportedEncodingExceptionwillbethrown:@Test
publicvoidcanConvertBytesUTF8()throwsUnsupportedEncodingException{
byte[]b8Array="hellothere".getBytes("UTF8");
}
ConstructorsWecanconstructanewStringwithnoargumentstocreatea0lengthString.Stringempty=newString();
assertThat(empty.length(),is(0));
Orwithargumentstoconstructfrom:
String
char[]-anarrayofcharbyte[]-anarrayofbyteStringBuffer-amutableStringStringBuilder-amutableString
e.g.char[]cArray={'2','3'};
assertThat(newString(cArray),is("23"));
Exercise:ConstructaStringConstructaStringfromaString,char[],andbyte[].
Experimentwiththedifferentcombinationsofparameters.
ComparingStringsStringprovidesmanymethodsforcomparisonandsearching:
.compareTo-returns0ifStringsareequal
.compareToIgnoreCase-sameascompareTo,butignoringcase
.contains-returnstrueifparameterisinString
.contentEquals-returnstrueifStringcontentisequaltoparameter
.equals-returnstrueifcontentisequalandtheparameterisaString
.equalsIgnoreCase-sameasequalsbutignoringcase
.endsWith-returnstrueifendofStringequalsparameter
.startsWith-returnstrueifstartofStringequalsparameter
.isEmpty-returnstrueiflengthofStringis0
.indexOf-returnstheindexpositionofasubstringinaString
.lastIndexOf-returnstheindexpositionofasubstringsearchingfromtheendoftheStringforwards.regionMatches-comparearegionofthesubstringtoaregionoftheString
compareTo&compareToIgnoreCasecompareTocomparestheStringyoucallthemethodon,withaStringparameter:
IfthetwoStringsareequalthencompareToreturns0Stringhello="Hello";
assertThat(hello.compareTo("Hello"),is(0));
IftheargumentStringissmallerthantheStringthencompareToreturnsanegativenumberassertThat(hello.compareTo("hello")<0,is(true));
assertThat(hello.compareTo("Helloo")<0,is(true));
assertThat(hello.compareTo("Hemlo")<0,is(true));
IftheargumentStringislargerthantheStringthencompareToreturnsapositivenumberassertThat(hello.compareTo("H")>0,is(true));
assertThat(hello.compareTo("Helln")>0,is(true));
assertThat(hello.compareTo("HeLlo")>0,is(true));
Notethatlargermeansbothlongerlengthor,acharacterdifference.Similarlysmallermeanssmallerlength,oracharacterdifference.
compareToIgnoreCaseusesthesamelogicascompareTobutthecaseofthelettersisignorede.gassertThat(hello.compareToIgnoreCase("hello"),is(0));
assertThat(hello.compareToIgnoreCase("Hello"),is(0));
assertThat(hello.compareToIgnoreCase("HeLlo"),is(0));
contains
ThemethodcontainsreturnstrueiftheparameterStringiscontainedwithintheString.ThevaluetruewillalsobereturnediftheparameterStringequalstheString.Stringhello="Hello";
assertThat(hello.contains("He"),is(true));
assertThat(hello.contains("Hello"),is(true));
Caseisimportantwhenusingcontains:assertThat(hello.contains("he"),is(false));
ThevaluefalseisreturnediftheparameterisnotcontainedwithintheStringassertThat(hello.contains("z"),is(false));
contentEquals&equals&equalsIgnoreCaseThemethodcontentEqualsreturnstrueiftheStringhasthesamecontentastheparameterandfalseifitdoesnot.Stringhello="Hello";
assertThat(hello.contentEquals("Hello"),is(true));
assertThat(hello.contentEquals("hello"),is(false));
ThecontentEqualsmethodwillworkwithanyobjectthatimplementstheCharSequenceinterface,oragainstaStringBuffer(e.g.aStringBuilder).
TheequalsmethodenforcestheadditionalrulethattheparametermustbeaString,aswellashavingequalcontent.
TheequalsIgnoreCasemethodworksthesameasequalsbutignoresthecaseinthecomparison.assertThat(hello.equalsIgnoreCase("hello"),is(true));
endsWith&startsWithTheendsWithmethodcomparestheendoftheStringtotheparameter.Stringhello="Hello";
assertThat(hello.endsWith("Hello"),is(true));
assertThat(hello.endsWith(""),is(true));
assertThat(hello.endsWith("lo"),is(true));
ThestartsWithmethodcomparesthestartofStringtotheparameter.assertThat(hello.startsWith("Hello"),is(true));
assertThat(hello.endsWith(""),is(true));
assertThat(hello.startsWith("He"),is(true));
BothendsWithandstartsWithmethodsimplementcasesensitivesearches.assertThat(hello.startsWith("he"),is(false));
assertThat(hello.startsWith("Lo"),is(false));
isEmpty
TheisEmptymethodreturnstrueifthelengthoftheStringis0,andfalseifthelengthis>0.Stringempty="";
assertThat(empty.isEmpty(),is(true));
assertThat(empty.length(),is(0));
regionMatches
TheregionMatchesmethodallowsyoutouseindexestospecifyaregionintheString,withinwhichtolookforaregioninthecomparisonotherString.regionMatches(booleanignoreCase,inttoffset,
Stringother,intooffset,intlen)
Or:regionMatches(inttoffset,
Stringother,intooffset,intlen)
GivenaparticularString:"Hellofella"
01234567890
IcansearchforasubstringintheaboveStringe.g.Stringhello="Hellofella";
assertThat(
hello.regionMatches(true,6,"fez",0,2),
is(true));
IntheaboveexampleIamspecifying:
theregionofthehelloStringtosearchasstartingatposition6,untiltheendofthestringthesubstringis"fez",and
Iwanttheregionofthis"fez"Stringtostartatposition0,andonlybe2characterslong
IneffectIamlookingfor"fe"inthehelloStringstartingatposition6.
Thisisaparticularlycomplicatedmethodtouse,andIhaverarelyusedit.ItendtousecontainsorindexOfinstead.
Exercise:UseregionMatchesWritean@TestmethodwhichusesregionMatchestosearchintheString"Hellofella".Andmatcharegionofthesubstring"younglady".e.g.searchforthe"la"portionof"younglady"in"Hellofella"
indexOf&lastIndexOfForthefollowingexamplesIamusingtheString:"Hellofella"
01234567890
Declared,inthecode,asfollows:Stringhello="Hellofella";
BoththeindexOfandlastIndexOfmethodsreturnthepositionintheStringwheretheCharacterparameterorStringparametercanbefound.
TheindexOfmethodreturnsthefirstplaceintheStringwheretheparametercanbefound.assertThat(hello.indexOf("l"),is(2));
ThelastIndexOfmethodreturnsthelastplaceintheStringwheretheparametercanbefound.ThesearchfortheindexbeginsfromtheendoftheString,workingtowardsthestartoftheString.
assertThat(hello.lastIndexOf("l"),is(9));
BothindexOfandlastIndexOfcanbecalledwithanadditionalparametertospecifythestartpositionintheStringtosearchfrom.
InthecaseofindexOfitsearchesfromthegivenposition,totheendoftheString.assertThat(hello.indexOf('l',3),is(3));
assertThat(hello.indexOf("l",4),is(8));
ThelastIndexOfmethodsearchesfromthegivenpositiontowardsthestartoftheString.assertThat(hello.lastIndexOf('l',8),is(8));
assertThat(hello.lastIndexOf("l",7),is(3));
IfindexOforlastIndexOfcannotfindanoccurrenceoftheCharacterorsubstringinStringthenthemethodreturns-1(negativeone).assertThat(hello.indexOf('z'),is(-1));
assertThat(hello.lastIndexOf("z"),is(-1));
Exercise:FindpositionsofalloccurrencesinaStringWriteamethod,whichtakesaStringandasubstringasparametersandreturnsaList<Integer>whereeachIntegeristhelocationofthesubstringintheString.
e.g.findAllOccurrences("Hellofella","l")wouldreturnaList<Integer>withthevalues2,3,8,9
Forbonuspoints,writeafindAllOccurrencesmethodwhichreturnsthelistinthereverseorderi.e.9,8,3,2
ComparingWithRegularExpressionsRegularExpressionsareanincrediblypowerfultoolforworkingwithstrings.
Javahasawholepackagededicatedtoregularexpressions,‘java.util.regex’,butadetailedlookatRegularExpressionhandlingisbeyondthescopeofthisbook.Ihavelistedthemainon-linereferencesIuseintheReferencessectionofthischapter.
InthisbookIwanttointroduceyoutoregularexpressionswiththe.matchesmethod.
AregularexpressionisaStringwheresomeoftheCharactershavespecialmeaning,e.g.wildcards,orgroupingconstructs.Thephrase“RegularExpression”isoftenabbreviatedto“Regex”.
Thematchesmethodhelpsustodothesimplestregularexpressiontask,whichisanswerthequestion“doesthisRegularExpressionmatchthisString?”
AnexamplescenariofortheuseofRegularExpressionsmightbethatwewanttoexpandthepasswordvalidationonourUserclass:
passwordmustcontainadigitpasswordmustcontainanuppercaseletter
WecouldimplementtheaboveconditionsusingtheindexOfoperatorandloopoverdigitsoruppercaselettersandtryandfindthemintheString.Butthatwouldbethehardway,itwouldrequireacomplicatedloopandcouldleadtobuggycode.
Or,wecouldbuildaregularexpressionthatonlymatchesifeachofthoseconditionsiscorrect.
Forexample,IcanwritearegularexpressionofmatchingaStringandcheckthatitincludesadigit".*[0123456789]+.*".
Atahighleveltheaboveregularexpressionmeans:
.*-match0ormorecharacters[0123456789]+-untilwefind1ormoreofthefollowingcharacters“0123456789”.*-whichcanbefollowedby0ormorecharacters
Todetailitfurther:
.-matchesanysinglecharacter*-meansmatch0ormoreoftheprecedingelement[]-matchesanysinglecharactercontainedinthebrackets+-meansmatch1ormoreoftheprecedingelement
IcanuseitinmyJavacodeasfollows:StringmustIncludeADigit=".*[0123456789]+.*";
IassignedtheregularexpressionintoaStringvariableforre-use.
IcallthematchesmethodonaStringandpassintheregularexpressionasaparameter,andiftheregularexpressionmatchestheStringthenmatchesreturnstrue.assertThat("12345678".matches(mustIncludeADigit),is(true));
assertThat("1nvalid".matches(mustIncludeADigit),is(true));
Ifthematchfailsthenfalseisreturned.assertThat("invalid".matches(mustIncludeADigit),is(false));
assertThat("Invalid".matches(mustIncludeADigit),is(false));
Icanwriteasimilarregularexpressiontomatchuppercaseletters:StringmustIncludeUppercase=".*[A-Z]+.*";
Iusedoneadditionalconstructintheaboveregularexpression:
A-Zin[A-Z]-meansanycharacterbetweenA-Z,soIcoulddoa-zor0-9
assertThat("Valid".matches(mustIncludeUppercase),is(true));
assertThat("val1D".matches(mustIncludeUppercase),is(true));
Exercise:RegularExpressionsforUsersetPasswordAddtheregularexpressioncheckstothesetPasswordmethodonUsersothatanIllegalPasswordexceptionisthrownifthepassworddoesnotcontainadigit,ordoesnotcontainanuppercaseletter.
WorkingwithRegex
WhenyouarenewtoRegularExpressionstheycanseemdaunting.
EverytimeIreturntothem,theyseemdaunting,becauseI’veforgottenalotofthenuancesandhowtowritethem.
SoIwanttoletyouinonmysecretsonhowIgetbackuptospeed.
1. Iuseregular-expressions.infotohelpmerememberthesyntax2. Iuseon-linetoolslikeregexpal.comtoconstructandchecktheregularexpression
againstsampletext3. IusedesktoptoolslikeRegexBuddy(regexbuddy.com)tohelpmeconstructand
checktheregularexpression.RegexBuddyalsobuildscodesnippetstouse.4. IwriteJUnitteststocheckmyregularexpressionworks5. IwriteJUnittestsaroundthecodeusingtheregularexpressione.g.totestthe
setPasswordmethod
Regularexpressionsareatremendoustoolwhenyougetusedtothem.AsyougrowmoreexperiencedwithJavaandstartusingthejava.util.regexpackageyoucanuseregularexpressionstoparsestringsandpulloutsubstringsusingregularexpressions.
Butforthemoment,startwiththe.matchesmethodandgetusedtowritingregularexpressionsforvalidation.
ManipulatingStrings
ReplacingStringsJavaprovidesthreemethodsonStringtohelpusgenerateanewStringbutwithelementsoftheStringreplacedwithothercharacters.
.replace-replaceallmatchingsubstringswithanewsubstring
.replaceAll-replaceallsubstringsthatmatcharegularexpressionwithanewsubstring.replaceFirst-replacethefirstsubstringmatchingtheregularexpressionwithanewsubstring
Stringhello="Hellofellafellafella";
assertThat(hello.replace("fella","World"),
is("HelloWorldWorldWorld"));
YoumightwonderwhythereisnoreplaceFirstfornormalStrings,ratherthanjustusingregularexpressions.Andthereasonisthata‘normal’string,isaregularexpression,butonewhichonlymatchesthatString.
ThisallowsmetousereplaceFirsttoreplacethefirstoccurrenceoffellawithWorld:assertThat(hello.replaceFirst("fella","World"),
is("HelloWorldfellafella"));
And,whentheregularexpressionisastringliteralwithnoregularexpressionspecialcharacters,IcanusereplaceAllinsteadofreplaceassertThat(hello.replaceAll("fella","World"),
is("HelloWorldWorldWorld"));
replaceFirstandreplaceAllofferusaverysimplewayofaccessingadditionalpowerofregularexpressions.
e.g.toreplacenumbers,withtheString"digit":assertThat("1,2,3".replaceFirst("[0-9]","digit"),
is("digit,2,3"));
assertThat("1,2,3".replaceAll("[0-9]","digit"),
is("digit,digit,digit"));
UppercaseandLowercaseJavaprovidesveryselfexplanatorymethodsforconvertinganentireStringtouppercaseorlowercase
.toUppercase-converttheStringtouppercase
.toLowercase-converttheStringtolowercase
Stringtext="Inthelower3rd";
assertThat(text.toUpperCase(),
is("INTHELOWER3RD"));
assertThat(text.toLowerCase(),
is("inthelower3rd"));
RemovingWhitespaceTheStringtrimmethod,removesleadingandtrailingwhitespacefromaString.Stringpadded="trimme";
assertThat(padded.length(),is(15));
Stringtrimmed=padded.trim();
assertThat(trimmed.length(),is(7));
assertThat(trimmed,is("trimme"));
Thisisaveryhandymethodtousewhentidyingupinputdata,ordatareadfromfiles.
SubstringsStringhastwoformsofsubstring:
substring(intbeginIndex)-fromanindextotheendoftheStringsubstring(intbeginIndex,intendIndex)betweenastartindexandanendindex
GivenaStringofdigits:
Stringdigits="0123456789";
Wecangetfrom(andincluding)the5thdigit,totheendoftheString:assertThat(digits.substring(5),is("56789"));
TheendIndexisnotincludedinthesubstring,so(5,6)means“from5thto(butnotincluding),the6th”:assertThat(digits.substring(5,6),is("5"));
String.format
InsteadofconcatenatingstringsallthetimewecanusethestaticformatmethodonStringtoconstructstrings.
Theformatmethodallowsustocreatesimplestringtemplates,whichwepassargumentsinto.
e.g.insteadofhavingtoconcatenateStringandothervariablestogether:intvalue=4;
Stringoutput="Thevalue"+value+"wasused";
assertThat(output,is("Thevalue4wasused"));
WecoulduseString.formatandaformatstring:Stringtemplate="Thevalue%dwasused";
Stringformatted=String.format(template,value);
assertThat(formatted,is("Thevalue4wasused"));
A‘format’stringisaStringwithembeddedconversionplaceholdersfortheargumentssuppliedtoString.format.e.g.
%d-meansconverttheargumenttoadecimalinteger
Commonplaceholdersare:
%d-adecimal%s-aString
e.g.Stringuse="%s%stowards%dlarge%s";
assertThat(
String.format(use,"Bob","ran",6,"onions"),
is("Bobrantowards6largeonions"));
Theargumentsareusedinordertofilltheplaceholdersintheformatstring.
Theformatstringcanspecifyexactlywhichargumentitwantstouseineachplaceholderbyusing%<index>$e.g.%2$wouldmeanthe2ndargument:Stringtxt="%2$s%4$stowards%3$dlarge%1$s";
assertThat(
String.format(txt,"Bob","ran",6,"onions"),
is("ranonionstowards6largeBob"));
Thisallowsustore-useargumentstofillthetemplateinmultipleplaces:
Stringtxt2="%1$s%1$stowards%3$dlarge%1$s";
assertThat(
String.format(txt2,"Bob","ran",6,"onions"),
is("BobBobtowards6largeBob"));
Theformatstringoffersalotofflexibility,andwhenyoulookattheofficialdocumentationfortheStringFormattingSyntaxyouwillseethis.
docs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax
Itendtokeeptheformatstringsverysimple,andmainlyusethemasplaceholdersfor%sand%d,butitisworthbeingawareofthepossibilitiesopentoyouwiththeformatplaceholders.
BasicStringparsingwithsplitsplitallowsustoconvertaStringintoanarray,whereeacharrayelementisaportionoftheStringdelimitedbythesplitargument.
Forexample,Icould‘parse’acommaseparatedvaluestringwithStringcsv="1,2,3,4,5,6,7,8,9,10";
String[]results=csv.split(",");
Theresultsarraywouldhave10elements,whereeachelementwasoneofthenumbersseparatedby“,”intheoriginalString:assertThat(results.length,is(10));
assertThat(results[0],is("1"));
assertThat(results[9],is("10"));
Thesplit,argumentisaregularexpression,socanbeusedcreatesophisticatedsplitfunctionswithminimalcode.
IfrequentlyusesplittoparsesimpleCSV,ortabdelimitedfiles.I’vealsousedittoparseHTMLandXML,withoutbringinginotherlibraries.
ManipulatingstringsWithStringBuilderWehavelearnedthatStringisimmutable,butJavaprovidesaClassformanipulatingandcreatingstringscalledStringBuilder:StringBuilderbuilder=newStringBuilder();
AStringBuilderallowsusto:
appendvaluestotheendofthestringdeletecharacters,orsubstrings,fromthestringinsertvaluesintothestringreplacesubstringswithotherstringsreversethestring
ItdoesthisbyholdinganinternalrepresentationofthestringwhichisonlyconvertedintoaStringwhenthetoStringmethodiscalled.e.g.
builder.append("HelloThere").
replace(7,11,"World").
delete(5,7);
assertThat(builder.toString(),is("HelloWorld"));
AStringBuilderextendsStringBuffer,andisslightlyfaster,butonlyforusewithsinglethreadedapplications.IfyouadvanceyourJavatothestagewhereyouareusingmultiplethreads,thenyoumayneedtouseStringBufferinstead.
ConstructaStringBuilderWecanconstructanemptyStringBuilder:StringBuilderbuilder=newStringBuilder();
WecanconstructaStringBuilderwithastartingStringvaluefromanythingthatimplementstheCharSequenceinterfacee.g.StringStringBuildersb=newStringBuilder("hello");
CapacityManagement
SinceStringBuildermaintainsaninternalrepresentationoftheStringitallocatesaparticularcapacityinmemoryforthatinternalrepresentation.WhenitemsareappendedtotheStringBuilderthecapacityisautomaticallyincreased.
Bydefault,ifyouusetheno-argumentconstructor,thecapacityis16.StringBuilderbuilder=newStringBuilder();
assertThat(builder.capacity(),is(16));
Youcanfindoutthecurrentcapacitysizeusingthecapacitymethod.
YoucanconstructaStringBuilderwithaspecificcapacityifyouwant.StringBuildersblen=newStringBuilder(512);
assertThat(sblen.capacity(),is(512));
assertThat(sblen.toString().length(),is(0));
Forautomationcodewetypicallydon’tworryaboutthecapacity,butifyouarewritingcodethatneedstobefastthenyoumightsizetheStringBuildertoavoidtoomuchcapacityre-allocation.
YoucansizetheStringBuilderafterconstructionusingtheensureCapacitymethod:builder.ensureCapacity(600);
Ifyouhaveamendedthecapacity,ordeletedalotofthestringthenyoucansetthecapacitytotheminimumnecessarytoholdthestringcharactersbyissuing:builder.trimToSize();
AppendingtotheStringBuilderTheappendmethodworksmuchlikethe+concatenationapproachforString.WecanappendObjects,primitives,Strings,orchar[]totheendofaStringBuilder.StringBuilderbuilder=newStringBuilder();
builder.append(">");
builder.append(1);
builder.append("+");
builder.append(2);
char[]ca={'','=','','3'};
builder.append(ca);
assertThat(builder.toString(),is(">1+2=3"));
Ifduringtheappending,weaddmorecharactersthanthecurrentcapacity,thenStringBuilderwillautomaticallyresize.
Exercise:CheckStringBuilderresizesWritean@TestannotatedmethodwhichvalidatesthataStringBuilderresizeswhenyouappendmorecharactersthanthecurrentcapacity.
InsertintotheStringBuilderTheinsertmethodsupportsthesameobjectsandprimitivesastheappendmethod.
WhenweinsertintotheStringBuilderwehavetospecifythepositiontoinsertinto:StringBuilderbuilder=newStringBuilder("123890");
builder.insert(3,"4567");
assertThat(builder.toString(),is("1234567890"));
InJava,indexesstartat0,sothefirstspacewecaninsertintoinanEmptystringis0.
IfweuseanindexwhichislongerthanthecurrentinternalrepresentationoftheStringthenaStringIndexOutOfBoundsExceptionwillbethrown.
WhenaStringBuilderhassomevaluesinthestringwecaninsertat:
index0toaddittothefront,indexlengthtoappenditanythinginbetweentoadditintothebody
Exercise:InsertintoaStringBuilderInsertaStringintoanemptyStringBuilder.InsertaStringontheend.InsertaStringinthemiddle.
Whenweinsertachar[]wehaveadditionaloptions.Inadditiontotheindex,wecanspecifytheoffsetinthechararray,andthenumberofcharacterstocopyfromthechararray.
GiventhefollowingStringBuilderwhichstartswiththeString"abgh":char[]ca={'.','a','b','c','d','e','f'};
StringBuilderbuilder=newStringBuilder("abgh");
Thecodebelowwillinsertatposition2inthestring(i.e.afterthe‘b’).Thecharactersfromposition3inthechararray('c')tothenext4characterse.g.(cdef);//atposition2inthestring
//insertfromthechar[]ca
//startingatindex3'c'
//inclusivethenext4indexes
builder.insert(2,ca,3,4);
assertThat(builder.toString(),is("abcdefgh"));
DeletingfromStringBuilderWecandeletesubstrings,basedonindexesfromtheStringBuilder:StringBuilderbuilder=newStringBuilder("abcdefg");
builder.delete(2,4);
assertThat(builder.toString(),is("abefg"));
Giventhestring"abcdefg"we:
specifythestartindextodeletefrom,e.g.2,whichis“c”,andspecifythelastindextodeleteupto,e.g.4,whichwouldspan“cd”
abcdefg
0123456
OrwecandeleteaspecificcharacterataspecifiedindexusingdeleteCharAt:builder.deleteCharAt(2);
assertThat(builder.toString(),is("abdefg"));
ReplaceSubStringsandCharactersWecanreplacesubstringswiththereplacemethod,whichtakesastartindex,endindex,andaStringasparameters.
Thecharactersfromstartindex,toendindexarereplacedbytheString:StringBuilderbuilder=newStringBuilder("abcdefgh");
builder.replace(0,4,"12345678");
assertThat(builder.toString(),is("12345678efgh"));
Intheexampleabove,thestringtoreplacewasonly4characters,butthe‘gap’waslengthenedtoallowthereplacementStringtobeinserted.
WecanreplaceindividualcharactersbyusingthesetCharAtmethod:StringBuilderbuilder=newStringBuilder("012345678");
builder.setCharAt(5,'f');
assertThat(builder.toString(),is("01234f678"));
ReverseTheabilitytoreversestringscomesinsurprisinglyuseful.
HavingthismethodbuiltintoStringBuildermeansthatIoftensimplyconstructaStringBuilderwithaStringandcall.reverse().toString().StringBuilderbuilder=newStringBuilder("0123456789");
assertThat(builder.reverse().toString(),is("9876543210"));
SubStringsThesubstringmethodreturnsaStringfromastartindextoanendindex:
StringBuilderbuilder=newStringBuilder("0123456789");
assertThat(builder.substring(3,7),is("3456"));
Orfromastartindextotheendofthestring:assertThat(builder.substring(3),is("3456789"));
StringBuilderSummaryStringBuilderisaverypowerfulclassthatpreventsneedingtousealotofStringsandconstantlyconcatenatingthemtogether.TheuseofStringBuilderisalsoveryefficientsinceitusesaninternalrepresentationratherthanconstructingnewStringobjectsoneachmethodcall.
Forefficiencywecouldmaintainthecapacityourself,andsizetheStringBuilderappropriatelyforthetaskathand,ratherthanhavetheStringBuilderresizeontheflywitheachmethod.
StringBuilderhasothermethodsthatwehaven’tcoveredhere,thishasbeenanoverviewofthemainStringBuilderfunctionalitythatyouwillusemostoften.
IfindthatIuseStringBuildermostforStringconstruction,somainlytheappendandinsertmethods.Irarelyusethereplace,andsubstringmethods,preferringtoreplaceandworkwithsubstringsdirectlywiththeStringclass.
Youwilldevelopyourownstyle,andworkwiththeclassesthatmakemostlogicalsensetoyou.
Forfulldocumentation,ofallthemethods,seethelinkintheReferencesorusecodecompletioninyourIDE.RememberinIntelliJpressingctrl+q(onWindows)orctrl+j(onMac)inthecodecompletionpop-upshowstheJavaDocdocumentationforthemethod.
Concatenation,.format,orStringBuilderHowdoyouchoosetherightwaytobuildStrings?
Wehaveseenmanydifferentwaystoconstructstrings:
simpleconcatenationeitherwith+orconcatsimpletemplatesusingString.formatStringBuilderflexibilitywithinserts,appendsanddeletes
Sowhichisbest?
Well,Iusethemall.
ForsimplestringbuildingIuseconcatenation.
IuseformatswhenIhavetoomanyconcatenationsandthecodebecomeshardtoreadandmaintain,orwhenIwanttoreusetheformatstringinmultipleplaces.ItrytoremembertouseString.formatmore,evenwhenIhaveasmallsetofconcatenations,butsometimesIgetlazyandconcatenateStringstogether.
ItendtouseStringBuilderifI’mbuildingaStringoveralongperiodoftime,orneedtobuildtheStringoveranumberofmethodcalls.
Idon’tthinkthereisarightanswer.Butdobeawarethatyouhaveoptions.
Trytomakeyourcodeasreadableandmaintainableaspossible.Sochoosethemethodthathelpsyoubuildcodethatlasts.
SummaryWhenautomatingIworkwithstringsallthetime:representingdata,parsingfiles,processingJSON,creatingHTTPrequests,etc.
SoIusealotofbasicStringprocessingmethodsandStringBuildergenerationmethods.
Thischapterhascoveredalotofthebasics,eventhoughwehaven’tgoneintodepthinmanyoftheareas.Referbacktothischapterwhenworkingwithautomationanddataandyou’llfindmanyofthebasicfunctionsthatyouareusing,orcoulduse,listedhere.
I’vetriedtocoverthemethodsandclassesbehindthebulkofmystringprocessingneeds,hopefullythatwillmatchyourinitialfutureneeds.
ReferencesandRecommendedReading
JavaEscapeSequencesdocs.oracle.com/javase/tutorial/java/data/characters.html
JavaStringstutorialdocs.oracle.com/javase/tutorial/java/data/strings.html
JavaByteEncodingandStringsdocs.oracle.com/javase/tutorial/i18n/text/string.html
StringFormattingsyntaxdocs.oracle.com/javase/7/docs/api/java/util/Formatter.html#syntax
StringBuilderTutorialdocs.oracle.com/javase/tutorial/java/data/buffers.html
StringBuilderDocumentationdocs.oracle.com/javase/7/docs/api/java/lang/StringBuilder.html
JavaRegularExpressionsdocs.oracle.com/javase/tutorial/essential/regex
RegularExpressionsInformationandTutorialsregular-expressions.info/
WikipediaRegularExpressionsen.wikipedia.org/wiki/Regular_expression
On-lineRegularexpressiontesterregexpal.com
RegexBuddyDesktopToolregexbuddy.com
ChapterSixteen-RandomData
ChapterSummaryInthischapteryouwilllearnhowtouseJava’sRandomfunctionalitytocreateRandomData:
Math.random-easytousestaticwrappertogeneratearandomdoublebetween0.0and1.0java.util.random-themainJavarandompackage:
nextBoolean-returneithertrueorfalsenextLong-returnarandomlongvaluenextInt-randomintovertherangeofallIntegervaluesnextInt(intbelow)-randomintgreaterthanorequalto0andlessthanbelownextDouble-flatdistributionwhereeachvaluebetween0.0and1.0hasequalchanceofbeingreturnednextGaussian-aGaussiandistributionwithameanof0.0andastandarddeviationof1.0,meaningabout70%valueshoveringaroundthe0.0mark(+or-1.0)nextFloat-randomfloatgreaterthanorequalto0.0andlessthan1.0nextBytes-fillagivenbyte[]withrandombytes
seedingrandomnumbergenerationwithnewRandom(seed)Generatingrandomstrings
Randomdatainautomationisacontentioussubject.Somepeoplearguethatautomationshouldbecompletelydeterministicandalwaysrunthesameway-implyingthatwealwaysusethesamedata.Iprefertovarydatathatisnotimportanttotheconditionschecked,i.e.datathatshouldbepartofanequivalenceclass.Bydoingthisweincreasethedatacoverageoftheautomation,andincreasethepossibilitythattheautomatedcheckwillrevealabug.
Javahasaverysimplesetofrandommethodsandclasses.
java.util.random
Math.random()
Java,aspartoftheSecuritypackageshasaSecureRandomclass,whichexposesthesamemethodsaswediscussinthischapter.IdonotcoverSecureRandominthisbookbecause:
Ihaveneveruseditinproductionautomationcode,Itisslightlyslowertoinstantiate,Itisslightlyhardertousewell.
Mostoftherandomnessyouneedinyourautomationcodeyoucanachievewith:
java.util.random
Math.random
ThestaticrandommethodonMathprovidesa‘pseudorandom’number.
Itisactuallyawrapperforthejava.util.randomnextDoublemethod.Butmakesitsimpletouse.
WhenMath.random()isfirstcalled,anewrandomnumbergeneratoriscreatedwhichisusedforeachcalltoMath.random()
Math.random()returnsadouble,greaterthanorequalto0.0andlessthan1.0doublernd=Math.random();
System.out.println(
String.format(
"generated%fasrandomnumber",rnd));
assertThat(rnd<1.0d,is(true));
assertThat(rnd>=0.0d,is(true));
java.util.random
Thejava.util.randompackageprovidesmethodstogeneraterandomvaluesasfollows:
boolean
nextBoolean-returneithertrueorfalselong
nextLong-returnarandomlongvalueint
nextInt-randomintovertherangeofallIntegervaluesnextInt(intbelow)-randomintgreaterthanorequalto0andlessthanbelow
double
nextDouble-flatdistributionwhereeachvaluebetween0.0and1.0hasequalchanceofbeingreturnednextGaussian-aGaussiandistributionwithameanof0.0andastandarddeviationof1.0,meaningabout70%valueshoveringaroundthe0.0mark(+or-1.0)
float
nextFloat-randomfloatgreaterthanorequalto0.0andlessthan1.0byte[]
nextBytes-fillagivenbyte[]withrandombytes.
TousethemethodswefirsthavetoinstantiateaRandomObject:Randomgenerate=newRandom();
Thencalltheappropriatemethodtogeneratetherandomvaluethatwerequire:booleanrandomBoolean=generate.nextBoolean();
intrandomInt=generate.nextInt();
intrandomIntRange=generate.nextInt(12);
longrandomLong=generate.nextLong();
doublerandomDouble=generate.nextDouble();
doublerandomGaussian=generate.nextGaussian();
byte[]bytes=newbyte[generate.nextInt(100)];
generate.nextBytes(bytes);//fillbyteswithrandomdata
MostoftheabovemethodsareprettyselfexplanatoryandIencourageyoutoexperimentwiththembydoingtheexerciseslistedinthischapter.
Iwillgointotwoofthemethodsinmoredetail,aftertheexercise:
nextInt(intbelow)
nextGaussian
Exercise:Create@TestMethodsWhichConfirmRandomLimitsCreate@Testmethodsforeachoftherandommethods.i.e.nextInt,nextLong,etc.Foreachrandommethod,generate1000randomvaluesandassertthatthereturnedvaluesmeetthedescription:
nextIntgeneratesfromInteger.MIN_VALUEandInteger.MAX_VALUEnextBooleangenerateseithertrueorfalsenextLonggeneratesalongbetweenLong.MIN_VALUEandLong.MAX_VALUEnextFloatgeneratesafloatbetween0.0fand1.0fnextDoublegeneratesadoublebetween0.0dand1.0dnextBytesfillsabyte[]withrandomdatanextInt(x)generatesandintfrom0tox-1
nextInt(intbelow)
Whengeneratingarandomintwecanspecifytheupperrangeforthegeneration.
nextInt(intbelow)
Foragivenvaluebelow,thenextIntmethodwillgenerateavaluebetween0(inclusive)andthevalueofthebelowparameter(exclusive)e.g:
nextInt(5)generatearandombetween0and4inclusiveanumbergreaterthanorequalto0(inclusive)butlessthan5(exclusive)
nextInt(200)generatearandomnumberbetween0and199inclusiveanumbergreaterthanorequalto0(inclusive)butlessthan200(exclusive)
IfwewanttousenextInttogenerateanintegerfromaspecificnumber,e.g.1insteadof0thenwehavetouseanalgorithm:
calculatetherangeofnumbersadd1tothis,sincethenextIntmaximumisonelessthandesiredandaddthestartnumber.
e.g.intminValue=1;
intmaxValue=5;
intrandomIntRange=generate.nextInt(
maxValue-minValue+1)+minValue;
Exercise:Createan@Testmethodwhichgenerates1000numbersinclusivelybetween15and20Usethealgorithmabovetogenerate1000numbersbetween15and20andassertthatallnumbers15,16,17,18,19,20weregenerated.
nextGaussian
AdoubledrawnfromaGaussiandistributionwithameanof0.0andastandarddeviationof1.0,meaning:
about70%valueshoveringaroundthe0.0mark(+or-1.0),about95%valuesbetween-2.0and2.0about99%valuesbetween-3.0and3.0about99.9%valuesbetween-4.0and4.0
TheoreticallythereisnolimittothevalueofthedoublethatcouldbereturnedbynextGaussianbecauseitisnotalimitedrange,itisaprobabilitydistributionaroundagivenmean.
Youcanfindreferencesto‘StandardDeviation’attheendofthechapter.
Exercise:Writean@TestmethodthatshowsthedistributionsWritean@Testmethodthatgenerates1000‘double’valuesusing‘nextGaussian’.Countthosethatarewithin1standarddeviation,within2standarddeviationsetc.Calculatethepercentagesofnumberswithineachstandarddeviationrangeandseeiftheyalignroughlywiththevaluesabove.
e.g.theoutputafterrunningthemethodcouldbe:
about70%onestandarddeviation=67.299995
about95%twostandarddeviation=95.3
about99%threestandarddeviation=99.8
about99.9%fourstandarddeviation=100.0
UsenextGaussiantogeneratearangeofintegers
ThenextGaussianmethodistypicallyusedincombinationwithothermethodstodistributetherangeofrandomvaluesoveraprobabilitycurve.
e.g.if‘most’ofourusersareaged30-40,thenwehaveameanof35withastandarddistributionof5,thenwecoulduseGaussiandistributiontogeneratetheageintage=(int)(generate.nextGaussian()*5)+35;
about70%valueshoveringaroundthe35+/-5mark(30-40),about95%valuesbetween35+/-10mark(25-45)about99%valuesbetween35+/-15mark(20-50)about99.9%valuesbetween35+/-20mark(15-55)
Whendealingwithagesyoumightneedtoaddadditionalcodetoensureaminimumandmaximumvalue,eventhoughtheprobabilityofgettinganextremevalueislow,itmighthappen.
Exercise:Writean@Testmethodwhichgenerates1000agesusingnextGaussian
Writean@Testmethodwhichgenerates1000agesusingnextGaussianwithameanof35andastandarddeviationof5.Counteachagegeneratedandoutputthesortedlistofagesandcountstotheconsole.
e.g.
...
34:70
35:167
36:83
37:80
38:66
39:51
...
SeedingrandomnumbersTherandomnumbersare‘pseudorandom’becausetheyarebasedona‘seed’,andeachcallto‘random’isdeterministicifthe‘seed’iscontrolled.
Forexample:Randomgenerate=newRandom(1234567L);
WouldgeneratearandomnumbergeneratorwherethenextIntreturns1042961893
Exercise:Createan@TestmethodforRandomwithSeedCreatean@Testmethodfortheseed1234567Landassertthat:
nextInt==1042961893thennextLong==-6749250865724111202Lcontinuetheassertionsandadd:
nextDouble,nextGaussian,nextFloat,nextBoolean
Makesureyoucanre-runthemethodandyougetthesame‘random’numbers.
Thisisusefulwhenyouwanttomakemethodexecutionrepeatable.e.g.ifatthestartofarunyouseedtheRandomwiththecurrentdatetime,thenifyoulogthedateandtime,youcouldrepeattherunexactly,evenifrandomdatawasused.
ForExample:longcurrentSeed=System.currentTimeMillis();
System.out.println("seedused:"+currentSeed);
Randomgenerate=newRandom(currentSeed);
IftheSystem.out.printlnwasaloggingcall,thenIcouldrecreatetherunbyseedingrandomwiththeseedvalueloggedintheoutput.
UsingRandomNumberstogenerateRandomStringsAcrudewaytogeneraterandomstringsistobuildaStringbyrandomlyaddingavalidcharactertotheString.
ForExampleifIwanttobuildaStringfromtheuppercaselettersandspace:StringvalidValues="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
ThenIcanrandomlyselectacharacterfromthatString:intrndIndex=random.nextInt(validValues.length());
charrChar=validValues.charAt(rndIndex);
IfIlooparoundthisgenerationprocessandconcatenatetheresultsthenIcangeneratearandomString.
Exercise:GenerateaRandomString100charslongGeneratearandomstring,100characterslong,containingthecharacters''(space)and'A'to'Z'.
DiscussionrandomdatainautomationManypeopledonotliketoaddrandomdatatotheirautomation.
Ido.
Iviewautomatedchecksasexercisingaparticularpaththroughthesystem,withvariabledata.
Somedata,isneededinordertocontrolthepath,andifIvarythatdatathenIrunadifferentpath.
ForExample:IfIamonlyaskedformypassportnumberwhenIam65,thenifIcreateauserwhoisnot65,Ican’tcoverthatpath.SoIwouldnotvarytheage.ButifIamaskedforapassportnumberwhenIam65orover,thenIhaveanequivalenceclass.AndifIrandomlygenerateanagewhichis65orolderthenIcancoverthatpath.Itshouldmakenodifferencetothe@Testmethods,soIcanvarythedata.IfIvarythedataandthe@TestmethoddoesnotrunasexpectedthenImayhavefoundabugwithourunderstandingoftheequivalenceclass,butImightalsohavefoundabugrelatedtothewaytheapplicationprocessesaparticularage.
Iuserandomnesstogeneratedataforequivalenceclasses,andcontrolthedatawhichneedstobestaticfortheexecutionpathpreconditionstobemet.
ImportanceofLoggingwhenusingRandomdataWhenIuserandomdata,Ineedtologit.
ThesimplestloggingmechanismtostartwithisSystem.out.printlnsoifmy@Testmethodswritetotheconsoleanoutputofwhatdatatheyhaveused,thenIcanrecreatetherunlaterbyusingtheoutputlogs.Becausethemethodsmayhavefailedduetothespecificcombinationofrandomvalues,andIneedtorecreateanyfailingassertionwiththatparticulardata.
Imayneedtocreateamechanismtorerunmethodswithparticulardatavalues,inwhichcaseseedingtherandommechanism,andloggingtheseedvalue,mightbeanappropriatesolution.
IhavemanagedtogetbyinmostofmyproductionuseofrandomizationbyloggingtheoutputoftherandomdatagenerationtoSystem.out.println.ThelogappearsinSystem.outwhenthecoderanaspartofcontinuousintegrationandifanassertionfailsduetodatathenwecanlookatthelogandusetheseed,ordata,torecreatetheexecution,orre-runningthefailing@Testmethodmanuallywiththegenerateddata.
Startsimplewithyourautomation.
Don’tthinkthatbecauseyou’vestartedusingrandomdatayouneedtheabilitytorecreatealltherunsexactlyandseedyourdatainthecontinuousintegrationenvironment.Youprobablydon’t.Youprobablyneedtostartwiththeabilitytoseewhatdatayouhaveusedsothatyoucanre-runanyfailingmethodsmanuallyanddetermineiftherandomdatacombinationyouused,triggeredabug.
SummaryYouhaveseenwiththelaterexamplesusingnextGaussianandtherandomStringgenerationthatevenwithasmallsetofrandomnumbergenerationfunctionswecanfairlyeasilyusethemtogeneratecomplicateddatasets.
IfrequentlyuserandomdatatohelpmebuildDomainobjectse.g.randomUsers.AndthenIsetthespecificvaluesIneedformy@Testmethod.i.e.insteadofadefaultusernameandpasswordintheconstructor,Imightassignarandomlygeneratedusernameandpassword.
ReferencesandRecommendedReading
StandardDeviationen.wikipedia.org/wiki/Standard_deviation
Math.random
docs.oracle.com/javase/7/docs/api/java/lang/Math.html#random()java.util.random
docs.oracle.com/javase/7/docs/api/java/util/Random.htmlHintsongeneratingvaluesinarange
http://stackoverflow.com/questions/363681
ChapterSeventeen-DatesandTimes
ChapterSummaryInthischapteryouwilllearnhowtouseJava’snativeDatefunctionality
System.currentTimeMillis-currentsystemtimeinmillisecondssincemidnightJanuary1st,1970System.nanoTime-currentJVMtimesourceinnanosecondsThenativeclassesassociatedwithdates:
Date-simpletouseclassforcomparisonandworkingfrommillisecondsSimpleDateFormat-createaStringfromaDateusingaformatpatternCalendar-awrapperforDatetoallowworkingwithdays,months,etc.
DatesinJavaarehandledalittleroughandready,asaresult,manyJavadevelopersuseexternallibrarieslike‘Joda-Time’.Externallibrariesarebeyondthescopeofthisbook,andwhiletheinternalJavaclassesmaynotoffertheflexibilityas‘JodaTime’,theyarestillverypowerful.
Inadditiontoworkingwithdates,IalsousetheDate/Timefunctionalityto:
seedrandomnumbersgenerateuniquedatae.g.filenames,anduserids
currentTimeMillisandnanoTime
System.currentTimeMillis-returnscurrentsystemtimeinmillisecondssincemidnightJanuary1st,1970System.nanoTime-returnscurrentJVMtimesourceinnanoseconds
System.currentTimeMillisreturnsalongwhichrepresentsthecurrenttimeonyourlocalmachine.ThetimeisrepresentedasthenumberofmillisecondssincemidnightoftheJanuary1st,1970.longstartTime=System.currentTimeMillis();
System.nanoTimereturnsalongwhichrepresentsthecurrentnanosecondsascalculatedbythecurrentJVM.Thisdoesn’tnecessarilymapontothecurrentsystemtime,butthedifferencebetweentwocallstonanoTimerepresentsthepassageoftime(innanoseconds)betweenthetwocalls.longstartTime=System.nanoTime();
Ananosecondisonethousand-millionthofasecond.
Itypicallyusethesemethodsto:
calculatethetimethatataskhastakencreateuniqueidsandfilenames
CalculatethetimethatatasktakesTocalculatethetimethatatasktakes,Iwould:
instantiateastartTimeperformthetaskinstantiateanendTimecalculatethetotalTimeasendTime-startTime
ForexampletocalculatehowlongittakestooutputthecurrentTimeMillistotheconsoletentimes,Icanwritecodelikethefollowing:@Test
publicvoidcurrentTimeMillis(){
longstartTime=System.currentTimeMillis();
for(intx=0;x<10;x++){
System.out.println("CurrentTime"+
System.currentTimeMillis());
}
longendTime=System.currentTimeMillis();
System.out.println("TotalTime"+(endTime-startTime));
}
WhenIrunthisInormallygetatotalTimevalueofaround1,butsometimesIwillgetatotalvalueof0becausetheentiretasktakesplacewithinthesame‘millisecond’ascalculatedbycurrentTimeMillis.
TheresolutionofvaluesrepresentedbycurrentTimeMilliscanvarybetweenoperatingsystems,itisnotguaranteedtobea‘millisecond’,itmightbemoree.g.tensofmilliseconds.Assuchthisisn’tagreatmethodforexacttime,butitveryoftengoodenoughforautomationtimings,particularlyifyouareroundinguptothenearestsecondanyway.
Whatitisverygoodfor,areuniquenumbersorvalues,assumingthatyoudon’tresetyourcomputerclockintothepast.
Exercise:Re-writethetiming@TestmethodusingnanoTimeRe-writethemillisecond@TestmethodshownaboveusingnanoTimeandseethedifferenceinoutput.
WhenusingnanoTime,againtheresolutionisdeterminedbytheunderlyingoperatingsystem,butisreportedinnanoseconds.
nanoTimeismuchbetterforcalculatingthetimedurationofanactivitywhichrunsquickly,andforwhichyouwantamoreaccuratemeasurement.nanoTimeisnotusefulforcreatinguniquenumbersbecauseyoudon’treallyknowthebasisfortheJVMtime.
CreateuniquevalueswithcurrentTimeMillis
TocreateuniqueidentifiersornamesIoftenprefixaStringtothecurrrentTimeMillisvalue:StringuserID="user"+System.currentTimeMillis();
Thisiscrudeandsimple,butfastandobvious.
e.g.user1424101386462
Exercise:UsecurrentTimeMillistocreateauniquenamewithnonumbersWeneedtocreateauniquename,thathasallalphabeticcharactersi.e.nonumbersinit.
CreateatestwhichgeneratesauniquestringfromcurrentTimeMillisbuthasnonumbersinthefinalstring.
Date
TheDateclassexposesasmallsetofmethods.Datedate=newDate();
MethodsthatDateprovides:
after-returntrueiftheparameterdateisaftertheDateobjectbefore-returntrueiftheparameterdateisbeforetheDateobjectcompareTo-returns0iftheDateobjectsareequal,negativeiftheDateobjectislessthanparameterandpositiveiftheDateobjectisgreaterthantheparameterequals-returntrueiftheparameterandDateobjectrepresentthesametimeanddatesetTime-setthetimerepresentedbytheDateobjecttoaspecificmillisecondvaluegetTime-returnthenumberofmillisecondsaftermidnight,January11970thatthisDaterepresentstoString-returnaStringrepresentationofthedate
InstantiatingDatewithoutaparameterwilldefaultthetimerepresentedbytheDatetothesamevalueasSystem.currentTimeMillis.
Thefollowingtwostatementsareessentiallyequivalent:DateequivDate1=newDate();
DateequivDate2=newDate(System.currentTimeMillis());
ThetoStringmethodprovidesasimplemethodofoutputtingaStringrepresentationofthedate.System.out.println(date.toString());
OnmymachinetoStringoutputsthefollowingstringformat:
ThuJun2012:18:04BST2013
WewilllearnhowtocontroltheoutputofaDateinthenextsection.
WecanalsoinstantiateaDatewithalong,inordertosettheDatetoaspecifictime.
Forexample,IcouldcreateaDate7daysinthefuturefromoneDatebymanipulatingthelongthatIinstantiatetheDatewith:longoneWeekFromNowTime=date.getTime();
oneWeekFromNowTime=oneWeekFromNowTime+
(1000*60*60*24*7);
DateoneWeekFromNow=newDate(oneWeekFromNowTime);
System.out.println(oneWeekFromNow.toString());
IntheabovecodeItakethetimefromoneDatethenIadd7daysworthofmillisecondstothelongvalue,andinstantiateanewDatefromthatmillisecondsvalue.Resultinginthefollowingoutput:
ThuJun2712:18:04BST2013
WecanusethesetTimetosetthemillisecondstimevalueofadateafterconstructingit,soIcancreateaDatewithaduplicatetimeusingtheconstructororthesetTimemethod:DatesameDate=newDate();
sameDate.setTime(date.getTime());
assertThat(date.equals(sameDate),is(true));
assertThat(date.compareTo(sameDate),is(0));
SimpleDateFormat
SimpleDateFormatallowsustooutputthevalueofaDateobjectasaString,inaformatthatwechoose.SimpleDateFormatsdf=newSimpleDateFormat();
SoifIinstantiateaDatetothe1stofJanuary1970:SimpleDateFormatsdf=newSimpleDateFormat();
Thenthefollowingtableshowsexamplepatternsandtheassociatedgeneratedoutput,whenIapplythepattern:
Pattern Output"MM/dd/yyyy" "01/01/1970"
"MMM/dd/yyy" "Jan/01/1970"
"MMMM/d/yy" "January/1/70"
IcanusetheapplyPatternmethodtosetthepatternforaSimpleDateFormatandusethepatternonadatewiththeformatmethod.sdf.applyPattern("MM/dd/yyyy");
assertThat(sdf.format(date),is("01/01/1970"));
applyPattern-setthepatternthatthenextformatwilluseformat-formatthegivenDatewiththedefinedpattern
IcanalsoinstantiateSimpleDateFormatwiththepatternthatIwanttousee.g.“yearmonthday24hour:minutes:seconds.milliseconds”shownbelow
SimpleDateFormatsdf=newSimpleDateFormat("yMdHH:mm:ss.SSS");
YoucanuseSimpleDateFormattogenerateaDateforagivendatestringe.g.thedateof“15thDecember2013”andatimeof“11:39pm”and“54secondsand123milliseconds”:Datedate=sdf.parse("2013121523:39:54.123");
Importantelementsforuseinthepatternformatarelistedbelow,using
Element Description Output"y" year "2013"
"yy" year "13"
"yyy" year "2013"
"yyyy" year "2013"
"yyyyy" year "02013"
"M" Month "12"
"MM" Month "12"
"MMM" Month "Dec"
"MMMM" Month "December"
"d" DayinMonth "15"
"dd" DayinMonth "15"
"ddd" DayinMonth "015"
"h" HourinAM/PMTime "11"
"hh" HourinAM/PMTime "11"
"hhh" HourinAM/PMTime "011"
"H" Hourin24HrTime "23"
"HHH" Hourin24HrTime "023"
"m" MinuteinTime "39"
"mm" MinuteinTime "39"
"mmm" MinuteinTime "039"
"s" SecondinMinute "54"
"ss" SecondinMinute "54"
"sss" SecondinMinute "054"
"S" Milllisecond "123"
"E" WeekDayName "Sun"
"EEEE" WeekDayName "Sunday"
"a" AM/PM "PM"
Moreunusualdateformatpatternsarelistedbelow.These,Ihaven’ttendedtousemuch:
Element Description Output"w" Weekintheyear "50"
"www" Weekintheyear "050"
"W" Weekinthemonth "2"
"WW" Weekinthemonth "02"
"WWW" Weekinthemonth "002"
"D" Dayintheyear "349"
"F" Dayofweekinthemonth "3"
"FF" Dayofweekinthemonth "03"
"FFF" Dayofweekinthemonth "003"
"u" Daynumberintheweek "7"
"uu" Daynumberintheweek "07"
"k" Hourintheday(1-24) "23"
"kkk" Hourintheday(1-24) "023"
"H" Hourintheam/pm(0-11) "23"
"HHH" Hourintheam/pm(0-11) "023"
"z" GeneralTimeZone "GMT"
"Z" RTC822TimeZone "+0000"
"X" ISO8601TimeZone "Z"
Thereasonforshowingsomanydifferentcombinationse.g."y","yy","yyyyy"wastodemonstratethatsomepatternswilltruncate,orpad,orexpanddependingonthevalueintheDate.
SimpleDateFormathasothermethodsavailable,Isuggestyoureadtheon-linedocumentationforSimpleDateFormatifyouwanttolearnmore.TypicallyIcreateaSimpleDateFormatwiththepatternIwanttouse,andthenformataDatewiththatpattern.You’llgetalotofmileageoutofthatsimpleapproach.
Calendar
CalendarprovidesawrapperfortheDateclasswhichallowsustoedititintermsofitsindividualcomponents,e.g.changethedate,orthemonth,ortheyear,ratherthanworkingdirectlywiththemillisecondtime.
InstantiateanewCalendarusingthestaticgetInstancemethodontheCalendarclass.Calendarcal=Calendar.getInstance();
InitiallyIwillcompareCalendarwithDatesoyougainbasicfamiliaritywithit,thenwewillexplorethemethodsandcapabilitiesinmoredetail.
WehavemanyofthemethodsthatyoualreadyencounteredwithDate,butthemethodsworkwithCalendarparameters:
after-returnstrueiftheparameterisaftertheCalendarbefore-returnstrueiftheparameterisbeforetheCalendar
equals-returnstrueiftheparameterrepresentsthesamedateandtimeastheCalendar
compareTo-returns0,-veor+ve;iftheparameterisequal,after,orbeforetheCalendar
WehaveamethodgetTimeonCalendarjustaswedidwithDatebutthegetTimemethodonCalendarreturnsaDatesothefollowinglinesareequivalentwhenworkingwithCalendar:System.out.println(cal.getTime().getTime());
System.out.println(System.currentTimeMillis());
TheCalendarmethodtoStringdoesnotprintanicelyformattedversionofthedateandtime,insteaditshowsalltheattributesoftheCalendarObject.
Exercise:WritethetoStringtoconsoleWritean@TestmethodwhichinstantiatesaCalendarobjectandwritestheoutputoftoStringtotheconsole.
IcancontroltheDatedetailsofaCalendarwiththesetTimemethod:CalendarsameDate=Calendar.getInstance();
sameDate.setTime(cal.getTime());
assertThat(cal.equals(sameDate),is(true));
assertThat(cal.compareTo(sameDate),is(0));
SinceI’musingtheDatefromanotherCalendarIcancomparethetwoCalendarswithequalsandcompareToandexpectthemtohavethesamedateandtimedetails.
ToadvancethedateandtimedetailsforaCalendarIcanusetheaddmethod.e.g.toaddon7days,asIdidpreviouslywiththeDate:CalendaroneWeekFromNow=Calendar.getInstance();
oneWeekFromNow.setTime(cal.getTime());
oneWeekFromNow.add(Calendar.DATE,7);
IcanthencomparetheCalendarobjectsaswesawbeforewithafter,before,compareTo.assertThat(oneWeekFromNow.after(cal),is(true));
assertThat(cal.before(oneWeekFromNow),is(true));
assertThat(cal.compareTo(oneWeekFromNow),is(-1));
assertThat(oneWeekFromNow.compareTo(cal),is(1));
SettingCalendarValuesCalendarConstants
Calendarprovidessomeconstantsforworkingwithfieldsinaliteralway:
DATE
YEAR
MONTH
DAY_OF_MONTH
HOUR
MINUTE
SECOND
etc.
Youcanfindafulllistoftheseconstantsintheon-linereferenceorthroughcodecompletionontheCalendarobject.
Weusetheseconstantswhenweadd,setorgetthefieldsontheCalendar.
setindividualCalendarfieldsWecansetindividualCalendarfieldsusingtheCalendarconstants:cal.set(Calendar.YEAR,2013);
cal.set(Calendar.MONTH,11);//startsat0
cal.set(Calendar.DAY_OF_MONTH,15);
cal.set(Calendar.HOUR_OF_DAY,23);
cal.set(Calendar.MINUTE,39);
cal.set(Calendar.SECOND,54);
cal.set(Calendar.MILLISECOND,123);
SinceitcanbeconfusingtoseeMonthsaszerobasedinthecodetherearealsoconstantsfortheMonthnamesthemselves.cal.set(Calendar.MONTH,Calendar.DECEMBER);
settheCalendarYoucanalsocallthesetmethodwithmultiplefields.Thesearetheninafixedorder:
YearMonthDayofMonthHourofdayMinuteSecond
cal.set(2013,11,15);
cal.set(2013,Calendar.DECEMBER,15);
cal.set(2013,11,15,23,39);
cal.set(2013,Calendar.DECEMBER,15,23,39,54);
Notethatthecombinationsdonotletyousetthehourwithoutalsosettingtheminute.
WecanuseDatetosetthetimeonaCalendarwiththesetTimemethod:cal.setTime(newDate(0L));
WecanalsosettheCalendarfromamillisecondvalueinthesamewaywedidforDate:cal.setTimeInMillis(0L);
WecanalsosettheCalendarfromarelativeperspectiveofweekse.g.Thursdayinthe3rdWeekofJanuary2013:cal.setWeekDate(2013,3,Calendar.THURSDAY);
Theabovesetsthedateto17thJanuary2013.Feelfreetodoublecheckthisonanactualcalendar.
getdetailsfromtheCalendarJustasweusetheCalendarconstantstosetvaluesinaCalendarwecanusethesameconstantstogetinformationfromtheCalendar.
GivenaCalendarsetto15thDecember2013,at23:49and54seconds:cal.set(2013,Calendar.DECEMBER,15,23,39,54);
WecanusetheconstantstoassertthattheCalendarhasbeencreatedasweexpected:assertThat(cal.get(Calendar.MONTH),is(Calendar.DECEMBER));
Exercise:UsetheotherCalendarconstantsWritean@TestmethodwhichinstantiatesaCalendar,andassertonthevaluesyouexpectforthefollowingconstants:
UseaCalendarsetto15thDecember2013,at23:49and54seconds.
Assertonthevaluesyouexpectfor:
MONTH
YEAR
DAY_OF_MONTH
HOUR_OF_DAY
MINUTE
HOUR-AM/PMhourAM_PM-Calendar.AMorCalendar.PM
Exercise:ExperimentwithotherconstantsExperimentwiththeotherconstantssothatyouaresureyouunderstandthem.e.g.confirmthefollowingforthe15thDecember2013:
itisaSundayitisinthe3rdweekinthemonth(0indexbased,so0isthefirstweek)itisthe1stdayintheweekitisinthe50thWeekoftheyearitisthe349thdayintheyear
getmoreinformationfromCalendar
getTime-returnstheCalendarasaDateobjectgetTimeInMillis-returnstheCalendarasalong
ThereareothermethodsonCalendartoretrievemoreinformationaboutthecalendar,butIsuggestyoureadtheon-linedocumentationorcodecompletiontohelpyouunderstandthescopeofalltheinformationyoucanretrievefromthisObject.
Inpractice.ItendtosetupdatesasIneedthem,retrievedates,andthenmovedatesforwardorbackwardsintime.Whichwewillcovernext.
addandsubtracttorolldatesthroughtimeTherearetwomainmechanismswiththeCalendarObjectformovingthetimeinarelativefashion:
add-addorsubtractanamountfromafieldroll-changeasinglefieldwithoutaffectingothers
Wecanuseaddtoincrementordecrementfieldvalues.ForexampleIcouldtakeaCalendardateof23:39anddecrementthehourofthetime:cal.add(Calendar.HOUR_OF_DAY,-1);
assertThat(cal.get(Calendar.HOUR_OF_DAY),is(22));
SimilarlyIcouldincrementtheminutesonthetime:cal.add(Calendar.MINUTE,10);
assertThat(cal.get(Calendar.MINUTE),is(49));
Exercise:IncrementandDecrementotherFieldsExperimentwiththeaddmethodandchangethefieldsindifferentwaystomovethedatefrom23rdDecember2013to3rdJune2011.
WiththerollmethodIcanchangeasinglefield,withoutaffectinganyofthelargerunitse.g.giventhedate15thDecember2013,Icanrollforward17Daysofthemonthtorollovertothe1st,anditwillstillbeDecember2013.IfIweretodothiswithanaddthedatewouldbecome1stJanuary2014becausetheotherfieldswouldadvanceaswelltokeepthedatevalid.cal.roll(Calendar.DAY_OF_MONTH,17);
assertThat(cal.get(Calendar.YEAR),is(2013));
assertThat(cal.get(Calendar.MONTH),is(Calendar.DECEMBER));
assertThat(cal.get(Calendar.DAY_OF_MONTH),is(1));
Exercise:ConfirmaddMovestheYearWritean@Testmethodthatdemonstratesthatadding17,to23rdofDecember2013,insteadofrolling17movesthedateto1stJanuary2014.
SummaryIntheproductionenvironment,inthemainapplication,weveryoftenusetheJoda-Timelibrary.ButI’mtryingtokeepcoverageof‘libraries’outofscopeforthisbook,tomakeiteasierforyoutogetstarted,andtohelpyoubuildknowledgeandexperiencewiththein-builtfeatures.
Relyingtoomuchonexternallibrariesoftenmeansaddinganotherlibraryintothecode-basewhenallthatisreallyrequiredisaquickwrapperaroundexistingcoreJava.
Thechaptercoveredbasicexamplesof:
timinghowlongasetofcodetakestoexecutecreatinguniqueidsandnamesforfilesformattingdatesdatearithmeticandmanipulation
Ifrequentlyhavetoformatdatesindifferentways,whenI’mgeneratinginputdataforapplicationautomation.
Itimethehowlongcoderuns,whenI’mwritingsimpleperformanceautomation.IoftenusenanoTimetodothis.
Iveryoftencreateuniquefile-namesusingthevaluereturnedbycurrentTimeMillis.Yousawexamplesofsimplewaystoconvertthenumericfilenamesintoalphabeticcharacters.Isometimesgenerateuniqueusernamesforinputdatainthisway,withcurrentTimeMillis.
Wealsocoveredbasicdatetimearithmeticinthechapter.Averyusefulthingtobeabletodo,whengeneratingrandomdata.
IthinkI’vecoveredthebasicsofDateandTimeforthecoreJavaclasseswellenoughforyoutostartusingtheminyour@Testmethods.
IhaveonlyeverhadtodropdowntoJoda-Timeonceortwiceinmycareer.Iencourageyoutoexperimentwiththein-builtDateTimefunctionality,beforebringinginanexternallibrary.Youmightbesurprisedhowmuchyoucando.
ReferencesandRecommendedReading
Joda-Timejoda-time.sourceforge.net
currentTimeMillis
docs.oracle.com/javase/7/docs/api/java/lang/System.html#currentTimeMillis%28%29nanoTime
docs.oracle.com/javase/7/docs/api/java/lang/System.html#nanoTime%28%29nanosecond
en.wikipedia.org/wiki/NanosecondDate
docs.oracle.com/javase/7/docs/api/java/util/Date.htmlSimpleDateFormat
docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.htmlCalendar
docs.oracle.com/javase/7/docs/api/java/util/Calendar.html
ChapterEighteen-PropertiesandPropertyFiles
ChapterSummaryInthischapteryouwilllearnhowtousethePropertiesclass
Apropertyfilehas“key,value”pairsoneachlinePropertiesclassmakesiteasytoloadandsave“key,value”pairdatasetPropertymethodtoaddapropertykeyandvaluegetPropertymethodtogetthevalueforapropertykeysizemethodtoreturnthenumberofpropertykeysIteratethroughpropertiesbykeyusingstringPropertyNameslisttodisplaypropertiestooutputcontainsKeycheckifapropertykeyexistsAnintroductiontoJavaSystemproperties
user.dir-currentworkingdirectoryforthecodeuser.home-homedirectoryofcurrentuserline.separator-endofnewlinestringfile.separator-characterseparatorfordirectorypathsjava.io.tmpdir-locationofthecurrenttemporarydirectory
LoadingandSavingPropertyfilesstoretosavepropertyfilesloadpropertyfilesincombinationwithaFileReader
OneoftheearlyproblemsIhadwhenworkingwithJava,wasworkingwithfilesformydata.Filesaren’treallythathard,andwe’llcovertheminalaterchapter,butmyinitialworkaroundwastousepropertyfiles,viathePropertiesclass.
Propertyfilesarethoseverysimplefilesyouseemanytoolsuseforconfiguration,withakey=valuepaire.g.#Definethebrowserstouse
browser=chrome
port=8080
Apropertyfiletreatslinesstartingwith#ascomments.Blanklinesareignored.Lineswithcontentaretreatedas“key,value”pairsseparatedbyan=sign.Ifapropertyfilehasmultipleentrieswiththesamekey,thenonlythelastonewillbeusedtrailingandleadingspacesbeforeandaftereitherthekeyorthevalueareignored,e.g.thefollowingentriesareallequivalent
browser=chrome
browser=chrome
browser=chrome
IntheearlydaysIwouldveryoftenusePropertyfilesasinputfileswhichIdidn’thavetostruggletoparsee.g.
step1=OPEN_APP
step2=TYPE12345
step3=CLICK_ENTER
step4=CLOSE_APP
Youcanprobablyguessthattheaboveexampleisasimplekeyworddrivenscript.Idon’trecommendthisapproach,I’mjustpointingoutthatwhenIwaslearningJava,IusedthebasicknowledgethatIhadtogetthingsdone,withoutworryingtoomuchaboutthe‘best’wayofdoingit.AndProperties,withassociatedpropertyfiles,madecertainthingseasy.
PropertiesBasicsTheJavaPropertiesobjectinjava.util.PropertiesisthemainclasswewilluseforworkingwithProperties.
Itworksmuchlikeahashmap,witha“key,value”pair,wherebothkeyandvalueareStringobjects.
Propertiesalsohasadditionalmethodsforloadingandsavingthepropertiestofiles.
Warning:Don’tgocrazyWhenIfirstlearnedaboutPropertiesIthinkIwentabitcrazyandusediteverywhere.IuseditinsteadofusingaMap.Insteadofdefiningallparametersinmethods,IjuststuckeverythinginaPropertiesobjectandpassedthatintothemethod.Idon’tdothisanymore.Andneithershouldyousinceyoualreadyknowhowtousethecollectionclasses.
CreatingnewPropertiesWecreatenewPropertiesobjectsusingthePropertiesclassfromjava.util.Properties
Propertiesproperties=newProperties();
TheabovewillgiveusaPropertiesobjectwithnoproperties.i.e.sizeof0assertThat(properties.size(),is(0));
SettingandGettingPropertyvaluesUsethesetPropertyandgetPropertymethodstosetandgetpropertyvalues:properties.setProperty("browser","firefox");
properties.setProperty("port","80");
setPropertywillcreatethepropertyifitdoesnotexist,oroverwritethevalueofthepropertyifitalreadyexists.
getPropertyreturnsthevaluefortheproperty:assertThat(properties.getProperty("browser"),
is("firefox"));
assertThat(properties.getProperty("port"),
is("80"));
IfthepropertykeyweprovidetogetPropertydoesnotexistthennullwillbereturned.
assertThat(properties.getProperty("missing"),
is(nullValue()));
WhenwecallgetPropertywecanspecifyadefaultvalue,sothatwedon’treceive‘null’,insteadwereceivethedefaultvalueifthepropertykeyhasnotbeenset.assertThat(properties.getProperty("missing","default"),
is("default"));
WorkingwithPropertiesGenerally,ifwehavesetupthepropertiesthenwewillworkwiththegetPropertymethod.
But,sometimesyouwanttoworkwiththePropertiesusingthesetofkeys.WeusethestringPropertyNamesmethodforthis:
IfIwanttoiterateoverthepropertykeysandoutputallthevalues,thenIcaniterateovertheSetofStringpropertykeys:for(Stringkey:properties.stringPropertyNames()){
System.out.println("Key:"+key+""+
"Value:"+properties.getProperty(key));
}
Theabovewouldoutput:Key:portValue:80
Key:browserValue:firefox
ThePropertiesclasshasamethodcalledlistwhichoutputsthepropertynameandvaluepairtothegivenprintstream:properties.list(System.out);
Callingthelistmethodwouldoutput:--listingproperties--
port=80
browser=firefox
IalsocheckforpropertyexistencewiththecontainsKeymethod:assertThat(properties.containsKey("browser"),is(true));
Exercise:CreateandListaPropertiesobjectWritean@Testannotatedmethodwhich:
CreatesaPropertiesobjectAddthefollowing“key,value”pairs:name=bob,gender=male,password=paSSw0rdAssertthatthesizeofthePropertiesobjectis3Outputthe“key,value”pairstotheconsolebyiteratingoverthekeysUsethelistmethodtooutputthepropertiesAssertthatthePropertiesobjectcontainsthekeygenderAssertthatthevalueofthepropertynameisbobUsegetPropertywithadefaultvalueandassertthatthevalueofkey"permission"is"Admin"
Java’sSystemProperties
ReadingSystemPropertiesJava’sSystemobjecthasasetofpropertiesthatcomeinveryhandwhenwritingautomationcode.
e.g."user.dir"returnstheworkingdirectoryfortherunningapplicationStringworkingDirectory=System.getProperty("user.dir");
IcanusethisforaccessingdatafilesthatIwanttouseinmyautomatione.g.ifIcreateadirectoryinmyprojectcalledproperty_filesunder/src/test/resources/thenIcouldbuildthefullpathtoafilebyprefixingthecurrentworkingdirectory:StringresourceFilePath=workingDirectory+
"/src/test/resources/"+
"property_files/"+
"static_example.properties";
YoucanworkdirectlywiththePropertiesobjectonSystem,byusingthegetPropertiesmethod.
ForexampleifIwantedtolisttheSystempropertiesthenIcanusethefollowingcode:Propertiessys=System.getProperties();
sys.list(System.out);
Apartialoutputoftheabovecommandisshownbelow:--listingproperties--
java.runtime.name=Java(TM)SERuntimeEnvironment
sun.boot.library.path=C:\ProgramFiles\Java\jdk1.7.0_10\jre...
java.vm.version=23.6-b04
java.vm.vendor=OracleCorporation
java.vendor.url=http://java.oracle.com/
path.separator=;
java.vm.name=JavaHotSpot(TM)64-BitServerVM
Exercise:OutputtheSystemPropertiesobjectWritean@TestannotatedmethodwhichwilllistthecontentsoftheSystemProperties
ReadtheSystemPropertiesdocumentationsoyouunderstandtherangeofpropertiesavailableforyoutousebydefault.
docs.oracle.com/javase/tutorial/essential/environment/sysprop.html
SystempropertiesIusemostoftenare:
user.dir-currentworkingdirectoryforthecodeuser.home-homedirectoryofcurrentuserline.separator-endofnewlinestringfile.separator-characterseparatorfordirectorypathse.g.\onwindows,/onlinuxjava.io.tmpdir-locationofthecurrenttemporarydirectory
SettingSystemPropertiesYoucansetSystemproperties,thesameasyoucanwithanormalPropertiesobjectusingthesetPropertycommand.
IfrequentlydothisifIwanttocontrolsomeenvironmentalconfigurationfromwithinmyrunningcode.
Asanexample,whenusingWebDriverandworkingwithChrome,IhavetosetaSystemproperty,sothattheChromedriverknowswheretofindtheChromeDriver.exethatitusestocontroltheChromebrowser.
webdriver.chrome.driver
Igenerallydon’taddtheChromeDriver.exeintoversioncontrolandhaveaconventionthatitislocatedinadirectoryrelativetomyworkingdirectory.SoIsetthepropertyrelativetomyworkingdirectory.
Sincethisisapropertythatmighthavebeensetalready,ItendtocheckifithasbeensetoutsidetherunningapplicationbeforeIoverwriteit.Leadingtocodelikethefollowing:if(!System.getProperties().containsKey("webdriver.chrome.driver")){
StringcurrentDir=System.getProperty("user.dir");
StringchromeDriverLocation
=currentDir+
"/../tools/chromedriver/chromedriver.exe";
System.setProperty("webdriver.chrome.driver",chromeDriverLocation);
}
IntheabovecodeIfirstcheckifthepropertyisset,ifitisthenIdon’toverwriteit.IfthepropertyisnotsetthenIusethecurrent"user.dir"andsetthepathrelativetothatworkingdirectory.
WorkingwithPropertyfilesInthissectionwearegoingtolookatthemethodsonthePropertiesObjectassociatedloadingandsavingfiles.
SavePropertiesdoeshaveasavemethod,butthisisdeprecatedbecauseitdoesnotthrowanIOException.
DeprecatedDeprecatedmeansthatthemethodshouldnotbeused,andthatthemethodmayberemovedinfutureversionsofJava.Themethodwillwork,butyourcodemayfailinthefuturewhenyouupdatetheJavalibraryorSDKyouareusing.
Insteadweusethestoremethod,whichwritesthefiletoaWriteroranOutputStream.
BecauseIwillcreateafilethatI’monlyusingaspartofthe@Testmethodexecution,I’mgoingtocreateitasatemporaryfile.
Java7providesawayofcreatingtemporaryfiles,whichwewillcoverintheFilesChapter.
SincethisisthePropertieschapter,wewillusetheSystemproperty"java.io.tmpdir"whichreturnsthepathofthesystemtempdirectory.StringtempDirectory=System.getProperty("java.io.tmpdir");
StringtempResourceFilePath=
tempDirectory+
"tempFileForPropertiesStoreTest.properties";
Wethenneedtocreatethepropertiesthatwewillstoretothefile:Propertiessaved=newProperties();
saved.setProperty("prop1","Hello");
saved.setProperty("prop2","World");
WeneedtocreateaFileOutputStreamtostorethepropertiesinto,andwritethemwiththestoremethod.ThestoremethodleavestheOutputStreamopensowehavetocloseitwhenwearefinishedwithit.FileOutputStreamoutputFile=
newFileOutputStream(tempResourceFilePath);
saved.store(outputFile,"HelloThereWorld");
outputFile.close();
Notethatthestoremethodtakestwoparameters:
theOutputStreamthatwewritethedetailstoacommentString
TheStringcommentiswrittentotheOutputStreampriortotheproperties,andinadditionaTimeStampforwhenthepropertiesarewrittenisaddedtothefile.
Sothefinalfileoutputfromtheabovemethodexecutionlooksasfollows:1#HelloThereWorld
2#MonAug0515:12:24BST2013
3prop2=World
4prop1=Hello
Notethatthepropertyorderingisnotretainedwhenwritingtothefile.
LoadSinceIhavealreadycreatedafileinmyproject(usingthestoremethod),allIhavetodoisloaditfromthedirectoryIsaveditto.
IcanuseeitheranInputStreamoraFileReaderforthis.WewillcovertheseinmoredetailintheFilesChapter.Butfornow,wewilluseaFileReader.FileReaderpropertyFileReader=
newFileReader(tempResourceFilePath);
Propertiesloaded=newProperties();
try{
loaded.load(propertyFileReader);
}finally{
propertyFileReader.close();
}
Ihavewrappedtheloadmethodinatry/finallyblock,becausetheloadmethodleavestheInputStreamorFileReaderopenwhenitfinishes,sowehavetocloseit.AndIwantittocloseeveniftheloadmethodthrowsanIOException.
OncethepropertyfilehasloadedintothePropertiesobject,IcanaccessthepropertywiththegetPropertymethodaswedidbefore:assertThat(loaded.getProperty("prop1"),is("Hello"));
assertThat(loaded.getProperty("prop2"),is("World"));
DeleteFilesWewillcoverfilesinmoredetailinalaterchapter.Butfornow,sincewehavecreatedafile.Weshouldlearnhowtodeleteit:newFile(tempResourceFilePath).delete();
Exercise:StoreandLoadaSavedPropertiesFileUsingthecodepresentedabove:
CreateaPropertiesobjectAddsome“key,value”pairstothePropertiesStorethePropertiesfileinthe"java.io.tmpdir"ReadthePropertiesfileandassertonthevaluesDeletethePropertiesfilewhenyouarefinished
SummaryIstillfindpropertyfilesveryusefulandbeforewritingcomplicatedfileparsingandstoringroutines.IfirstseeifIcanprototypeanyfilestoragefunctionalitywithpropertyfiles.
Propertyfileshavetheadvantagethattheyareeasytoeditbyhumans,sincetheyareasimpleformatoftextfile.
Theyarealsoeasytoparsefortheapplicationcode.
ReferencesandRecommendedReading
Propertiesofficialdocumentation-docs.oracle.com/javase/7/docs/api/java/util/Properties.html
PropertiesJavaTutorialdocs.oracle.com/javase/tutorial/essential/environment/properties.html
SystemPropertiesofficialdocumentationdocs.oracle.com/javase/tutorial/essential/environment/sysprop.html
CreateaTemporarydirectoryinJavastackoverflow.com/questions/617414/create-a-temporary-directory-in-java
ChapterNineteen-Files
ChapterSummaryInthischapteryouwilllearnhowtousethebasicJavafilehandlingclasses
FilethegeneralwrapperforafilecreateTempFile-createatemporaryfilecreateNewFile-createthefiledelete-deletethefilenowdeleteOnExit-deletethefilewhentheapplicationclosesgetName-returnthefilenameordirectorynamegetParent-returnthepathoftheparentdirectorygetAbsolutePath-returnthefullfilenameandpathgetCanonicalPath-returntheuniquefullrepresentationoftheFilemkdir-createsasingledirectorymkdirs-createsadirectoryandallnecessarydirectoriesinthepathisDirectory,isFile-determingtypeofphysicalFileseparator,pathSeparator-forfilese.g.‘\’andPathe.g.‘;’listRootsanarrayoftherootpathsinthefilesystemlength-thelengthoftheFileinbytesgetFreeSpace,getTotalSpace,getUsableSpace-diskspacerenameTo-renameafileDirectorymethods
list-alistofthefilenamesasStringlistFiles-alistofFileobjectsforeachfileanddirectory
AttributemethodscanRead,canWrite,canExecute,lastModifiedsetExecutable,setReadable,setWritable,setReadOnly,setLastModified
FilesclasswithstaticmethodstocopyandmoveafileordirectoryPrintWriter-hasmethodstomakewritingeasiere.g.print,printlnFileWriter-writetocharacterbasedfilesBufferedWriter,BufferedReader-bufferoutputandinputforefficiencyFileReader-readfromaninputstream
Itendtokeepmyfilecodeassimpleaspossible,becausemyusecasesareusuallyfairlysimple:
readingfilesthatotherpeoplehavewritten-sometimestocheckvalidityofthedatareadingsimpleCSVortabdelimitedfiles-oftenasinputtodatadrivencheckscopyingfiles-tokeepafolderofdatausedduringautomation,orforsetupdatacreatingdirectories-tomakemywork-flowsimplermovingfiles-screenshotimages,logfilesdeletingfileswritingreport-simplelogfilesorHTMLreportoutput
InthischapterI’llcoverthebasicclassesandapproachesforimplementingtheaboveusecases.
ExampleofreadingandwritingafileIwillquicklyshowyousomecodethatwritesafile,andreadsthesamefile.
Ifyouwanttoimmediatelyexperimentthenfeelfree.Therestofthechapterwillworkthroughthevariousmethodsandclassesused,explainingtheminmoredetail.
WriteaTempFileprivateFilewriteTheTestDataFile()throwsIOException{
FileoutputFile=File.createTempFile("forReading",null);
PrintWriterprint=newPrintWriter(
newBufferedWriter(
newFileWriter(outputFile)));
for(intlineNumber=1;lineNumber<6;lineNumber++){
print.println("line"+lineNumber);
}
print.close();
returnoutputFile;
}
Theabovecode,createsatemporaryfile,inthesystem‘Temp’directory.
e.g.forReading2536453396676632859.tmpin%TEMP%(onWindows)
Ituses3classestowraparoundthefile:FileWriter,BufferedWriterandPrintWriter.Thenprints5linesoftexttothefile,closesthefile,andreturnstheFiletothecallingmethod.
Readthetempfile@Test
publicvoidoutputFileToSystemOutWithBufferedReader()throwsIOException{
FileinputFile=writeTheTestDataFile();
BufferedReaderreader=newBufferedReader(newFileReader(inputFile));
try{
Stringline;
while((line=reader.readLine())!=null){
System.out.println(line);
}
}finally{
reader.close();
}
}
Thecodeabove,callsthewriteTheTestDataFilemethodtocreateatemporaryfile.ThenitusesthereturnedFile,andwrapsitwithaFileReaderandaBufferedReader,thenreadseachlineandprintsitout.
Itwrapsthereadingcodeinatry/finallyblockwhenreadingtomakesurethatthefileactuallyclosesifanexceptionisthrown.
BasicNotes
Itseemslikealotofclassesareinvolvedthere.Butasyouwillseelater,theybuildoneachothertomakethereadingandwritingoffileseasyforyou.
Ifyoustartbycopyingthecodeabove,andamendingitslightly,youcanprobablymeetatleast3oftheusecasesImentionedatthetopofthischapterasmycommonusecases.
Andyoucouldprobablyfigureouttheotherusecasesbyreadingthecontextsensitivecodecompletionontheclasses.
Theremainderofthischapterwillcovereachoftheclassesinvolvedinmoredetail.
FileTheFileclassprovidesthemainclasstorepresenta‘file’or‘directory’andmethodsforcreatingdirectoriesandotherlocalfileactions.
TheFileclassalsoprovidesasetofstaticmethodsthatcanhelpus.
Fileisinthejava.iopackage.
StaticMethods
createTempFile
createatemporaryfileinthesystem’stemporarydirectory(onWindowsthisis‘%TEMP%’)
separator
theseparatorforfilevaluese.g.‘\’pathSeparator
thesystemseparatorinthePathe.g.‘;’listRoots
anarrayoftherootpathsinthefilesystem
IonlyreallyusethecreateTempFileandseparatorbutwillcoveralltheabovemethods.createTempFile
FileoutputFile=File.createTempFile("forReading",null);
Thismethodcreatesanemptyphysicalfileinthesystemtemporarydirectory(%TEMP%).
IntheaboveexampleIassigntheFileintoavariablecalledoutputFilesothatIcanuseit.
Themandatoryparameterstothismethodare:
prefix
e.g.forReading.Theprefixneedstobe3charsorlongerotherwiseandexceptionisthrown:
java.lang.IllegalArgumentException
suffix
Thevaluetoaddattheendofthetempfilename.Ifyouleavethisasnullthenthefilewillbegiventhesuffix.tmpbutyoucanaddyourownsuffixifyouwantto.
IntheaboveexampleIpassinaprefixofforReading,andnullforthesuffix,sotheendresultisanemptyfilewithanamelike:
forReading16535777254649642741.tmp
ThenumberisaddedbytheJavamethodtotryandmakethefilenameuniqueinthetempfolder.
Theoptionalfinalparametertothismethodis:
directory
AFileobjectforthedirectorytocreatethetempfilein.
aTempFile=File.createTempFile("pre",null,
newFile(System.getProperty("user.dir")));
Intheabovecode,Ileftthesuffixasnullsoitwilluse‘.tmp’asthesuffix,andwillcreatethefileintheUserDirectorywhereIamrunningthecode.Onmysystemthiscreatedafilenamedandlocatedasfollows:D:\Users\Alan\Documents\javaForTesters\pre4051399336820173102.tmp
Exercise:CreateaTempFileandVarytheParametersWritean@Testmethodwhichcreatesatempfile.
FindthefileinyourSystem’stemporarydirectoryandmakesureitwaswritten.
Varytheprefix,andthesuffixtoseetheimpactoftheoutputfile.
separatorandpathSeparator
TheseparatormethodisthemainoneIuse,sinceitprovidestheseparatorbetweenvaluesinfilepaths,i.e.thedirectoryseparator‘\’onWindowsand‘/’onLinux.
IusethiswhenbuildingupStringvaluestoactaspathsforfiles.Assert.assertTrue("UnrecognisedOSfileseparator",
File.separator.equals("\\")||
File.separator.equals("/"));
Assert.assertTrue("UnrecognisedOSpathseparator",
File.pathSeparator.equals(";")||
File.pathSeparator.equals(":"));
ThepathSeparatoristhevalueyouuseinthePATHvariables.
TheseparatorandpathSeparatorreturnsystemdependentvaluessohelpyoumakeyourcodeplatformagnostici.e.runonLinuxorWindows.listRoots
listRootsreturnsanarrayofFileobjectswhichrepresentthe‘root’filepathsinthesystem.File[]roots=File.listRoots();
Onmywindowssystemthisreturnsalistofthe‘drives’onmysystem,e.g.:C:\
D:\
E:\
F:\
G:\
HaveIeverusedthismethod?No.Butitmightcomeinhandyforsomeone.
Exercise:WriteouttherootsWritean@TestmethodwhichprintstoSystem.outtheresultofcallingthegetAbsolutePathmethodoneachoftheFileobjectsreturnedbylistRoots.
ConstructorAndBasicOperationsFileaTempFile=newFile("d:/tempJavaForTesters.txt");
TheabovecodeshowsthesimplestconstructorfortheFileobject.SimplycreateanewFilewiththepathyouwanttouse.
Filewillconvert‘/’to‘\’Notethat,IhaveusedtheLinuxformatforthefilepath,eventhoughIprimarilywrotethebookonaWindowsmachine.
TheFilecanconvertfrom/to\ifyouareworkingonadifferentplatform.
Ifyouwrotean@Testmethodwiththeabovecode,thenuponrunningit,youwillnotethatinstantiatingaFileobject,doesnotcreateaphysicalfileonthedisk.@Test
publicvoidaNewFileDoesNotCreateAFile()throwsIOException{
FileaTempFile=newFile("d:/tempJavaForTesters.txt");
assertThat(aTempFile.exists(),is(false));
}
IusedtheexistsmethodontheFileobjecttocheckexistence.
TheFileobjectcreatesarepresentationofthe‘file’or‘directory’,andallowsustointeractwiththefile.
Weuse‘streams’,‘readers’or‘writers’tointeractwiththeactualfilecontent.
TheFileobjecthasmethodsforfilecreationanddeletion:
createNewFilewillcreatethefiledeletewilldeletethefile
e.g.@Test
publicvoidcreateAFileAndDeleteIt()throwsIOException{
FileaTempFile=newFile("d:/tempJavaForTesters.txt");
assertThat(aTempFile.exists(),is(false));
aTempFile.createNewFile();
assertThat(aTempFile.exists(),is(true));
aTempFile.delete();
assertThat(aTempFile.exists(),is(false));
}
Anotherformoftheconstructorallowsustopassinthefilepathandthefileasseparatearguments.FileaTempFile=newFile("d:","tempJavaForTesters.txt");
NotethatIdon’thavetoworryabouttrailingdirectoryseparatorswhenIusebothparametersintheFileconstructor.
Fileoperationscanthrowavarietyofexceptionsbutthejava.io.IOExceptionisacatchallfortheexceptionsthatarelikelytobethrown.
Inthisshortsectionwecovered:
TwoFileConstructorsexistsmethodtocheckifafileordirectoryexistsdeletetodeleteafileordirectorycreateNewFiletocreateanemptyfile
Exercise:CreateaTemporaryFileWithCustomCodeSimulatethecreateTempFilemethodusingthenormalFileobjectandthecreateNewFilemethod.
Hints:Thesystemtemporarydirectoryisaccessiblefromthe“java.io.tmpdir”Systemproperty.
UseSystem.currentTimeMillistocreatea‘unique’numberaspartofthefilename.
OtherBasicMethodsThebasicmethodsonFileweneedtolearninitiallyare:
deleteOnExit-deletethefilewhentheapplicationclosesgetName-thefilenameordirectorynamegetParent-thepathoftheparentdirectorygetAbsolutePath-thefullfilenameincludingroot,folderhierarchyandfilenameusedtocreatetheFilegetCanonicalPath-theuniquefullrepresentationoftheFilemkdir-createsasingledirectorymkdirs-createsadirectoryandallnecessarydirectoriesinthepath
deleteOnExit
AssoonasyouhaveaFileyoucanaddittothe‘deleteonexit’queue.FileaTempFile=File.createTempFile("prefix","suffix");
aTempFile.deleteOnExit();
Whentheapplicationfinishes.Whenallthe@Testmethodshaverun.Allfilesinthe‘deleteonexit’queuewillbedeleted.
ThisisausefulmethodtocombinewiththecreateTempFilemethodbecauseitmeansyourtemporaryfilesaredeletedaftertherunofthe@Testmethod.Ratherthanrelyingonyouroperatingsystemtemporarydirectorycleanuproutines.
getName,getParent,getAbsolutePath,getCanonicalPath
IfIcreateatempfile:FileaTempFile=File.createTempFile("prefix","suffix");
Idon’tknowexactlywhatthenameofthatfileis.
WhenworkingwiththeFileobjectaTempFile.Idon’tneedtoknowtheactualnamebecauseIoperatewiththeFileobjectdirectly.
IfIdowanttoworkwiththenameorpath,thenIcanusethemethods:
getName,getParent,getAbsolutePathandgetCanonicalPath.
getNamereturnsthefilename,withoutthepath.SofortheexampleaboveIwouldhaveafilenamelikeprefix12345678901234567890suffixcreated.assertThat(aTempFile.getName().startsWith("prefix"),is(true));
assertThat(aTempFile.getName().endsWith("suffix"),is(true));
getParentreturnsthepathstructurefortheparentdirectory.assertThat(aTempFile.getParent()+File.separator,
is(System.getProperty("java.io.tmpdir")));
getAbsolutePathandgetCanonicalPathbothreturnthefullpath,includingthefilenameoftheFile:assertThat(aTempFile.getAbsolutePath().endsWith("suffix"),
is(true));
assertThat(aTempFile.getAbsolutePath().startsWith(
System.getProperty("java.io.tmpdir")),is(true));
assertThat(aTempFile.getCanonicalPath().endsWith("suffix"),
is(true));
assertThat(aTempFile.getCanonicalPath().startsWith(
System.getProperty("java.io.tmpdir")),is(true));
An‘absolute’pathwoulddisplayanyrelativefileoperatorsinthename,e.g.‘../..’but‘canonical’wouldnot.
Canonicalistheuniquepath,soanyrelativeelementsaremadeabsolute.
e.g.thefollowingabsolutepaths:
C:/1/2/3/4/../../..
C:/1/2/../../1
wouldberepresentedasthefollowingcanonicalpath
C:/1
Exercise:Writean@TestmethodToCheckCanonicalConversionWritean@TestmethodwhichcheckstheassertionthattheabsolutepathsbelowarerepresentedbythecanonicalpathC:/1:
C:/1/2/3/4/../../..
C:/1/2/../../1
DothisbycreatingaFileforeachpath.ThencomparingthevaluesfromgetAbsolutePathwithgetCanonicalPath.
mkdirandmkdirs
Bothmkdirandmkdirsareusedforcreatingdirectories.
Bothmkdirandmkdirsreturneithertrueorfalsetoletyouknowiftheymanagedtocreatethedirectory.
Thedifferencebetweenthemisthatmkdirwillcreateasingledirectory,butonlyiftheparentpathalreadyexists.
mkdirswillcreatethenecessaryparentdirectoriestoallowtheoperationtosucceed.
Anexample
IfIwanttocreateadirectorystructureinthetempdirectorylikethefollowing:
%TEMP%1234567890
0987654321
Theexisting%TEMP%directory,withasubdirectory‘1234567890’,andanothersubdirectory‘0987654321’.WhereeachofthesenumbersissupposedtorepresentacalltoSystem.currentTimeMillis()
StringtempDirectory=System.getProperty("java.io.tmpdir");
StringnewDirectoryStructure=tempDirectory+
System.currentTimeMillis()+
File.separator+
System.currentTimeMillis();
FileaDirectory=newFile(newDirectoryStructure);
Acalltomkdirwillfail,becausethemiddledirectory‘1234567890’doesnotexist,andmkdirwillonlycreatethefinaldirectory,inourexample‘0987654321’.mkdirneedstherestofthedirectorystructuretoexist.assertThat(aDirectory.mkdir(),is(false));
Acalltomkdirswillpass,becauseitwillcreateanynecessarydirectoriesinthedirectorystructure.assertThat(aDirectory.mkdirs(),is(true));
UsefulChecks
ForaparticularFileobject,youcancheckifitisafileordirectoryusingthefollowingmethods:
isDirectoryreturnstrueiftheFileobjectisadirectoryisFilereturnstrueiftheFileobjectisafile
Exercise:CheckthattheTempDirectoryisaDirectoryCreateaFileobjectthatrepresentsthetemporarydirectory.System.getProperty("java.io.tmpdir")
AssertthatisDirectoryreturnstrueandisFilereturnsfalse.
WritingAndReadingFiles
WritingTextFilesJavaprovidessomewrapperclasseswhichhidelowerlevelinputandoutputclassestomakereadingandwritingfileseasier.
Yousawtheuseofthoseintheinitialexamplesinthechapter.
FileWriterisawrapperaroundFileOutputStreamforcharacterbasedfiles.e.g.textfiles.BufferedWritermakeswritingmoreefficientbywaitinguntilthebufferisfullandthenflushingthebuffertothewriter.Forfilewritingthisqueuesupthewritingofbytestothefile.PrintWriterprovidesconveniencemethodsforwritinglinestofilesforhumanreadableoutput.e.g.println,print
Forexample:FileoutputFile=File.createTempFile("printWriter",null);
FileWriterwriter=newFileWriter(outputFile);
BufferedWriterbuffer=newBufferedWriter(writer);
PrintWriterprint=newPrintWriter(buffer);
YoucanappendtoexistingfilesbycreatingtheFileWriterwithanappendparametersettotrue.writer=newFileWriter(outputFile,true);
WritingwithaPrintWriter
UsingaPrintWriteristhesameasusingtheSystem.out.printlnthatyouhaveseenthroughoutthebook.
Wecanwritealinetothefilebyusingprintlnprint.println("SimplePrinttoBufferedWriter");
print.println("===============================");
ByusingthePrintWriterandprintlntowritetextfiles,wedon’thavetoworryaboutendoflinecharactersasitwillusetheappropriateendoflineforthesystem.
Youcanalsoaddtothefilewithoutanewlineusingprint.
Justremembertoclosethefilewhenyouhavefinishedwritingtoit.
Exercise:WritetoaPrintWriterthenAppendCreateatempfile.ThenusePrintWritertoprintlntexttothefile.Remembertoclosethefile.
Afteryouhaveclosedit,re-openthefile,bycreatinganewFileWriter.Thistimesettingtheappendparametertotrue.Then:
printlnsomenewlinestothefile.closethefile.manuallyopenthefileinatexteditortocheckthatyourlinewasappendedtothefile.
WritingwithaFileWriter
YoucanwritefilesdirectlywithaFileWriter.FileoutputFile=File.createTempFile("fileWriter",null);
FileWriterfileWriter=newFileWriter(outputFile);
fileWriter.write("SimpleReportWithOutputWriter");
fileWriter.write("===============================");
fileWriter.close();
Sincethisisarawtextwriter,therearenolineendingsaftereachline,astherewerewiththePrintWriter’sprintlnsotheoutputfilewouldlookasfollows:SimpleReportWithOutputWriter===============================
ReadingTextFiles
FileReaderisawrapperaroundInputStreamReaderandFileInputStreamwhichusesthedefaultcharacterencodingstream.BufferedReadermakesthereadingmoreefficient.
UsethereadLinemethodtoreadthenextlinefromthefileintoastring.
IfwehavereachedtheendofthefilethenreadLinewillreturnnull.
AdditionalFileMethodsTheFileobjecthasalotofveryusefulmethodsforaccessingthevariouspropertiesofthefile.
SpaceThefollowingmethodsonfilescanbeusedtofindinformationaboutthesizeofthefile,orthediskthefileislocatedon.
Rememberthelengthcontainstheendoflinecharactersaswell.
length-thelengthoftheFileinbytesgetFreeSpace-numberofbytesoffreespacegetTotalSpace-numberofbytesoftotalspacegetUsableSpace-numberofbytesofusablespace
Exercise:CreateaFileandCalculatethelengthCreateafileandcalculatetheexpectedfilelength.
Hint:UseSystem.lineSeparator()togetthelineendcharacter(s).
DirectoryMethodsForaparticularFilethatrepresentsadirectory.Youcangetalistofthefilescontainedinthedirectory.
listwillreturnalistofthefilenamesasStringlistFileswillreturnalistofFileobjectsrepresentingeverycontainedfileanddirectory
e.g.togetalistofthefilenamesfortheitemsinthetempdirectoryIcouldusethelistmethod:@Test
publicvoidlistTempDirectory(){
FiletempDir=newFile(System.getProperty("java.io.tmpdir"));
String[]fileList=tempDir.list();
for(StringfileInList:fileList){
System.out.println(fileInList);
}
}
Exercise:UselistFilestoshowtheTempDirectorycontentsUsethelistFilesmethodonFiletooutputthenameofeachfileinthetempdirectory.
Foreachfile,alsowritebesideit“DIR:”ifitisadirectoryand“FIL:”ifitisafile.
AttributesYoucancheckandamendthefileAttributeswiththefollowingmethods.
canRead-trueifthefileisreadablecanWrite-trueifthefileiswritablecanExecutetrueifthefileisexecutablelastModified-thelastmodifieddateasalong
Youcansettheaboveattributesusingthemethodsbelow:
setExecutable
setReadable
setWritable
setReadOnly
setLastModified
Exercise:OutputAttributesofFilesInTempDirectoryExtendthe@TestmethodyouwroteforlistFilestoalsooutputtheread,write,executeattributes,andthelastmodifieddate.
FilesFilesispartofthejava.niopackage.niobeingthe“NewIO”classes,introducedinJava1.4;sonotreallythatnewanymore,buttheyaddsomeusefulfunctionalitythatweoftenlookforotherlibrariestomanage.
Theniopackageoffersalotofmethods,butwewillprimarilylookattheFilesmoveandcopymethods.
copy-willcreateacopyofafileordirectorymove-willmoveafileordirectory,creatinganewoneanddeletingtheold
RenamevsMoveFilehasa‘renameTo’method,butItendtousethemovemethodonFiles,evenwhenIwanttorenameafile.
moveandcopycanbeusedtomoveandcopyentiredirectorytrees.
BothmoveandcopyoperateonPathobjectsratherthanFileobjects.FortunatelytheFileobjecthasatoPathmethodwecanusetoreturnaPathobject.Files.copy(copyThis.toPath(),toThis.toPath());
Bothmoveandcopycantakeanoptionalparameterlistwhichspecifiesthe‘copyoptions’.
Thecopyoptionsarecontainedinjava.nio.file.StandardCopyOption.soyouhavetoaddanadditionalimporttoyourclass.importstaticjava.nio.file.StandardCopyOption.*;
Whenyouimportthecopyoptionsyoucanuse:
REPLACE_EXISTING-willallowtheoperationtocompleteevenifdestinationexistsCOPY_ATTRIBUTES-preservethefileattributesduringthecopyATOMIC_MOVE-anyoperatingsystemfollowonfileactionswaittillthemoveiscomplete
Themovebelowusescopyoptions:
Files.move(moveThis.toPath(),toThis.toPath(),
REPLACE_EXISTING,ATOMIC_MOVE);
Exercise:copyAndmoveaFileWriteafiletothetemporarydirectoryandcopyittoanewfilewitha“.copy”suffix.Writeafiletothetemporarydirectoryandmoveittoanewfilewitha“.moved”suffix.
SummaryWehaven’tcoveredallthemethodsavailableforworkingwithfiles.
IrecommendyouusecodecompletionandtheofficialhelpdocumentationtoexploretheclassesavailabletoyouontheJavainputoutputpackages.Doreadthe‘JavaIOOfficialDocumentation’linkedtointheReferencessection.
Themethodsandclasseswecoveredinthischaptershouldgiveyouenoughinformationfortacklingtheinitialproblemsyouwillneedforautomationtosupportyourtesting.
Certainlyyoushouldbearmedwithenoughinformationtoreadandwritetextfiles:eitherforinputdataorforwritingad-hocreports.
Readthepageslinkedtobelow.ThereisarichsetoflibrariesinJavacoreforworkingwithfiles.
AlsointhischapterweconcentratedonworkingwithtextfilessinceIsuspectthatmostofthefilesyouwillhavetoparseandwritewhileautomatingwillbetextfiles.
ReferencesandRecommendedReading
JavaIOOfficialDocumentationdocs.oracle.com/javase/tutorial/essential/io/index.html
JavaFileOfficialDocumentationdocs.oracle.com/javase/7/docs/api/java/io/File.html
JavaFilesOfficialDocumentationdocs.oracle.com/javase/7/docs/api/java/nio/file/Files.html
JavaNiovsJavaIOblogs.oracle.com/slc/entry/javanio_vs_javaio
BufferedWriterdocs.oracle.com/javase/7/docs/api/java/io/BufferedWriter.html
PrintWriterdocs.oracle.com/javase/7/docs/api/java/io/PrintWriter.html
Readingandwritingfilepracticeswww.javapractices.com/topic/TopicAction.do?Id=42
Differentwaysofreadingfilesstackoverflow.com/questions/4716503/best-way-to-read-a-text-file
Copydocs.oracle.com/javase/tutorial/essential/io/copy.html
Movedocs.oracle.com/javase/tutorial/essential/io/move.html
ChapterTwenty-MathandBigDecimal
ChapterSummaryInthischapteryouwilllearnhowtouseadditional‘number’classes:
BigDecimal-aclassthatoffersaccuratemathoperationswithoutrounding,importantforfinancialapplications
subtract-amethodtosubtractavaluefromtheBigDecimaladd-amethodtoaddavaluetotheBigDecimalmultiply-amethodtomultiplytheBigDecimalbythevaluedivide-amethodtodividetheBigDecimalbythevaluevalueOf-astaticmethodtoreturnaBigDecimalrepresentingthesupplieddoubleorlongBigDecimaldoesnotsupport==,!=,<,>etc.insteadusethemethodsequalsandcompareTo
Math-aclassthathasadditionalmethodsforworkingwithfloatanddoublemax-comparetwovaluesandreturnthelargermin-comparetwovaluesandreturnthesmallerabs-returntheabsolutevaluerandom-returnarandomnumber>=0.0and<1.0trigonometricfunctions:sin,cos,tan,asin,acos,atan,toDegrees,toRadians
TheMathclasscanhelpyouwithasetofmethodstohelpyouworkwithdoubleandfloat,sowewilllookatthatclassinthischapter.
Formostofyourautomationyou’llprobablygetawaywithfloatanddouble.Butyouhavetobecarefulasthesetypesuseroundingandapproximationintheircalculations.Theydonotrepresent0.1inaformthatyoucanuseforexactcalculations,forexactoperationsandvaluesyouuseBigDecimal.
e.g.0.10+0.73=0.83
but…floattotal=0.1f+0.73f;
assertThat(total,is(0.83f));
Theabovecodefailswhenpartofan@Testmethodbecause:java.lang.AssertionError:
Expected:is<0.83F>
but:was<0.83000004F>
Withdoubleandfloatyouhavetobecarefulandhandleroundingyourselfthroughoutthecalculationprocess.
OryoucanusetheBigDecimalclass.
YoucouldalsouseintorlongIfyouuseanintthenyoudon’tworryaboutrounding,particularlywhendoingacalculationliketheexamplewhichactuallyrepresents10pence,plus73pence.i.e0.1pounds+0.73pounds.
Icouldhavedonethecalculationinpenniesandbeenfine.
BigDecimalBigDecimalisimportedusingthejava.mathpackage.importjava.math.BigDecimal;
BigDecimalisnotaprimitive,soisalittleclumsiertoworkwith,andwillperformmoreslowlythantheprimitives.BigDecimalbdtotal=newBigDecimal("0.1").add(newBigDecimal("0.73"));
assertThat(bdtotal,is(newBigDecimal("0.83")));
BigDecimalmaintainsthedecimalpointprecision.Particularlyusefulforfinancialcalculations
Soif,asatesterworkinginfinance,youneedtoreadvaluesfromafileandcomparethecalculationsproducedfromsomeothersystem.YouarelikelytouseBigDecimaltoensurethatyourcalculationsareasaccurateasyoucanmakethem.
Youcoulduseintorlongandmanagetheroundingyourself.OrtaketheeasyrouteanduseBigDecimalwhenyouwanttomaintaintheprecision.
JoshuaBloch,theauthorof“EffectiveJava”,summarizesthesituationas“Ifthequantitiesdon’texceedninedecimaldigits,youcanuseint;iftheydon’texceedeighteendigits,youcanuselong.Ifthequantitiesmightexceedeighteendigits,youmustuseBigDecimal”.
Beawareofthechoicesnow,soyoudon’traisedefectsagainstsystemswhenthebugsareactuallyinyourmathcalculationcode.
Exercise:ConvinceYourselfofBigDecimalorintCreatean@Testmethodwhichcalculatestheresultofthefollowingsituation.
(Thereare100pencetothepound,or100centstothedollar)InthisexampleIusepoundsandpence.Feelfreetomentallytranslatethisintoanycurrencyyouwant,justbeawarethatthereare100pencetothepoundwhenyoutranslate.
Istartwith5pounds.Ispend43pence,thenIspend73pence,thenIspend1poundand73pence.
i.e.5-0.3-0.47-1.73
InmyhandIhave2pounds50pence(or2.5pounds).
Howmuchdoesyourdoublehave?Recreatethecodewithint.RecreatethecodewithBigDecimalusingthesubtractmethod.
BigDecimalMethodsConstructor
YoucanconstructaBigDecimalfroma:
int
long
String
double
BigInteger-anunboundedintegere.g.largerthana64bitlong.
BigDecimalfromInt=newBigDecimal(5);
BigDecimalfromLong=newBigDecimal(5L);
BigDecimalfromString=newBigDecimal("5");
BigDecimalfromDouble=newBigDecimal(5.0);
BigDecimalfromBigInteger=newBigDecimal(BigInteger.valueOf(5L));
StaticMethods
BigDecimalprovidessomefactorymethodsforcreatingaBigDecimalobject.
ONE
TEN
ZERO
valueOf-convertadoubleoralongtoaBigDecimal
BigDecimalbd0=BigDecimal.ZERO;
BigDecimalbd1=BigDecimal.ONE;
BigDecimalbd10=BigDecimal.TEN;
BigDecimalbdVal=BigDecimal.valueOf(5.0);
BasicArithmeticMethods
ThebasicarithmeticoperatormethodsonBigDecimalare:
add
subtract
multiply
divide
EachofthesetakesaBigDecimalasargumentandreturnsanewBigDecimalrepresentingtheresultoftheassociatedoperator+,-,*,or/
Exercise:BasicArithmeticwithBigDecimalCreatean@TestannotatedmethodwhichimplementsthefollowingcalculationusingBigDecimalmethods:
aBigDecimal=0
(((aBigDecimal+10)*2)-10)/2)=5
ComparisonOperators
Youcan’tusethenormalcomparisonoperatorsonBigDecimali.e.>,<,==,!=,>=,or<=
YoucanuseequalstocompareBigDecimalobjects.assertThat(BigDecimal.ONE.equals(
newBigDecimal(1.0)),is(true));
assertThat(BigDecimal.ONE.equals(
newBigDecimal("1")),is(true));
YoucanalsousethecompareTomethod:
compareTo(value)returns:-1iftheBigDecimalislessthanvalue,0iftheBigDecimalisequaltovalue,1iftheBigDecimalisgreaterthanvalue
TheofficialdocumentationsuggeststhefollowingusageBigDecimal.TEN.compareTo(BigDecimal.ONE)>0
Whichwouldbeequivalentto:BigDecimal.TEN>BigDecimal.ONE
Exercise:CompareTENandONEWritean@TestannotatedmethodtocompareTENandONE.
Simulatingeachofthecomparisonoperators:
>,<,==,!=,>=,or<=
Followthesuggestedusagepatternabovee.g.>0
UsingBigDecimal
IfyoustartworkingwithBigDecimalthenreadtheofficialdocumentationorusingcodecompletioninyourIDEtoseetheadditionalrangeofmethodsoffered.InthischapterwecoveredasmallsubsetofBigDecimalmethodstohelpyougetstarted,andtohelpyouunderstandthedifferencebetweenBigDecimalandtheearlierprimitivesdoubleandfloat.
BigDecimalsupportsdifferentroundingmethodswhichyoucanuseinconjunctionwiththearithmeticoperations.Youcanalsoprovidea‘scale’toworkatdifferentpowersoften.
JavaalsooffersaBigIntegerobjectinthejava.mathpackagewhichworkswithgreaterthan64bitintegers.Thenormaloperatorsandfunctionsassociatedwithanintorlong,areaccessibleviamethodsonBigInteger.
YoucanalsoconvertfromBigDecimalusingfloatValue,doubleValue,intValue,longValueetc.ThisisusefulwhenyouwanttousesomeofthemethodsintheMathclassafteraseriesofcalculations.
MathThejava.lang.Mathclassprovidesarangeofmathematicalmethodsforworkingwithfloatordouble,andsometimeswithanintorlong.
Theofficialdocumentationliststhesetofmethodsavailablesoyoucanfindtherangeeasilyenoughon-lineorinyourIDE.
Themethodsontheclassareallstatic,soareusedwithoutinstantiatingaMathobject,andyouwillnotneedtoimportthejava.lang.Mathpackage.
e.g.tofindthemaximumoftwovalues:assertThat(Math.max(23.0,42.0),is(42.0));
I’vedescribedasmallsetofmethodsIhavefoundusefulinthepastbelow.
Thefollowingmethodsoperateonint,long,doubleorfloat:
max-comparetwovaluesandreturnthelargermin-comparetwovaluesandreturnthesmallerabs-returntheabsolutevaluerandom-returnarandomnumber>=0.0and<1.0
Youalsohavetrigonometricfunctions:sin,cos,tan,asin,acos,atan,toDegrees,toRadians.
Idonotintendtocoverallthemethodsinthisbook.IsimplywanttomakeyouawareofthebuiltinMathclass.Andnow,whenyoustartworkingwithmathematicalfunctionalityinyourtests,goingbeyondthetypicalarithmeticoperations,youcanexaminetheMathclassinmoredetailtoseeifithasexistingmethodsthatmeetyourneeds.
SummaryThiswasachapterintroducingtwoimportantclassesataveryhighlevel:
BigDecimal
Math
UseBigDecimalwhenworkingwithcurrencyvaluesorwhenyouneedaccuracyinthecalculations,andavoidingrounding.
UseMathwhenyouneedtogobeyondthesimplemathematicaloperators+-*/.
RememberalsotheBigIntegerclasswhenyouneedtoworkwithlargerthan64bitintegervalues.
ReferencesandRecommendedReading
JavaBigDecimaldocs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html
BigIntegerofficialdocumentationdocs.oracle.com/javase/7/docs/api/java/math/BigInteger.html
JavaMathclassofficialdocumentationdocs.oracle.com/javase/7/docs/api/java/lang/Math.html
ChapterTwentyOne-CollectionsRevisited
ChapterSummaryInthischapteryouwillrevisitthecollectionclasses.
CoreCollections-Corecollectioninterfaces:SortedSet-likeaSetbutmaintainsanorder
first-returnthefirstitemlast-returnthelastitemheadSet(e)-returntheelements,beforeelementetailSet(e)-returntheelementsafterandincludingelementesubSet(e1,e2)-theelementsfrom(andincluding)elemente1,to(butexcluding)e2comparator-returntheComparatorobjectusedforcomparisonforsortorder
SortedMap-likeaMapbutmaintainsanorderfirstKey-thefirstkeybasedonthesortorderlastKey-thelastkeybasedonthesortorderheadMap(k)-every“key,value”pairbeforekeyktailMap(k)-every“key,value”pairafterandincludingthekeyksubMap(k1,k2)-every“key,value”pairbetweenk1andk2(includingk1,excludingk2)comparator-thecomparatorusedtodeterminethesortorderofthekeys
Queue-afirstinfirstoutcollectionDeque-addelementseitheratfrontorendbutnotmiddle
CoreImplementations-Corecollectionimplementations:TreeSet-implementsaSortedSetTreeMap-implementsaSortedMap
CoreCollectionInterfacesRevisitedTheofficialdocumentationliststhefollowingastheCoreCollectioninterfaces:
Collection
List
Set
SortedSet
Queue
Deque
Map
SortedMap
ThefollowingtableprovidesasummaryofthekeymethodsontheInterfaces,andIhaveremovedListandaddedtheSortedSetandSortedMapsoyoucanseetheadditionalnuances.:
Collection Set SortedSet Map SortedMap
add(e)AllinCollection
first put(k,v) firstKey
remove(e) last remove(k) lastKey
removeAll(c) headSet(e) entrySet headMap(k)
retainAll(c) tailSet(e) get(k) tailMap(k)
clear subSet(i1,i2) clear subMap(k,k)
contains(e) containsKey(k) containsAll(c) containsValue(v) size comparator size comparator
isEmpty AllinCollection
isEmpty AllinMap
toArray values toArray(a) keySet addAll(c) putAll(m)
where:e==element,c==collection,a==array,i==index,k==key,v==value,m==map
SetWedescribedSetintheearliercollectionchapter.
InthischapterwewillbuildonSetandconsidertheSortedSet.
SortedSet
TheSortedSet,liketheSetstripsoutduplicatesifyoutrytoaddthem.
TheSortedSetalso:
guaranteestheorderoftheelementsbasedonaComparatororthecompareTomethodoftheelements
ThesortingreliesontheelementsinthesettoimplementaComparableinterfacewhichmandatestheimplementationofacompareTomethod.OryoucanprovideaComparatortotheSortedSetimplementationatinstantiation,andtheComparatorknowshowtocomparetheobjects.
FortheexamplesIwillmainlyuseStringbutwillalsoprovideashortoverviewoftheComparator.
first-returnthefirstitemlast-returnthelastitemheadSet(e)-returntheSortedSetofelements,beforeelementetailSet(e)-returntheSortedSetofelementsafterandincludingelementesubSet(e1,e2)-theSortedSetfrom(andincluding)elemente1,to(butexcluding)e2
comparator-returntheComparatorobjectusedforcomparisonforsortorder
WithaSortedSetyoualsohaveaccesstoallmethodsintheCollectioninterface.
WithaSortedSetIusetheTreeSetfromjava.utilasmydefaultimplementation.
Thefollowingexampleshows:
theSortedSetmaintainingtheorderoftheelements,eventhoughIaddedthemoutofordertheSortedSetdoesnotaddtheduplicated"a"element
@Test
publicvoidsortedSetCanMaintainSortOrder(){
SortedSet<String>alphaset=new<String>TreeSet();
alphaset.add("c");
alphaset.add("d");
alphaset.add("a");
alphaset.add("b");
alphaset.add("a");
assertEquals(4,alphaset.size());
String[]alphas=newString[alphaset.size()];
alphaset.toArray(alphas);
assertEquals("a",alphas[0]);
assertEquals("b",alphas[1]);
assertEquals("c",alphas[2]);
assertEquals("d",alphas[3]);
}
Intheabovelisting,IaddtheStringvaluestothealphasetinarandomorder,butwhenIconvertthealphasettoanarray,thearrayhastheStringvaluesinorder.
Also,althoughIaddedtheString"a"twice,itisonlyaddedtothealphasetonce:asevidencedbythesize()methodreturning4,andtheconversiontoarrayonlycontainingtheString"a"once.
firstretrievesfirstelementinsort
WhennewelementsareaddedtotheSortedSet,thesortorderofelementsismaintainedsothatfirstalwaysreturnsthefirstelementinthesetbasedonthesortorder.@Test
publicvoidcanRetrieveFirstFromSortedSet(){
SortedSet<String>alphaset=new<String>TreeSet();
alphaset.add("c");
assertEquals("c",alphaset.first());
alphaset.add("d");
assertEquals("c",alphaset.first());
alphaset.add("b");
assertEquals("b",alphaset.first());
alphaset.add("a");
assertEquals("a",alphaset.first());
}
lastretrieveslastelementinsort
WhennewelementsareaddedtotheSortedSet,thesortorderofelementsismaintainedsothatlastalwaysreturnsthelastelementinthesetbasedonthesortorder.@Test
publicvoidcanRetrieveLastFromSortedSet(){
SortedSet<String>alphaset=new<String>TreeSet();
alphaset.add("c");
assertEquals("c",alphaset.last());
alphaset.add("b");
assertEquals("c",alphaset.last());
alphaset.add("d");
assertEquals("d",alphaset.last());
alphaset.add("a");
assertEquals("d",alphaset.last());
}
headSetsubsetbeforeanelement
Youcancreateasortedsubsetofallelementsinthesetbeforeaspecificelement.SortedSet<String>subset=alphaset.headSet("c");
Theabovestatementwouldreturneveryelementbefore“c”i.e“a”and“b”,asthefullexamplebelowillustrates.@Test
publicvoidsortedSetcanReturnHeadSet(){
SortedSet<String>alphaset=new<String>TreeSet();
alphaset.add("c");
alphaset.add("d");
alphaset.add("b");
alphaset.add("a");
SortedSet<String>subset=alphaset.headSet("c");
assertEquals(2,subset.size());
String[]alphas=newString[subset.size()];
subset.toArray(alphas);
assertEquals("a",alphas[0]);
assertEquals("b",alphas[1]);
}
tailSetsubsetafter,andincluding,anelementSortedSet<String>subset=alphaset.tailSet("c");
ThetailSetcreatesasubset,butthistimethesetofallelementsinthesetwhicharegreaterthanorequaltotheelement,sothesubsetalsoincludestheelementitself.
Thisisillustratedbytheexamplebelow:@Test
publicvoidsortedSetcanReturnTailSet(){
SortedSet<String>alphaset=new<String>TreeSet();
alphaset.add("c");
alphaset.add("d");
alphaset.add("b");
alphaset.add("a");
SortedSet<String>subset=alphaset.tailSet("c");
assertEquals(2,subset.size());
String[]alphas=newString[subset.size()];
subset.toArray(alphas);
assertEquals("c",alphas[0]);
assertEquals("d",alphas[1]);
}
subSetbetweentwoelementsSortedSet<String>subset=alphaset.subSet("b","d");
ThesubSetcontainsasubsetfrom,andincluding,thefirstelementargument,to,butexcludingthesecondelementargument.e.g.given"a","b","c","d"thenasubSet("b","d")wouldbefromandincluding“b”,to(butexcluding)"d",giving"b","c".
Thisisillustratedbytheexamplebelow:@Test
publicvoidsortedSetcanReturnSubSet(){
SortedSet<String>alphaset=new<String>TreeSet();
alphaset.add("c");
alphaset.add("d");
alphaset.add("b");
alphaset.add("a");
SortedSet<String>subset=alphaset.subSet("b","d");
assertEquals(2,subset.size());
String[]alphas=newString[subset.size()];
subset.toArray(alphas);
assertEquals("b",alphas[0]);
assertEquals("c",alphas[1]);
}
comparatorusedforsorting
comparatorreturnstheComparatorobjectwhichtheSortedSetisusingforcomparisons.
ThereforeweshouldlearnhowtocreateaComparator.
IhavechosentoexpandonComparatorbutnothashSetandequalsbecauseIthinktheComparatoroffersmorere-usepotentialandlikelihoodofyouimplementingit.
ToillustratethisfunctionalitywearegoingtocreateaSortedSetoftheUserdomainobjectthatwecreatedearlier.
Wedidn’taddacompareTomethodtothatobject,nordidwecreateequalsorhashCode.
Intheexamplebelow,ourfirstattemptatcreatingaSortedSetofUserobjectswouldfailwithaClassCastException.TheClassCastExceptionwouldbethrownassoonaswetrytoaddtheUsernamed"Bob"totheSortedSet.BecauseourUserobjectdoesnotimplementtheComparableinterface.Userbob=newUser("Bob","pA55Word");//11
Usertiny=newUser("TinyTim","hello");//12
Userrich=newUser("Richie","RichieRichieRich");//22
Usersun=newUser("sun","tzu");//6
UsermrBeer=newUser("Stafford","sys");//11
SortedSet<User>userSortedList=newTreeSet<User>();
userSortedList.add(bob);
OurimmediatethoughtmightbetoimplementtheComparableinterfaceontheUserclass.Butsometimeswedon’thavecontroloveralltheclassesweuse,andsometimeswedon’twanttoimplementthatinterfaceforallourdomainobjects.Wemightonlywanttosortthemonceortwice.
CreatingacustomComparatorcanbeveryuseful.Alsowemightwanttosortthemindifferentways,atdifferenttimes,andembeddingthecomparisoncodeintheobjectitselfmightnotgiveusthatflexibility.
InthisbookIwilltaketheapproachofcreatingaUserComparator.TheUserComparatorisaclasswhichwillcompareUserobjects.
Inthe@TestmethodwhereIwanttocreatetheSortedSetIinstantiatetheTreeSetasfollows:SortedSet<User>userSortedList=newTreeSet<User>(newUserComparator());
HereIcreateanewUserComparatorandpassitasanargumenttotheTreeSetconstructor.ThisprovidesflexibilitybecauseifIwanttosortorcomparetheobjectsindifferentwaysthenIcouldconstructtheTreeSetwithadifferentComparatorobject.
SothatyouunderstandthecomparisonthatIwanttouse,Iwillshowyouthefullmethodcode:@Test
publicvoidsortedSetWithComparatorForUser(){
Userbob=newUser("Bob","pA55Word");//11
Usertiny=newUser("TinyTim","hello");//12
Userrich=newUser("Richie","RichieRichieRich");//22
Usersun=newUser("sun","tzu");//6
UsermrBeer=newUser("Stafford","sys");//11
SortedSet<User>userSortedList=
newTreeSet<User>(newUserComparator());
userSortedList.add(bob);
userSortedList.add(tiny);
userSortedList.add(rich);
userSortedList.add(sun);
userSortedList.add(mrBeer);
User[]users=newUser[userSortedList.size()];
userSortedList.toArray(users);
assertEquals(sun.getUsername(),users[0].getUsername());
assertEquals(bob.getUsername(),users[1].getUsername());
assertEquals(mrBeer.getUsername(),users[2].getUsername());
assertEquals(tiny.getUsername(),users[3].getUsername());
assertEquals(rich.getUsername(),users[4].getUsername());
}
Iwantthesortordertobebasedonthelengthoftheusername+thelengthofthepassword.ThisisthealgorithmthattheUserComparatorwillimplement.
YoucanseethatIhaveaddedthelengthsascommentsaftereachoftheUserinstantiationssothatIknowwhattoasserton.
Therestofthecodeisprettysimple:
createtheUserobjectsinstantiateaSortedSetwiththeUserComparatorconvertthesettoanarraysothatwecanassertontheexpectedorder
ThenextstepistocreatetheComparator.
Iwillcreateitinthesrc\main\javabranchasI’llprobablyreuseitinmoreplaces.AndI’lladdittothecom.javafortesters.domainentitiespackage.
Thisisthefirstclassyouareseeinguscreatewhichimplementsaninterface.InthisexamplewewillimplementtheComparatorinterface:publicclassUserComparatorimplementsComparator{
Inordertosatisfythisinterface,IhavetoimplementacomparemethodwhichtakestwoObjectasarguments,andreturnsanint:publicintcompare(ObjectoUser1,ObjectoUser2){
Theinthastocorrespondto:
0ifthetwoobjectsareequalinthetermsofthesortingalgorithmnegative-veifobject1islessthanobject2positive+veifobject1isgreaterthanobject2
SincetheargumentshavetobeoftypeObjectweneedtocasttheminthecodetothecorrecttype,whichforusisUser:
Useruser1=(User)oUser1;
Useruser2=(User)oUser2;
Implementthealgorithmdecidedupontohelpmecomparethetwovalues:intuser1Comparator=user1.getPassword().length()+
user1.getUsername().length();
intuser2Comparator=user2.getPassword().length()+
user2.getUsername().length();
Thencalculatethereturnintintval=user1Comparator-user2Comparator;
Great.Andallofthatimplementsthesortingalgorithm.TheproblemisthatSortedSetalsousestheComparatortodecideifthevaluesintheSortedSetareunique.AndtheimplementationabovewouldnotletmeaddanyUserintotheSortedSetwheretheusername+passwordlengthisthesame.
InthecodeaboveIwouldfailtoaddmrBeerbecausehehasthesamelengthasbob.AndIwantmrBeerintheSortedSet.
BeerIdon’tactuallyliketodrinkbeer.InfactIcan’tstandthestuff.Imuchprefertodrinkwine.ButIdolovethebooksofMrStaffordBeer.AparticularlysplendidSystemsThinkerandCybernetician.Ifyougetthechance,readhiswork.
IhavetoaddonelittleadjustmenttotheComparatortoallowforduplicatelengths,butIwillexcludeduplicatelengthswithaduplicateusernamefromtheSortedSet.ThiswouldstillallowinUserswithduplicatenames(providedtheyhavedifferentlengthpasswords)butthatisfineforthiscomparisonalgorithm.if(val==0){
val=user1.getUsername().compareTo(user2.getUsername());
}
Andwiththatwecanreturnval;
ThefullcodefortheUserComparatorwhichallowsthe@Testmethodtocompleteisbelow:publicclassUserComparatorimplementsComparator{
publicintcompare(ObjectoUser1,ObjectoUser2){
Useruser1=(User)oUser1;
Useruser2=(User)oUser2;
intuser1Comparator=user1.getPassword().length()+
user1.getUsername().length();
intuser2Comparator=user2.getPassword().length()+
user2.getUsername().length();
intval=user1Comparator-user2Comparator;
if(val==0){
val=user1.getUsername().compareTo(user2.getUsername());
}
returnval;
}
}
Exercise:Removeif(val==0)Removetheif(val==0)blockofcodeandrunthe@Testmethod.Ensurethatyouunderstandwhyweaddedthatlineofcode.
Exercise:DisallowDuplicateUserNamesCreateaDupeUserComparatorwhichimplementsthelengthcheckasabove,butalsodoesnotallowUserwithaduplicateusernametobeaddedtotheSortedSet.
Useitinan@Testannotatedmethodtodemonstrateitworks.
Exercise:UserclassimplementsComparableAddcodetotheUserclasssuchthatitimplementsComparablewiththealgorithmfordisallowingaUserwithduplicateusernameaswellasthelengthcheckinthecompareTomethod.
Useitinan@Testannotatedmethodtodemonstrateitworks.
Exercise:SeethesortinactionAddthelineofcodebelow,toyourComparator.JustbeforethereturnvallineandseetheComparatorinactioninyourconsole.
System.out.println("Compare"+user1.getUsername()+
"with"+user2.getUsername()+"="+val);
Set&SortedSetDocumentation
YoucanfindthedetailsofSetandSortedSetontheofficialdocumentationsite.
Interface:
docs.oracle.com/javase/tutorial/collections/interfaces/set.htmldocs.oracle.com/javase/tutorial/collections/interfaces/sorted-set.html
Implementation:
docs.oracle.com/javase/tutorial/collections/implementations/set.html
MapWedescribedMapintheearliercollectionchapter.
InthischapterwewillbuildonMapandconsidertheSortedMap.
SortedMapSortedMapistoMap,asSortedSetistoSet.AndtheinterfaceandfunctionofthemethodsofSortedMaparealmostthesameasSortedSet.Soitwon’ttakelongforyoutofigureouthowSortedMapworks.
ASortedMapisorderedonitskeys,notitsvalues.Thecomparatorisusedtodeterminetheordering,orthecompareTomethodonthekey
ThemethodsshouldbefamiliarastheyarealmostthesameasSortedSet
firstKey-thefirstkeybasedonthesortorderlastKey-thelastkeybasedonthesortorderheadMap(k)-theSortedMapcontainingevery“key,value”pairbeforekeyktailMap(k)-theSortedMapcontainingevery“key,value”pairafterandincludingthekeyksubMap(k1,k2)-theSortedMapcontainingevery“key,value”pairbetweenk1andk2(includingk1,excludingk2)comparator-thecomparatorusedtodeterminethesortorderofthekeys
Forthesakeofbrevity,sincewecoveredtheSortedSetindetail,andSortedMapismuchthesame,IwilluseexamplestoexplainSortedMapratherthanalotofdescriptivetext.AlltheexamplesfortheSortedMapmethodsusethefollowingMapdeclarationandinstantiation:SortedMap<String,String>map=newTreeMap<>();
map.put("key1","value1");
map.put("key3","value3");
map.put("key2","value2");
map.put("key5","value5");
map.put("key4","value4");
firstKey&lastKeytoretrievekeylimits
firstKeyandlastKeyrespectivelyreturnthefirstandlastkeysinthemap:assertEquals("key1",map.firstKey());
assertEquals("key5",map.lastKey());
CreatesortedextractswithheadMap,tailMapandsubMap
headMap(k)returnsaSortedMapcontainingeverykey,valuepairbeforethekeypassedasargument.e.g.SortedMap<String,String>headMap;
headMap=map.headMap("key3");
assertEquals(2,headMap.size());
assertTrue(headMap.containsKey("key1"));
assertTrue(headMap.containsKey("key2"));
tailMap(k)returnsaSortedMapcontainingeverykey,valuepairafterandincludingthekeypassedasargument.e.g.SortedMap<String,String>tailMap;
tailMap=map.tailMap("key3");
assertEquals(3,tailMap.size());
assertTrue(tailMap.containsKey("key3"));
assertTrue(tailMap.containsKey("key4"));
assertTrue(tailMap.containsKey("key5"));
subMap(k,k)returnsaSortedMapcontainingeverykey,valuepairafterandincludingthekeypassedasfirstargumentandbefore,butexcluding,thekeypassedassecondargument.e.g.SortedMap<String,String>subMap;
subMap=map.subMap("key2","key4");
assertEquals(2,subMap.size());
assertTrue(subMap.containsKey("key2"));
assertTrue(subMap.containsKey("key3"));
comparatorforsorting
ThecomparatorusageforSortedMap,differsfromSortedSetonlybecausethekeyissortedandnotthevalue(orelement).
WheneverIhaveusedaSortedMap,mykeystypicallyareStringsandsonaturalsortorderisnormallyadequate.
AMapcanuseanyobjectasthekey,soIhaveusedthesameexamplefromSortedSettoillustratethecomparatoronSortedMap.EventhoughthisrepresentsafairlyobtuseuseoftheMap.
InthisexampleyoushouldimaginethattheUseristhekeyandthevalueisadescriptionoftheUser
IinstantiatetheSortedMapwiththeUserComparatorasIdidwithSortedSet:SortedMap<User,String>userSortedMap=
newTreeMap<User,String>(newUserComparator());
ThentherestofthecodeisthesameasSortedSet
createabunchofUserobjectsinstantiatetheSortedMapputalltheUserobjectsintotheMapasthekey,andaddadescriptionasthevalueextractthekeystoanarray-theywillbeinthesortorderspecifiedbythecomparator
assertonthesortorder
@Test
publicvoidsortedMapWithComparatorForUser(){
Userbob=newUser("Bob","pA55Word");//11
Usertiny=newUser("TinyTim","hello");//12
Userrich=newUser("Richie","RichieRichieRich");//22
Usersun=newUser("sun","tzu");//6
UsermrBeer=newUser("Stafford","sys");//11
SortedMap<User,String>userSortedMap=
newTreeMap<User,String>(newUserComparator());
userSortedMap.put(bob,"Bobrules");
userSortedMap.put(tiny,"TinyTime");
userSortedMap.put(rich,"RichRichie");
userSortedMap.put(sun,"WarfareArt");
userSortedMap.put(mrBeer,"Cybernetician");
User[]users=newUser[userSortedMap.size()];
userSortedMap.keySet().toArray(users);
assertEquals(sun.getUsername(),users[0].getUsername());
assertEquals(bob.getUsername(),users[1].getUsername());
assertEquals(mrBeer.getUsername(),users[2].getUsername());
assertEquals(tiny.getUsername(),users[3].getUsername());
assertEquals(rich.getUsername(),users[4].getUsername());
}
MapKeySetExploredkeySetreturnsaSetwhereeachelementisakeyfromtheMap:Set<String>keys=map.keySet();
IcouldusethistocreateaSortedSetofkeys:SortedSet<String>keys=newTreeSet<String>(map.keySet());
Exercise:AccessValuesinaMapinKeyorderCreateaMapUseaSortedSetforthekeystoiteratethroughtheMapinkeyorder.
Map&SortedMapDocumentationYoucanfindthedetailsofMapandSortedMapontheofficialdocumentationsite.
Interface:
docs.oracle.com/javase/tutorial/collections/interfaces/map.htmldocs.oracle.com/javase/tutorial/collections/interfaces/sorted-map.html
Implementation:
docs.oracle.com/javase/tutorial/collections/implementations/map.html
Queue&Deque
I’mnotgoingtogointodetailontheQueueandDeque(deck).SimplybecauseI’veneverhadtousethemintherealworld.
AQueueprovidesafirstin,firstoutcollection.Whereyouaddelementsatthebackofthequeueandremovethemfromthefront.
ADequeallowsyoutoaddelementsatthefrontorbackofthequeue,butnotthemiddle.
Itisworthknowingthatthesecollectiontypesexist,butifyouneedtousethem,I’msureyou’llnowbeabletounderstandthedocumentationontheofficialsite.
Queue&DequeDocumentation
YoucanfindthedetailsofQueueandDequeontheofficialdocumentationsite.
Interface:
docs.oracle.com/javase/tutorial/collections/interfaces/queue.htmldocs.oracle.com/javase/tutorial/collections/interfaces/deque.html
Implementation:
docs.oracle.com/javase/tutorial/collections/implementations/queue.htmldocs.oracle.com/javase/tutorial/collections/implementations/deque.html
ImplementationsYouhaveseeninthelistingsabovetheImplementationsIused.
ForcompletenessI’velistedbelowtheimplementationsforthevariousCollectioninterfacesthatwecoveredinbothchapters.
Collection&List:ArrayList
Set:HashSet
TreeSet-forsortedMap:
HashMap
TreeMap-forsortedonkeys
PeriodicallyIhavehadtocallupontheConcurrentHashMapinjava.util.concurrentwhenIwaswritingcodetoshareobjectsinmemoryacross@Testmethodsrunninginparallel.Ididn’tknowabouttheConcurrentHashMapbeforeIstarted.ButIknewaboutcollections,andIknewIneededsomethingtoworkconcurrentlysoIdidafewInternetsearchesandfoundthecollection.
WhatI’mreallysuggestingintheaboveparagraphisthatyoulearnafewclassestostartwith.Then,ifyouhavetime,lookaroundatothers,orwaituntilyouneedone.You’llknowyouneedanewimplementationbecauseyouarehavingtocodeworkaroundswith
yourexistingimplementation,andchancesaresomeoneelsehasalreadyexperiencedyourproblem,andwrittenaclasssosolveit.Youjustneedtohuntitout.
SummaryTheSortedMapandSortedSetrequirealittleextrawork-specificallytheimplementationofaComparatororanObjecttoimplementComparable.
Inpractice,IdefaulttoimplementingComparatorObjectsasthisgivesmemoreflexibilityandIdon’thavetocluttermydomainobjectswiththeComparableinterface.
ReferencesandRecommendedReading
SortedSetInterfacedocs.oracle.com/javase/tutorial/collections/interfaces/set.htmldocs.oracle.com/javase/tutorial/collections/interfaces/sorted-set.html
SortedSetImplementationdocs.oracle.com/javase/tutorial/collections/implementations/set.html
SortedMapInterfacedocs.oracle.com/javase/tutorial/collections/interfaces/map.htmldocs.oracle.com/javase/tutorial/collections/interfaces/sorted-map.html
SortedMapImplementationdocs.oracle.com/javase/tutorial/collections/implementations/map.html
QueueandDequeInterfacedocs.oracle.com/javase/tutorial/collections/interfaces/queue.htmldocs.oracle.com/javase/tutorial/collections/interfaces/deque.html
QueueandDequeImplementationdocs.oracle.com/javase/tutorial/collections/implementations/queue.htmldocs.oracle.com/javase/tutorial/collections/implementations/deque.html
ChapterTwentyTwo-AdvancingConcepts
ChapterSummaryThischapterprovidesabriefoverviewofeachofthefollowingareas,withlinksforyoutostartconductingyourownresearchonthetopic.
InterfacesAbstractClassesGenericsLoggingEnumRegularExpressionsReflectionAnnotationsDesignPatternsConcurrencyAdditionalFileconsiderations
Andwearealmostfinishednow.
TheoriginalintentbehindthisbookwastocoverthebasicsofJavathatyouneedtounderstand,inanorderthatallowedyoutousetheconceptsquickly,withoutbeingdistractedbytoomuchadditionaloverhead.
Thischapterprovidesanoverviewof‘advancing’conceptswhicharenotnecessarilyrequiredtobefunctionalinJava,butitisimportanttoknowtheyexist,andgiveyousomethingtoresearchinyournextsteps.
Youprobablywon’tneedtheseconceptsforwritingsimpleJUnittests.
Youmayneedthesewhenyoustartbuildingalotofcodethathastohangtogetherwell,andwhentheJavacodeitselfneedstoembodygooddesignprinciples.
Forthefirst3or4yearsofmywritingautomationcode,Iprobablydidn’tuseanyoftheseconceptsverymuchatall.
Iusedcompositiontore-usecode,withoutusingInterfaces.IrarelyusedInheritance.IneverusedAbstractClasses.Ididn’treallyknowwhatanenumwasetc.
Mycodewassimple,butdidn’thavedesignprinciplesholdingittogether.WhichiswhyIthinkoftheseas“AdvancingConcepts”.
Theyarenot‘advanced’sincetheyarefundamentaltothewaythatJavaandgoodprogrammingworks.Butintermsofyourusageofthem,theyonlyneedtobecome
relevantwhenyouare“Advancing”yourunderstandingofJavaandtherobustnessofyourabstractionlayers.
InterfacesInearliersectionsofthebookweusedInterfaceswithoutactuallyexplainingmuchaboutthem.
AnInterfacedeclaresasetofmethodsthataClassmustimplement.Anywhereinourcodethatweonlywanttousethesetofinterfacemethods,wecancastobjectstotheinterface,ordeclareobjectsas,thatinterface,ratherthanworkingwithconcreteclasses.
e.guseaListratherthananArrayList
Eachobjectthatimplementsaninterfacethenhasfreedomtodecidehowtoimplementthemethodsonthatinterface,suchthattheyareappropriatetothatparticularobject.
ItendtointroduceinterfacesintomycodewhenIstarttoseesimilarusagepatternsoftheobjects.
Asanexample.WhenautomatingawebsiteImightcreateobjectstorepresenteachPageonthesite.Pagesonthesitetendtohavesimilarcomponentse.g.headerorfooter.EarlyinmycodeImighthaveagetHeadermethodonsomepages,butnotothersandImighthaverepeatedcodeasaresult.
WhenIspotthis,IcancreateaninterfacecalledHasHeaderandthismightforcethepagetoimplementthegetHeadermethod.AndIcanwritemethodsthatoperateonaHeaderofapagewhichtakeaHasHeaderinterfaceasaparameterinsteadofindividualpageobjects,orangenericObject.
ResearchInterfacessoyouunderstandtheircapabilities.Andusethemtohelpyouorganizeyourabstractionlayers.
ResearchLinks:
InterfaceDefinitiondocs.oracle.com/javase/tutorial/java/concepts/interface.html
HowtocreateanInterfacedocs.oracle.com/javase/tutorial/java/IandI/createinterface.html
AbstractClassesAbstractclassesareclasseswhichyoucanextend,butcan’tinstantiatedirectlysincenotallthemethodsintheAbstractclasswillhavebeenimplementedintheAbstractClass.
IrarelyuseAbstractClasses.Itendtouseinterfacesanddelegateouttootherconcreteclasses.IdothisbecauseIknowthatmyautomationabstractionsarelikelytochangefrequentlyandIneedalotofflexibilityinmycode.
ResearchLinks:
AbstractClassesOfficalDocumentationdocs.oracle.com/javase/tutorial/java/IandI/abstract.html
AbstractClassesvs.Interfacesjavaworld.com/javaqa/2001-04/03-qa-0420-abstract.html
GenericsInthemainbodyofthisbookyousawGenericsusedwheninstantiatingCollectionsandwedeclaredthetypeofobjectsthatthecollectionwouldhold.
YoucanuseGenericswhencreatingyourownobjectsandmethods,suchthatyoudon’tknowexactlywhatobjecttheywilluse.
Thisisaverypowerfulcodingstyle,tomakeyourautomationabstractionsflexible,butonethatItendnottohavetouseveryoften.
ResearchLinks:
OfficialJavaTutorialonGenericsdocs.oracle.com/javase/tutorial/java/generics
LoggingWedidn’tcoverlogginginthisbook.TheclosestwecamewaswritinginformationouttoaFile,andusingSystem.out.printlntooutputtotheconsole.
FormostofmyautomationcodeIcangetawaywithwritinglogmessagestoSystem.outsincetheywillbedisplayedincontinuousintegrationsystems,andwerarelyhavetoconfigurethelevelofloggingwhenrunningautomation.
Javaloggingallowsyoutowritecodethatoutputslogmessagese.g.warnings,errors,etc.Thelevelofloggingoutputwhenrunningthecodecanbeconfiguredexternallytotheapplicationbytheuserrunningtheapplication.
Whenyouneedthislevelofflexibility,itistimetolearnaboutloggingframeworks.
Javahasabuiltinloggingframework.Andalotofexternalframeworkswhichincreasetheeaseofuse,orflexibilityofconfiguration.
ResearchLinks:
OfficialJavaLoggingOverviewdocs.oracle.com/javase/7/docs/technotes/guides/logging/overview.html
TutorialbyLarsVogelvogella.com/articles/Logging/article.html
EnumAnenumcanbethoughtofasasetofpredefinedconstants.Usefulwhenorganizingconstantsinyourabstractionlayers.
Anenumcanbeusedastheargumentinaswitchstatement.Thiscanleadtoreadableandsimplecode.
Theseconstantscanalsohavemethodsmakingthemveryflexible,andmightevenremovetheneedtoputtheminaswitchstatement,andinsteadusetheenum’smethoditself.
ResearchLinks:
OfficialEnumdocumentationdocs.oracle.com/javase/tutorial/java/javaOO/enum.html
RegularExpressionsWebrieflytoucheduponregularexpressionsinthemaintext.
RegularExpressionsprovideamassiveamountofpowerandflexibilityforparsingandprocessinginput.
Whenyourcodestartstolookcomplicated,andyouhaveaseriesofnestedifstatements,orcomplicatedtransformations.ThenitmightbetimetograduatetotheuseofRegularExpressions.
ResearchLinks:
docs.oracle.com/javase/tutorial/essential/regex/
ReflectionMostofourprogrammingworkusesspecificobjects,andweknowthemethodsandinterfacesavailableatthetimeofcoding.
Reflectionmeansqueryingtheclassatruntimetofindoutinformationabouttheobject,e.g.findingoutwhichmethodsareontheobject,whataretheirparameters,whatannotationsexistetc.
Youcanalsoamendthemethodsignaturestoallowyoutocallprivatemethods,oraccessprivatevariablesetc.
MostprogrammersIknowspurnreflection.Andindeedmostofthetimeinanapplicationitisn’tused,itcanbeslow,anditcanbedangeroustoperformtheseactionsatRuntime.
SomeoftheproblemsI’vefacedinthepasthowever,couldonlybesolvedusingreflection:
TryingtouselibrarieswithoutdocumentationUsingpiecesoffunctionalityoutofsequenceWorkingaroundlimitationsinabstractionlayers
Someofthetoolsweusee.g.JUnit,canonlyworkbecauseofreflection,andalltheannotationsyouaddedtoyourcodeareaccessedviareflection.
Learnaboutreflectionsothatyouknowwhatitiscapableof.Thenyoucantryanduseitwhenyouencounteraproblemthatyouseenootherwaytosolve.
ResearchLinks:
docs.oracle.com/javase/tutorial/reflect
AnnotationsYouusedannotationswhenyouput@Testatopyourmethodcode.
Annotationsaremeta-data.MeaningtheyareusedbythecompilerandwhenyourcodeisaccessedatruntimeusingReflection.
IhaveinthepastusedannotationswhentryingtofindwaysofreportingonexecutioncoverageandcreatingcustomJUnitrunners.
Importanttoknowabout,butIimagineyouwillnotusethemveryoften.
ResearchLinks:
docs.oracle.com/javase/tutorial/java/annotations
DesignPatternsDesignPatternsarethosestatementsthatyouhearontheprojectthateveryoneassumesthateveryoneelseunderstandsandneverexplains,e.g.
SingletonObserverVisitorFactoryProxyetc.
Thesearecommonapproachestosolvingcommonproblems.Thefamousbook“DesignPatterns”byGamma,Helm,JohnsonandVlissideslists23commonpatternsandsomesolutions.
Somefamiliaritywiththemisimportantbecausetheyofferapproachestoproblemsthatotherpeoplehavesolved.Theywillalsohelpyouunderstandwhatdevelopersaretalkingaboutwhentheyexplaintheircodetoyou.
ResearchLinks:
c2.com/cgi/wiki?DesignPatternsBookoodesign.com/
ConcurrencyConcurrencyisimportantinJava.Itallowsyoutoruncodeinmultiplethreadsandpotentiallyachievesomeresultsfaster,orrunmorethanone@Testmethodatthesametime.
Youwilloftenreadthatcertainclassesarenot“ThreadSafe”whichmeanstheyshouldnotbeusedwhenyoutryanduseconcurrency.
Therearedifferentapproachestoconcurrency,rangingfromsimpleuseofsynchronizedwhichmeansthatamethodcanonlybecalledbyasinglethreadatatime.Tofullnon-blockingconcurrency.
Thistopicisfartoadvancedforthisbook.Unfortunatelymanytesterstryandtacklethissubjectearlybecausetheywanttoruntheir@Testmethodsinparallel.Oftenbeforethereisevenacompellingneedtoruntheautomationchecksinparallel.
ConcurrencyisaveryinterestingpartofJavatostudy,andIhavehadtocreateautomationabstractionsthatwereusableinamulti-threadedmanner.ButnotearlywhenIwaslearningJava.Irecommendyoureadaboutit,butdon’ttryanddoanyconcurrentprogramminguntilyouareverycomfortableunderstandinghowyourapplicationworks.Otherwiseyoumaycreatecodethatfailsintermittentlythatishardtodebugandfix.
IprimarilyaddedConcurrencyinthissectiontowarnyouofftryingtouseittooquickly.
ResearchLinks:
docs.oracle.com/javase/tutorial/essential/concurrency
AdditionalFileconsiderationsInthefilechapterIskippedoveralotofinformation,totryandcreateexamplecodeandbasicinformationthatwillcovermanyofyourinitialfileprocessingneeds.
IalsocoveredmostofthethingsthatIusefilesfor.Irarelyhavetoworkwiththebasicfilebuildingblocks:streamsandchannels.
IrarelyworryaboutFileencoding,becausemostofmyfilesarecreatedandreadfromwithinthesameJUnittestclass,andbecausetheyaretemporary,theygetdeletedafterthe@Testmethodsfinish.
Iincludethelinksbelowasresearchitemsincaseyouneedtheminyourenvironment.
ResearchLinks:
Streamsdocs.oracle.com/javase/tutorial/i18n/text/stream.html
FileIOdocs.oracle.com/javase/tutorial/essential/io/file.html
SummaryIknowthischapterhasveryfewexamples.ThemainpurposewastomakeyouawareofadditionalareasoffunctionalityavailableinJava.
Ididnotexplainanyindetailbecauseeachareareasthatcouldhaveentirebooksdedicatedtothem,andinsomecasesbooksdoexistdedicatedtothem,andImentionsomeofthosebooksinthenextchapter.
I’vetriedtomakeyouawareofthecircumstancesthatwillleadyoutousingtheconcepts.ButIhopeyoufollowandreadtheprovidedresearchlinkssoyouhaveabasicmemoryofthecapability,evenifyouhaven’tusedit,ordon’tyetunderstandit.
ChapterTwentyThree-NextSteps
ChapterSummaryThischapterwillprovideyouwitharecommendedsetofnextsteps:
RecommendedReadingListRecommendedVideosRecommendedWebSitesRecommendedNextSteps
Ihopethatifyoumadeitthisfarintothebook,thatyouattemptedtheexercises.Ifyoudid,andyoufollowedthesuggestionspepperedthroughoutthebook,thenyounowhaveagraspofthefundamentalsofwritingJavacode.Thischaptersuggestsbooksandwebsitestovisittohelpyoucontinuetolearn.
Certainlyyou’veseenalotofcodesnippets.Mostofthecodeyouhaveseenhasbeenwrittenintheformof@Testannotatedmethodswithassertions.Prettymuchwhatyouwillbeexpectedtowriteintherealworld.
RecommendedReadingIdon’trecommendalotofJavabooksbecausetheyareaverypersonalthing.TherearebooksthatpeopleraveaboutthatIcouldn’tgetmyheadaround.AndtherearethosethatIlovethatotherpeoplehate.
ButsinceIhaven’tprovidedmassivecoverageoftheJavalanguage.I’veprettymuchgivenyou“justenough”togetgoingandunderstandthecodeyouread.I’mgoingtolisttheJavabooksthatIgainedmostfrom,andstillreferto:
“EffectiveJava”byJoshuaBloch
“ImplementationPatterns”byKentBeck
“GrowingObject-OrientedSoftware,GuidedbyTests”bySteveFreemanandNatPryce
“CoreJava:Volume1-Fundamentals”byCayS.HorstmannandGarryCornell
“CovertJava:TechniquesforDecompiling,PatchingandReverseEngineering”byAlexKalinovsky
“JavaConcurrencyinPractice”byBrianGoetz
“MasteringRegularExpressions”byJeffreyFriedl
Now,tojustifymyselections…
EffectiveJava“EffectiveJava”byJoshuaBloch,atthetimeofwritinginits2ndEdition.Thisbookworksforbeginnersandadvancedprogrammers.
Javadevelopersbuildupalotofknowledgeabouttheirlanguagefromotherdevelopers.“EffectiveJava”helpsshortcutthatprocess.
Ithas78chapters.Each,fairlyshort,butdenseintheircoverageandpresentation.
WhenIfirstreadit,Ifounditheavygoing,becauseIdidn’thaveenoughexperienceorknowledgetounderstanditall.ButIre-readit,andhavecontinuedtore-readitoverthetimeIhavedevelopedmyJavaexperience.AndeachtimeIreadit,Ifindanewnuance,oradeeperunderstandingoftheconcepts.
Becauseeachchapterisshort,Ireturntothisbooktorefreshmymemoryofcertaintopics.
Thiswasalsothebookthathelpedmeunderstandenumwellenoughtousethemandhelpedmeunderstandconcurrencywellenoughtothenread,andunderstand,“JavaConcurrencyinPractice”.
Irecommendthatyoubuyandreadthisbookearlyinyourlearning.Evenifyoudon’tunderstanditall,readitall.Thencomebacktoitagainandagain.ItconcentratesonverypracticalaspectsoftheJavalanguageandcanboostyourreal-worldeffectivenesstremendously.
Youcanfindaverygoodoverviewofthebook,intheformofarecordingofaJoshuaBlochtalkat“GoogleI/O2008-EffectiveJavaReloaded”onYouTube:
youtu.be/pi_I7oD_uGI
ImplementationPatternsAnotherbookthatbenefitsfromrepeatedreading.Youwilltakedifferentinformationfromitwitheachreading,dependingonyourexperiencelevelatthetime.
“ImplementationPatterns”byKentBeckexplainssomeofthethoughtprocessesinvolvedinwritingprofessionalcode.
Thisbookwasoneofthebooksthathelpedme:
concentrateonkeepingmycodesimple,decidetolearnthebasicsofJava(andknowhowtofindinformationwhenIneededit),trytouseinbuiltfeaturesofthelanguage,beforebringinginanewlibrarytomycode.
Thebookisthinand,againdense.MostcomplaintsIseeon-lineseemtostemfromthelengthofthebookandthetersenessofthecoverage.Ifoundthatbeneficial,itmeantverylittlepaddingandwaste.Ihavelearned,orre-learned,somethingfromthisbookeverytimeIreadit.
Otherbooksthatcoversimilartopicsinclude“CleanCode”byRobertC.Martin,and“ThePragmaticProgrammer”byAndrewHuntandDavidThomas.ButIfound“ImplementationPatterns”farmoreusefulandapplicabletomywork.
FormoreinformationonKentBeck’swritingandwork,visithiswebsite:
threeriversinstitute.org
GrowingObject-OrientedSoftwareAnotherbookIbenefitedfromreadingwhenIwasn’treadyforit.Iwasabletore-readitandlearnmore.Istillgainvaluefromre-readingit.
“GrowingObject-OrientedSoftware,GuidedbyTests”,bySteveFreemanandNatPryce
Heavilyfocusedonusing@Testmethodcodetowriteandunderstandyourcode.Italsocoversmockobjectsverywell.
Thisbookhelpedchangemycodingstyle,andhowIapproachthebuildingofabstractionlayers.
Theofficialhomepageforthebookisgrowing-object-oriented-software.com
CovertJava“CovertJava:TechniquesforDecompiling,PatchingandReverseEngineering”,byAlexKalinovskystartstoshowitsagenowasitwaswrittenin2004.ButhighlightssomeofthewaysofworkingwithJavalibrariesthatyoureallywouldn’tuseifyouwereaprogrammer.
Butsometimesasatesterwehavetoworkwithpre-compiledlibraries,withoutsourcecode,andusepartsofthecodebaseoutofcontext.
IfoundthisaveryusefulbookforlearningaboutreflectionandotherpracticesrelatedtotakingapartJavaapplications.
Youcanusuallypickthisupquitecheaplysecondhand.Thereareotherbooksthecoverdecompiling,reverseengineeringandreflection.Butthisonegotmestarted,andIstillfinditclearandsimple.
JavaConcurrencyinPracticeConcurrencyisnotsomethingIrecommendtryingtoworkwithwhenyouarestartingoutwithJava.
Butatsomepointyouwillprobablywanttorunyourcodeinparallel,orcreatesomethreadstomakeyourcodeperformfaster.Andyouwillprobablyfail,andnotreallyunderstandwhy.
Iused“EffectiveJava”tohelpmegetstarted.But“JavaConcurrencyinPractice”byBrianGoetz,wasthebookIreadwhenIreallyhadtomakemyautomationabstractionlayerworkwithconcurrentcode.
CoreJava:Volume1TheCoreJavabooksaremassive,over1000pages.AndifyoureallywanttounderstandJavaindepththenthesearethebookstoread.
Ifindthemtobehardworkanddon’treadthemoften.ItendtousetheJavaDocfortheJavalibrariesandmethodsthemselves.
But,periodically,Iwanttohaveanoverviewofthelanguageandunderstandthescopeofthebuiltinlibraries,becausetherearelotsofin-builtfeaturesthatIdon’tuse,thatIwouldotherwiseturntoanexternallibraryfor.
EverytimeI’veflickedthrough“CoreJava”,Ihavediscoveredanuanceandanewsetoffeatures,butIdon’tdoitoften.
MasteringRegularExpressionsWedidn’tcoverthefullpowerofRegularExpressionsinthisbook.
ItendtotryandkeepmycodesimpleandreadablesoI’llusesimplestringmanipulationtostartwith.
Butovertime,IoftenfindthatIcanreplaceaseriesofifblocksandstringtransformationswitharegularexpression.
SinceIdon’tuseregularexpressionsoftenIfindthateachtime,Ihavetore-learnthemandIstillturnto“MasteringRegularExpressions”byJeffreyE.F.Friedl.
Asanalternativetoconsider:“RegularExpressionsCookbook”byJanGoyvaerts,whichisalsoverygood.
IsometimesusethetoolRegexMagicregexmagic.com,writtenbyJanGoyvaertswhenwritingregularexpressions,itletsmetestouttheregularexpressionacrossarangeofexampledata,andgeneratesamplecodeforalotofdifferentlanguages.
Janalsomaintainsthewebsiteregular-expressions.infowithalotoftutorialinformationonit.
RecommendedVideosThevideosproducedbyJohnPurcellatcaveofprogramming.comhavebeenrecommendedtomebymanytesters.
I’velookedthroughsomeofthem,andJohnprovidesexamplecodingformanyoftheitemscoveredinthisbook,andinthe“AdvancingConcepts”section.
John’sapproachisgearedaroundwritingprograms,andIthinkthatifyouhavenowfinishedthisbook,youwillbenefitfromthetraditionalprogrammerbasedcoveragethatJohnprovides.
RecommendedWebSitesForgeneralJavanews,anduptodateconferencevideos,Irecommendthefollowingwebsites.
theserverside.cominfoq.com/java
MakesureyousubscribetotheRSSfeedsfortheabovesites.
IwillremindyouthatIhaveawebsitejavaForTesters.comandIplantoaddmoreinformationthere,andlinkstootherresourcesovertime.Iwillalsoaddadditionalexercisesandexamplestothatsiteratherthancontinuetoexpandthisbook.
Remember,allthecodeusedinthisbook,andtheanswerstotheexercisesisavailabletodownloadfromgithub.com/eviltester.
NextStepsThishasbeenabeginner’sbook.
Youcanseefromthe“AdvancingConcepts”chapterthattherearealotoffeaturesinJavathatIdidn’tcover.ManyofthemIdon’tusealotandIdidn’twanttopadoutthebookwithextensivecoveragethatyoucanfindinotherbooksorvideos.
IwantedthisbooktowalkyouthroughtheJavalanguageinanorderthatIthinkmakessensetopeoplewhoarewritingcode,butnotnecessarilywritingsystems.
Yournextstep?Keeplearning.
Irecommendyoustartwiththebooksandvideosrecommendedhere,butalsoaskyourteammates.
Youwillbeworkingonprojects,andthetypeoflibrariesyouareusing,andthetechnicaldomainthatyouareworkingon,mayrequiredifferentapproachesthanthosementionedinthisbook.
Ihopeyouhavelearnedthatyoucangetalotdonequiteeasily,andyoushouldnowunderstandthefundamentalclassesandlanguageconstructsthatyouneedtogetstarted.
Now:
startwriting@Testmethodswhichexerciseyourproductioncodeinvestigatehowmuchofyourrepeatedmanualeffortcanbeautomated
Thankyouforyourtimespentwiththisbook.
Iwishyouwellforthefuture.ThisisjustthestartofyourworkwithJava.Ihopeyou’llcontinuetolearnmoreandputittouseonyourprojects.
Myabilitytouseautomationtosupportmytestingandaddvalueonprojectscontinuestoincrease,themoreIlearnhowtoimprovemycodingskills.Ihopeyoursdoestoo.
References
JavaForTestersgithub.com/eviltester/javaForTestersCodeJavaForTesters.com
JoshuaBlochen.wikipedia.org/wiki/Joshua_Blochyoutu.be/pi_I7oD_uGI
KentBecktwitter.com/kentbeck“ThreeRiversInstitute”threeriversinstitute.org
GrowingObjectOrientedSoftware,GuidedbyTestsgrowing-object-oriented-software.comSteveFreeman’sBloghigherorderlogic.comnatpryce.com
CoreJavaBookhorstmann.com/corejava.html
JavaConcurrencyInPracticejcip.net.s3-website-us-east-1.amazonaws.com/
RegularExpressionsMasteringRegularExpressionshomepageregex.inforegular-expressions.info/regexmagic.comregexpal.comwww.regexr.com
Appendix-IntelliJHintsandTips
ThroughoutthebookImentionedhintsandtips,andshortcutsforusingIntelliJ.
Icollateallofthoseinthisappendixforeasyreference,andaddsomeadditionalinformationonusingIntelliJwiththisbook.
ShortcutKeysThistablecontainstheshortcutkeysthatIusemostoften.
Function Windows MacCreateNew alt+insert ctrl+n
IntentionActions
alt+enter alt+enter
IntentionActions
alt+return alt+return
RunJUnitTest ctrl+shift+F10 ctrl+shift+F10
ShowParameters
ctrl+p cmd+p
ShowJavaDoc ctrl+q ctrl+j
CodeCompletion
ctrl+space ctrl+space
Findbyclass ctrl+n ctrl+n
Findbyfilename ctrl+shift+n ctrl+shift+n
Findbysymbol ctrl+shift+alt+
n
ctrl+shift+alt+
n
JetBrainsIntelliJhavesupportingdocumentationontheirwebsite:
ReferencepdfforWindowsandLinuxjetbrains.com/idea/docs/IntelliJIDEA_ReferenceCard.pdf
ReferencepdfforMacOSXjetbrains.com/idea/docs/IntelliJIDEA_ReferenceCard_Mac.pdf
Andthehelpfileshave“Keyboardshortcutsyoucannotmiss”
jetbrains.com/idea/help/keyboard-shortcuts-you-cannot-miss.html
CodeCompletionCodecompletionisyourfriend.YoucanuseittoexploreAPIsandLibraries.
Allyoudoisstarttypingandafterthe.youwillseecontextspecificitemsyoucanuse.
Youcanforceastartofcodecompletionifyouclosethepop-upmenubypressing:
ctrl+space
NavigatingSourceCode
ctrl+click
Foranymethodinyourcode,eitherabuiltinmethod,oralibrarymethod,orevenonethatyouhavewritten.Youcanholddownctrlandleftmouseclickonthemethodnametojumptothesourceofthatmethod.
YoumightbepromptedtoallowIntelliJtodownloadthesourceforexternallibraries.
Thiscanhelpwhenworkingwiththeexamplesourcecodeforthisbookasyoucannavigatetothedomainobjectsfromwithinthe@Testmethodcode.
FindingClassesandSymbolsIfinthisbookyouseeamethodnameoraclassname,butdon’tknowwheretofinditinthesourcecodethenyoucanusethefindfunctionalityinIntelliJtohelp.
Tofindaclassbyname,usethekeyboardshortcut:
ctrl+n
Thiscanperformpartialmatching,soyoudon’thavetotypeinthefullnameoftheclass.
Ifyouwanttofinda‘file’intheprojectthenusekeyboardshortcut:
ctrl+shift+n
Ifyouwanttofindamethodname,orvariablename(symbol)thenusethekeyboardshortcut:
ctrl+shift+alt+n
RunningaJUnitTestAnnotatingmethodswith@Testmakesiteasyforusto‘run’themethodswewrite.YoucanrightclickonthemethodnameorclassandchoosetoRunasJUnittest.Oruseshortcutkey:
ctrl+shift+F10
LoadingProjectSourceTheeasiestwaytoloadaprojectintoIntelliJ,andthisappliestothebookexamplesourcecode,istouse:
File\Openandselectthepom.xmlfile.
HelpMenuThehelpmenudoesmorethanofferalinktoahelpfile.
FindActionThemenuoptionHelp\FindActionallowsyoutotypeanactionandIntelliJwillprovidemenuoptionsandshortcutkeystohelp.
e.g.
SelectHelp\FindActiontype“junit”andyouwillseealistof‘settings’youcanusetohelpconfigureJUnitinIntelliJtype“run”andyouwillseealistofoptionsforrunningcode,ortests
Thelistisn’tjustforinformation,youcanclickontheitemsinthelistandyouwillbetakentothefunctionalityinIntelliJorrunthecommand.
ProductivityGuideTheHelp\ProductivityGuidemenuoptionshowsadialogwithcommonproductivityimprovements.
Youcanclickontheitemsinthelisttoseewhatitdoes,andyoucanalsoseewhichonesyouhaveused,andwhichyouhaven’t.
ThiscanhelpyoulearnthebasicsofIntelliJveryquickly.
SummaryIntelliJoffersalotofflexibilityinhowweworkwithcode.OvertimeyouwilllearntomakeyourworkwithJavafasterasyoulearnmoreabouttheIDE.
OvertimeIwilladdvideosandinformationtoJavaForTesters.comtodemonstratemorefunctionalitywithIntelliJthatIdonothavespacetoaddtothisbook.
Appendix-ExerciseAnswers
Thisappendixcontainsanswersto,andcommentaryon,theexercisesinthebook.
Allthecodefoundhere,canalsobefoundinthesupportingsourcecodegithubrepository:
https://github.com/eviltester/javaForTestersCode
ChapterThree-MyFirstJUnitTest
Checkfor5insteadof4WhenIrantheJUnittestIsawconsoleoutputinformingmeofanAssertionError.1java.lang.AssertionError:2+2=4expected:<5>butwas:<4>
2 atorg.junit.Assert.fail(Assert.java:88)
3 atorg.junit.Assert.failNotEquals(Assert.java:743)
4 atorg.junit.Assert.assertEquals(Assert.java:118)
5 atorg.junit.Assert.assertEquals(Assert.java:555)
6 atcom.javafortesters.chap003myfirsttest.examples.MyFirstTest.
7 canAddTwoPlusTwo(MyFirstTest.java:19)
Theactualmessagewaslongerthanthis,butwewillexplainerrormessagesinalaterchapter.
ItisimportanttonotethatinIntelliJIcouldclickonthehypertextintheerrormessageMyFirstTest.java:19andIwillbetakentothelineofcodeintheeditorthatthrewtheexception.Didyoutryclickingonthelink?Itmakesdebuggingaloteasier.
Createadditional@Testmethodstocheck@Test
publicvoidcanSubtractTwoFromTwo(){
intanswer=2-2;
assertEquals("2-2=0",0,answer);
}
@Test
publicvoidcanDivideFourByTwo(){
intanswer=4/2;
assertEquals("4/2=2",2,answer);
}
@Test
publicvoidcanMultiplyTwoByTwo(){
intanswer=2*2;
assertEquals("2*2=4",4,answer);
}
CheckthenamingoftheTestclasses
IntheexamplecodeyouwillseethatIhavewrittentheJUnitteststhatdonotrunfromMaven,asfailingmethodsi.e.theassertionsfail.Justtomakethepointthatnamingisveryimportant.publicclassNameClass{
@Test
publicvoidwhenClassNameHasNoTestInItThenItIsNotRun(){
//thistestwillnotrunfrommavensoicanmake
//afailingtest…itfailsintheIDE
assertTrue("whenClassNameHasNoTestInItThenItIsNotRun",
false);
}
}
publicclassNameClassTest{
@Test
publicvoidwhenClassHasTestAtEndThenTestIsRun(){
//thistestwillrunfrommavensoitneedstopass
assertTrue("whenClassHasTestAtEndThenTestIsRun",
true);
}
}
publicclassNameTestClass{
@Test
publicvoidwhenClassHasTestInMiddleThenTestIsNotRun(){
//thistestwillnotrunfrommavensoicanmake
//afailingtest…itfailsintheIDE
assertTrue("whenClassHasTestInMiddleThenTestIsNotRun",
false);
}
}
publicclassTestNameClass{
@Test
publicvoidwhenClassHasTestAtFrontThenTestIsRun(){
//thistestwillrunfrommavensoitneedstopass
assertTrue("whenClassHasTestAtFrontThenTestIsRun",
true);
}
}
ChapterFour-WorkWithOtherClasses
ConvertaninttoHex@Test
publicvoidcanConvertIntToHex(){
assertEquals("hex11isb","b",
Integer.toHexString(11));
assertEquals("hex10isb","a",
Integer.toHexString(10));
assertEquals("hex3isb","3",
Integer.toHexString(3));
assertEquals("hex21isb","15",
Integer.toHexString(21));
}
ConfirmMAXandMINIntegersizes
@Test
publicvoidcanConfirmIntMinAndMaxLimits(){
intminimumInt=-2147483648;
intmaximumInt=2147483647;
assertEquals("integermin",minimumInt,Integer.MIN_VALUE);
assertEquals("integermax",maximumInt,Integer.MAX_VALUE);
}
ChapterFive-WorkWithOurOwnClasses
ExperimentwiththecodeWhenyoureplacetheStringwithanint,youshouldseeasyntaxerrorbecauseanintdoesnotsatisfythemethoddeclarationwhichneedsaString
WhenyoureplacetheStringliteral"http://192.123.0.3:67"withnull,youwon’tgetasyntaxerrorbecausenullisavalidobjectreference,butifyourunthe@Testmethoditshouldfail.
ConvertfromStaticUsagetoStaticImportTheexamplesourceshowstheindividualimportsofDOMAINandPORT,ifIcommentthosetwoimportsoutandaddintheimportforTestAppEnv.*thenIhaveimportedeverythingstaticallyandthenhavetheoptiontoremovetheTestAppEnvprefixfromgetUrl,butIdon’thaveto.
InormallywouldnotimportTestAppEnvstaticallyasIdon’tthinkitisasreadableasasimpleimportoftheclass.1importcom.javafortesters.domainobject.TestAppEnv;
2importorg.junit.Assert;
3importorg.junit.Test;
4
5//IcouldimporteverythingonTestAppEnvstatically,andthen
6//Idon'tneedtoprefixgetUrlwithTestAppEnv
7/*
8importstaticcom.javafortesters.domainobject.TestAppEnv.*;
9*/
10//IfIjustimporttheDOMAINandPORTthenIstillneedto
11//prefixgetUrlwithTestAppEnv
12importstaticcom.javafortesters.domainobject.TestAppEnv.DOMAIN;
13importstaticcom.javafortesters.domainobject.TestAppEnv.PORT;
14
15
16publicclassTestAppEnvironmentNoStaticImportTest{
17
18@Test
19publicvoidcanGetUrlStatically(){
20Assert.assertEquals("ReturnsHardCodedURL",
21"http://192.123.0.3:67",
22TestAppEnv.getUrl());
23}
24
25@Test
26publicvoidcanGetDomainAndPortStatically(){
27
28Assert.assertEquals("JusttheDomain",
29"192.123.0.3",
30DOMAIN);
31
32Assert.assertEquals("Justtheport",
33"67",
34PORT);
35}
36}
ChapterSix-JavaClassesRevisited:Constructors,Fields,Getter&SetterMethods
ExperimentwiththepackagestructureWhenIhavetheJunitTestclassinthesamepackageastheUserclassthenIdonotneedtoimportit.Eventhoughweareindifferentsourcehierarchiesi.e.oneinsrc\testandoneinsrc\main.1packagecom.javafortesters.domainentities;
2
3importorg.junit.Test;
4
5importstaticorg.junit.Assert.assertEquals;
6
7publicclassUserTest{
IfIchangethepackagethenIhavetoaddtheimportfortheUserclass.1packagecom.javafortesters.chap006domainentities.exercises.differentpackage;
2
3importcom.javafortesters.domainentities.User;
4importorg.junit.Test;
5importstaticorg.junit.Assert.assertEquals;
6
7publicclassUserTest{
IwouldalsohavetoaddtheimportifthereweremultipleUserclassesinmycodebase,inordertotellJavawhichoneIwanttouse.
ExperimentwithprivateandpublicfieldsWhenaclasshasfieldswhicharepublic:1publicclassUser{
2publicStringusername;
3publicStringpassword;
4
5publicUser(){
6username="admin";
7password="pA55w0rD";
8}
9}
Thenitdoesn’treallyneedgetterorsettermethods.
ButtheUserclasshasnocontroloveritsdata.Laterweaddchecksonthesetterandgettermethodssothatwecan’taddinvaliddatatotheobject.Ifyoumakethefieldspublicthenyoudon’thavethosesafeguards.1@Test
2publicvoidcanConstructWithUsernameAndPassword(){
3Userauser=newUser();
4auser.username="bob";
5assertEquals("notdefaultusername",
6"bob",
7auser.username);
8}
9
10@Test
11publicvoidcanSetNameToInvalidValue(){
12Userauser=newUser();
13auser.username="12345£$%$";
14assertEquals("invalidusername",
15"12345£$%$",
16auser.username);
17}
ExperimentwiththefieldandparameternamesWhenyouremovethis.fromtheconstructor:1publicUser(Stringusername,Stringpassword){
2username=username;
3password=password;
4}
WhenJavaseestheline:1username=username;
Itexecutesit,butassignsthevaluepassedinastheparametertotheparameter,andnottothefield,soourfieldcalledusernameisneverassignedavalueandsoisnull,asreportedbytheassertionmessage:java.lang.AssertionError:givenusernameexpectedexpected:<admin>butwas:
<null>
Whenwerenametheparameters:1publicUser(StringaUsername,StringaPassword){
2username=aUsername;
3password=aPassword;
4}
Thenwedonotneedthethiskeyword.Theparametersandfieldshavedifferentnames,sotheywillnotclash.
Itisuptoyouwhichstyleyouchoosetoadoptforyourcoding.
Iusebothandswitchbetweenthematdifferenttimes.Bynamingtheparameterthesameasthefield,andusingthethiskeywordtodistinguishthem,whenIusecodecompletionintheconstructor,thecodecompletionshowsmeusernameandpasswordmakingiteasyformetoseewhattheparametersreferto.Thiscodecompletionusecaseisthemain
decisionmakerforme,whenIchoosewhetherornottousethisorrenametheparameters.
ChapterEight-SelectionsandDecisions
CatorCats?TernaryOperatorWritean@Testmethodthatusesaternaryoperatortoreturn“cats”ifanumberOfCatsequals1.Andreturn"cat"ifthenumberOfCatsisnot11@Test
2publicvoidcatOrCats(){
3
4intnumberOfCats=1;
5
6assertEquals("1==cat",
7"cat",
8(numberOfCats==1)?"cat":"cats");
9
10numberOfCats=0;
11assertEquals("0==cats",
12"cats",
13(numberOfCats==1)?"cat":"cats");
14
15numberOfCats=2;
16assertEquals("2==cats",
17"cats",
18(numberOfCats==1)?"cat":"cats");
19}
WhenIrewritethecodesothatitusesamethod,thenthecodeiscleanerandavoidstherepetition.1@Test
2publicvoidcatOrCatsAsMethod(){
3
4assertEquals("1==cat","cat",catOrCats(1));
5
6assertEquals("0==cats","cats",catOrCats(0));
7
8assertEquals("2==cats","cats",catOrCats(2));
9}
10
11privateStringcatOrCats(intnumberOfCats){
12return(numberOfCats==1)?"cat":"cats";
13}
AssertTrueiftrue1@Test
2publicvoidtruthyIf(){
3booleantruthy=true;
4
5if(truthy)
6assertTrue(truthy);
7
8if(truthy){
9assertTrue(truthy);
10assertFalse(!truthy);
11}
12}
AssertTrueelseAssertFalseForasinglestatementIdonotneedtoaddthebraces:1@Test
2publicvoidtruthyIfElse(){
3booleantruthy=true;
4
5if(truthy)
6assertTrue(truthy);
7else
8assertFalse(truthy);
9}
WhenthereismorethanonestatementintheifortheelsethenIneedtoaddthe{}braces:1@Test
2publicvoidtruthyIfElseBraces(){
3booleantruthy=true;
4
5if(truthy){
6assertTrue(truthy);
7assertFalse(!truthy);
8}else{
9assertFalse(truthy);
10}
11}
Icanchoosetoleaveoffthebracesfortheelsebecausethereisonlyonecondition,butinpracticeIwouldnotdothisbecauseImightwanttoexpandthenumberofstatementsontheelseconditioninthefuture,andImakethecodehardertoreview:1@Test
2publicvoidtruthyIfElseOnlyOneSetOfBraces(){
3booleantruthy=true;
4
5if(truthy){
6assertTrue(truthy);
7assertFalse(!truthy);
8}else
9assertFalse(truthy);
10}
NestedIfElseHorrorIfyoueverfindyourselfwritingcodelikethefollowingthenIguaranteethatyouhavedonesomethingwrong,andhavenotthoughtthroughtheproblemproperly.
IdecidedtopullthemainlogicoutintoaseparatemethodsothatIcouldcallitmoreeasilywiththedifferentcombinationsoftrueandfalsefortruthyandfalsey.
IalsoaddedasetofSystem.out.printlnsothatIcouldseethetruthtablecombinations.ItwasfortunateIdidthisbecauseIactuallymadeamistakeinthenestedif/elsestatementswhenIfirstwrotemyanswer-howdidyoucheckyouranswer?
1@Test
2publicvoidnestedIfElseHorror(){
3horrorOfNestedIfElse(true,true);
4horrorOfNestedIfElse(true,false);
5horrorOfNestedIfElse(false,true);
6horrorOfNestedIfElse(false,false);
7}
8
9publicvoidhorrorOfNestedIfElse(booleantruthy,booleanfalsey){
10
11if(truthy){
12if(!falsey){
13if(truthy&&!falsey){
14if(falsey||truthy){
15System.out.println("T|F");
16assertTrue(truthy);
17assertFalse(falsey);
18}
19}
20}else{
21System.out.println("T|T");
22assertTrue(truthy);
23assertTrue(falsey);
24}
25}else{
26if(!truthy){
27if(falsey){
28System.out.println("F|T");
29assertTrue(falsey);
30assertFalse(truthy);
31}else{
32System.out.println("F|F");
33assertFalse(falsey);
34assertFalse(truthy);
35}
36}
37}
38}
SwitchonShortCodeIaddedabreak,afterthedefault.Removethebreaktoverifyforyourselfifitisrequiredornot,anddecideifthereisanydifferenceinthereadabilityofthecode.
Also,removesomeofthebreakstatementsandverifythattheresultsarenotasexpected.1@Test
2publicvoidcountrySwitch(){
3
4assertEquals("UnitedKingdom",countryOf("UK"));
5assertEquals("UnitedStates",countryOf("US"));
6assertEquals("UnitedStates",countryOf("USA"));
7assertEquals("UnitedStates",countryOf("UsA"));
8assertEquals("France",countryOf("FR"));
9assertEquals("Sweden",countryOf("sE"));
10assertEquals("RestOfWorld",countryOf("ES"));
11assertEquals("RestOfWorld",countryOf("CH"));
12}
13
14privateStringcountryOf(StringshortCode){
15
16Stringcountry;
17
18switch(shortCode.toUpperCase()){
19case"UK":
20country="UnitedKingdom";
21break;
22case"US":
23case"USA":
24country="UnitedStates";
25break;
26case"FR":
27country="France";
28break;
29case"SE":
30country="Sweden";
31break;
32default:
33country="RestOfWorld";
34break;
35}
36
37returncountry;
38}
SwitchonintThisexercisewasdesignedtoallowyoutoswitchonvariablesotherthanString,andalsotoseewhatcreativeapproachyouadoptedforthe>4and<1conditions.
Inmyanswerbelow,youcanseethatIaddedasetofifstatementsinthedefaultblock.1@Test
2publicvoidintegerSwitch(){
3
4assertEquals("One",integerString(1));
5assertEquals("Two",integerString(2));
6assertEquals("Three",integerString(3));
7assertEquals("Four",integerString(4));
8assertEquals("Toobig",integerString(5));
9assertEquals("Toobig",integerString(Integer.MAX_VALUE));
10assertEquals("Toosmall",integerString(0));
11assertEquals("Toosmall",integerString(Integer.MIN_VALUE));
12}
13
14privateStringintegerString(intanInt){
15
16StringvalReturn="";
17
18switch(anInt){
19case1:
20valReturn="One";
21break;
22case2:
23valReturn="Two";
24break;
25case3:
26valReturn="Three";
27break;
28case4:
29valReturn="Four";
30break;
31default:
32if(anInt<1){
33valReturn="Toosmall";
34}
35if(anInt>4){
36valReturn="Toobig";
37}
38break;
39}
40
41returnvalReturn;
42}
Andfortheextrapoints,youexploredwritingaswitchstatementwithoutusingbreak;.
Inthisexample,becausethemethodissosimple,thecodeactuallyreadsquitewell,andsuccinctly.Ididhavetoaddanextrareturn"";line,whichwillneverbeexecuted,inordertosatisfythemethod’sdeclarationofreturningaString.1privateStringintegerStringUsingReturnOnly(intanInt){
2switch(anInt){
3case1:
4return"One";
5case2:
6return"Two";
7case3:
8return"Three";
9case4:
10return"Four";
11default:
12if(anInt<1){
13return"Toosmall";
14}
15if(anInt>4){
16return"Toobig";
17}
18}
19
20return"";
21}
ChapterNine-ArraysandForLoopIteration
CreateanArrayofUsersInordertoworkwiththeUserobjects,IfirsthadtoimporttheUserclass.importcom.javafortesters.domainentities.User;
ThenIcreatedthearrayandaddedtheusers.@Test
publicvoidcreateAnArrayOfUsers(){
User[]users=newUser[3];
users[0]=newUser("bob","bA55Word");
users[1]=newUser("eris","eA55Word");
users[2]=newUser("ken","kA55Word");
assertEquals("bob",users[0].getUsername());
assertEquals("eris",users[1].getUsername());
assertEquals("ken",users[2].getUsername());
}
NotethatIaddedassertsontheusernametocheckthatIhadaddedtheuserscorrectly.Didyouaddassertstoyour@Testmethod?Ifnot,howdidyouknowitworked?
IterateovertheArrayofUsersIaddedthefollowingcodetomy@Testmethodabove,toiterateoverthearrayandprintoutthevaluesinthearray:for(UseraUser:users){
System.out.println(aUser.getUsername());
}
Createanarrayof100usersInmysampleanswer,IchosetoSystem.out.printlnthearraytocheck.
Icouldhaveputabreakpointaftertheloopandusedthedebuggertocheckbyrunningthecodeindebugmode.
Iaddedassertioncode,whichusestheforeachsoIiterateovereveryitem,andcounteachitem,usingthecountuserIdtochecktheusernameandpassword.SinceIknowthattherearesupposedtobe100,whenIexittheforeachloop,IexpectmyuserIdtoequal101.
Youmayhavechosenanothermethod.That’sfine.Therearemanywaystodothis.@Test
publicvoidexerciseCreateAnArrayOf100Users(){
User[]users=newUser[100];
for(intuserIndex=0;userIndex<100;userIndex++){
intuserId=userIndex+1;
users[userIndex]=newUser("user"+userId,
"password"+userId);
}
//checkcreation
for(UseraUser:users){
System.out.println(aUser.getUsername()+
","+
aUser.getPassword());
}
//bonuspointsassertcreation
intuserId=1;
for(UseraUser:users){
assertEquals("user"+userId,aUser.getUsername());
assertEquals("password"+userId,aUser.getPassword());
userId++;
}
//checkthelastoneoutputwas100,i.e.nextwouldbe101
assertEquals(userId,101);
}
SortWorkdaysArrayandAssertResultThetextissortedinalphabeticalorder,andsinceallthestringsstartwithuppercase,thewordsareintheorderwewouldexpect.@Test
publicvoidsortWorkdaysArrayAndAssertResult(){
String[]workdays={"Monday","Tuesday","Wednesday",
"Thursday","Friday"};
Arrays.sort(workdays);
assertEquals(workdays[0],"Friday");
assertEquals(workdays[1],"Monday");
assertEquals(workdays[2],"Thursday");
assertEquals(workdays[3],"Tuesday");
assertEquals(workdays[4],"Wednesday");
}
Afteramendingthedaynames,Iexpectthewordsstartingwithlowercaseletterstocomeafterthewordswithuppercaseletters.@Test
publicvoidsortWorkdaysMixedCaseArrayAndAssertResult(){
String[]workdays={"monday","Tuesday","Wednesday",
"thursday","Friday"};
Arrays.sort(workdays);
assertEquals(workdays[0],"Friday");
assertEquals(workdays[1],"Tuesday");
assertEquals(workdays[2],"Wednesday");
assertEquals(workdays[3],"monday");
assertEquals(workdays[4],"thursday");
}
Understandhowprint2DIntArraymethodworks1publicvoidprint2DIntArray(int[][]multi){
2for(int[]outer:multi){
3if(outer==null){
4System.out.print("null");
5}else{
6for(intinner:outer){
7System.out.print(inner+",");
8}
9}
10System.out.println("");
11}
12}
line01:declarethemethodasacceptinga2dimensionalintarrayasparameterline02:iterateovertheouterarrayline03:iftheouterarrayisnull,then…
line04:output"null",wedonottryandprocessthecontentsofthisarray
line05:theouterarrayisnotnull,therefore…line06:iterateoverthecontentsofthisarray
line07:outputthecontentsofthearraycellline10:outputablankline
CreateaTriangleTocreateatriangle,Icreatethearraytoallowaraggedarray.
Thenloopoverthearray,andassignanarraytoeachcellinthearray.
Foreachofthenewarrays,Iloopoverthecellcontentsandinserttheindexvalue.@Test
publicvoidcreateTriangle2dArray(){
int[][]triangle=newint[16][];
for(introw=0;row<triangle.length;row++){
triangle[row]=newint[row+1];
for(inti=0;i<(row+1);i++){
triangle[row][i]=i;
}
}
print2DIntArray(triangle);
}
publicvoidprint2DIntArray(int[][]multi){
for(int[]outer:multi){
if(outer==null){
System.out.print("null");
}else{
for(intinner:outer){
System.out.print(inner+",");
}
}
System.out.println("");
}
}
ChapterTen-IntroducingCollections
Useaforloopinsteadofawhileloop@Test
publicvoiduseAForLoopInsteadOfAWhile(){
String[]someDays={"Tuesday","Thursday",
"Wednesday","Monday",
"Saturday","Sunday",
"Friday"};
List<String>days=Arrays.asList(someDays);
intforwhile;
for(forwhile=0;!days.get(forwhile).equals("Monday");forwhile++){
}
assertEquals("Mondayisatposition3",3,forwhile);
}
CreateandmanipulateaCollectionofUsers@Test
publicvoidcreateAndManipulateACollectionOfUsers(){
Collection<User>someUsers=newArrayList<User>();
Userbob=newUser("bob","Passw0rd");
Usereris=newUser("eris","Cha0sTime");
assertEquals(0,someUsers.size());
assertTrue(someUsers.isEmpty());
someUsers.add(bob);
someUsers.add(eris);
assertEquals(2,someUsers.size());
assertFalse(someUsers.isEmpty());
Collection<User>secondUsers=newArrayList<User>();
Userrobert=newUser("robert","9assword");
Useraleister=newUser("aleister","Pass5word");
secondUsers.add(robert);
secondUsers.add(aleister);
assertEquals(2,secondUsers.size());
someUsers.addAll(secondUsers);
assertEquals(4,someUsers.size());
assertTrue(someUsers.containsAll(someUsers));
assertTrue(someUsers.contains(aleister));
secondUsers.removeAll(someUsers);
assertEquals(0,secondUsers.size());
someUsers.clear();
assertEquals(0,someUsers.size());
}
CreateandmanipulateaListofUsers@Test
publicvoidcreateAndManipulateAListOfUsers(){
List<User>someUsers=newArrayList<User>();
assertEquals(0,someUsers.size());
Userbob=newUser("bob","Passw0rd");
Usereris=newUser("eris","Cha0sTime");
someUsers.add(bob);
assertEquals(1,someUsers.size());
someUsers.add(0,eris);
assertEquals(2,someUsers.size());
assertEquals(1,someUsers.indexOf(bob));
assertEquals(0,someUsers.indexOf(eris));
someUsers.remove(0);
assertEquals(0,someUsers.indexOf(bob));
assertEquals(1,someUsers.size());
}
CreateandmanipulateaSetofUsers@Test
publicvoidcreateAndManipulateASetOfUsers(){
Set<User>someUsers=newHashSet<User>();
assertEquals(0,someUsers.size());
Userbob=newUser("bob","Passw0rd");
someUsers.add(bob);
assertEquals(1,someUsers.size());
someUsers.add(bob);
assertEquals(1,someUsers.size());
}
CreateandmanipulateaMapofUsers@Test
publicvoidcreateAndManipulateAMapOfUsers(){
Map<String,User>someUsers=newHashMap<String,User>();
assertEquals(0,someUsers.size());
Userbob=newUser("bob","Passw0rd");
Usereris=newUser("eris","Cha0sTime");
someUsers.put(bob.getUsername(),bob);
assertEquals(1,someUsers.size());
someUsers.put(bob.getUsername(),eris);
assertEquals(1,someUsers.size());
}
ChapterEleven-IntroducingExceptions
FixtheNullPointerExceptioninthecodeAllIhadtodowastakethecodelistedearlierinthechapter,andassign18totheagevariablebeforetryingtoaccessit.@Test
publicvoidnoLongerThrowANullPointerException(){
Integerage=18;
StringageAsString=age.toString();
StringyourAge=
"Youare"+ageAsString+"yearsold";
assertEquals("Youare18yearsold",yourAge);
}
Uninitialisedvariables,andparametersareacommonsourceofexceptions.
UseadifferentexceptioninsteadofNullPointerExceptionWhenIreplacedNullPointerExceptionwithArithmeticException.
TheNullPointerExceptionisthrownbecausetherewasnocodetocatchit.@Test(expected=NullPointerException.class)
publicvoidcatchADifferentException(){
Integerage=null;
StringageAsString;
try{
ageAsString=age.toString();
}catch(ArithmeticExceptione){
age=18;
ageAsString=age.toString();
}
StringyourAge=
"Youare"+age.toString()+"yearsold";
assertEquals("Youare18yearsold",yourAge);
}
YoucanseeIusedtheexpectedparametertoallowmetocheckforthisExceptionthrownbythe@Testmethod.
Don’tfixthecauseoftheexceptionWhenIremovetheage=18;statementfromwithinthecatchblockandrunthecode.ThecodethrewaNullPointerExceptionbecauseweaddednotrycatchblockinsidethecatchblock.@Test(expected=NullPointerException.class)
publicvoidtestNotFixedStillThrowsNullPointer(){
Integerage=null;
StringageAsString;
try{
ageAsString=age.toString();
}catch(ArithmeticExceptione){
//age=18;
ageAsString=age.toString();
}
StringyourAge=
"Youare"+age.toString()+"yearsold";
assertEquals("Youare18yearsold",yourAge);
}
CatchaCheckedExceptionWhenIusedNoSuchMethodExceptioninsteadofNullPointerException.Ireceivedasyntaxerror.@Test
publicvoidthisTriggersASyntaxErrorBecauseExceptionIsNotDeclared(){
Integerage=null;
StringageAsString;
try{
ageAsString=age.toString();
}catch(NoSuchMethodExceptione){
age=18;
ageAsString=age.toString();
}
StringyourAge=
"Youare"+age.toString()+"yearsold";
assertEquals("Youare18yearsold",yourAge);
}
IreceivedasyntaxerrorontheNoSuchMethodExceptionline:}catch(NoSuchMethodExceptione){
NoSuchMethodExceptionisacheckedexceptionandneedstobedeclaredasthrownbymethods.ThetoStringmethoddoesnotdeclarethatitwillthrowaNoSuchMethodExceptionsoIreceiveasyntaxerror.
NullPointerExceptionandArithmeticExceptionareuncheckedexceptionsanddon’tneedtobedeclaredasthrownbymethods.
UseExceptionasanobjectWhenIaddthecodetousethemethodsontheexception:@Test
publicvoiduseExceptionAsAnObject(){
Integerage=null;
StringageAsString;
try{
ageAsString=age.toString();
}catch(NullPointerExceptione){
System.out.println("getMessage-"+
e.getMessage());
System.out.println("getStacktrace-"+
e.getStackTrace());
System.out.println("printStackTrace");
e.printStackTrace();
}
}
Ireceivethefollowingoutput,Ihavecutdowntheoutputtosavespaceso...representssomemissingoutput:getMessage-null
getStacktrace-[Ljava.lang.StackTraceElement;@4ea3c69a
printStackTrace
java.lang.NullPointerException
atcom.javafortesters.exceptions.exercises.IntroducingExceptionsExercisesTest.
useExceptionAsAnObject(IntroducingExceptionsExercisesTest.java:99)
...
atjava.lang.reflect.Method.invoke(Method.java:601)
atcom.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
FromthisIcanseethatgetMessageonaNullPointerExceptiondoesnotreturnamessage,soweneedtousethestacktracetofigureoutwhatwentwrong.Otherexceptionsdoreturnmessages,andwhenyoustartcreatingyourownexceptions,Irecommendthatyouaddamessagetomakeiteasierforotherpeopletounderstandtheprobleminthecode.
ThegetStacktraceisanarrayofStackTraceElementObjects,soIcouldaccesselement[0],whichisthemostrecentitemontheArray,anduseittofindinformationaboutthatpartofthestacktracee.g.
getClassName
getFileName
getLineNumber
getMethodName
System.out.println("StackTraceLength-"+
e.getStackTrace().length);
System.out.println("StackTrace[0]classname-"+
e.getStackTrace()[0].getClassName());
System.out.println("StackTrace[0]filename-"+
e.getStackTrace()[0].getFileName());
System.out.println("StackTrace[0]linenumber-"+
e.getStackTrace()[0].getLineNumber());
System.out.println("StackTrace[0]methodname-"+
e.getStackTrace()[0].getMethodName());
whichwoulddisplay:StackTraceLength-27
StackTrace[0]classname-com.javafortesters.exceptions.exercises
IntroducingExceptionsExercisesTest
StackTrace[0]filename-IntroducingExceptionsExercisesTest.java
StackTrace[0]linenumber-100
StackTrace[0]methodname-useExceptionAsAnObject
FormoreinformationontheStackTraceElementyoucanreadtheofficialdocumentation:
docs.oracle.com/javase/7/docs/api/java/lang/StackTraceElement.html
ChapterTwelve-IntroducingInheritance
CreateaUserthatiscomposedofTestAppEnv
Ihavemultipleapproachesforimplementingthis.
Ican:
createaTestAppEnvobjectwithinmyUserobject,orre-useTestAppEnvstaticallyfromwithinmyUserobjectcreateanewEnvironmentUserobjectwhichextendsobjectandusesTestAppEnv
CreateaTestAppEnvobjectwithinmyUserobject
TocreateaTestAppEnvobjectwithinmyUserobjectIcould:
addanewTestAppEnvfield,instantiatetheobjectintheconstructor,andimplementagetUrlmethodontheobject.
publicclassUser{
privateStringusername;
privateStringpassword;
privateTestAppEnvtestAppEnv;
publicUser(){
this("username","password");
}
publicUser(Stringusername,Stringpassword){
this.username=username;
this.password=password;
this.testAppEnv=newTestAppEnv();
}
publicStringgetUsername(){
returnusername;
}
publicStringgetPassword(){
returnpassword;
}
publicvoidsetPassword(Stringpassword){
this.password=password;
}
publicStringgetUrl(){
returnthis.testAppEnv.getUrl();
}
}
Re-useTestAppEnvstaticallyfromwithinmyUserobject
SinceTestAppEnvwasoriginallydesignedtobeaccessedstatically,Idon’tneedtodeclareafieldorinstantiateanobject,Icouldjust:
addagetUrlmethodtoUserdelegatetothestaticmethodonTestAppEnv
publicStringgetUrl(){
returnTestAppEnv.getUrl();
}
CreateanewEnvironmentUser
SincetheEnvironmentUserisaspecialcaseofuser,Idon’tneedtoamendtheUserobjectatall.IcouldcreateanewobjectcalledEnvironmentUserwhichextendsUser,andthenaddanewmethodtotheEnvironmentUserwhichstaticallyusestheTestAppEnvobject.packagecom.javafortesters.chap012inheritance.exercises;
importcom.javafortesters.domainentities.User;
importcom.javafortesters.domainobject.TestAppEnv;
publicclassEnvironmentUserextendsUser{
publicStringgetUrl(){
returnTestAppEnv.getUrl();
}
}
AndIwouldusetheobjectinan@Testmethodasfollows:@Test
publicvoidcreateAnEnvironmentUser(){
EnvironmentUserenuser=newEnvironmentUser();
assertEquals("username",enuser.getUsername());
assertEquals("http://192.123.0.3:67",enuser.getUrl());
}
CreateaReadOnlyUserTocreateaReadOnlyUserwhichhasthepermissionReadOnly,withthesamedefault“username”and“password”fromUser.Ifirstwrotean@Testmethodwhichcheckedforthecorrectimplementation.@Test
publicvoidreadOnlyUserPrivsAndDefaults(){
ReadOnlyUserrod=newReadOnlyUser();
assertEquals("ReadOnly",rod.getPermission());
assertEquals("username",rod.getUsername());
assertEquals("password",rod.getPassword());
}
ThenIimplementedtheReadOnlyUser.ThiswasaverysimpleclasswhichextendstheUser,andimplementsan@OverrideofgetPermissionpackagecom.javafortesters.chap012inheritance.exercises;
importcom.javafortesters.domainentities.User;
publicclassReadOnlyUserextendsUser{
@Override
publicStringgetPermission(){
return"ReadOnly";
}
}
ChapterThirteen-MoreExceptions
CreateanInvalidPasswordexceptionPartof‘helping’peopleusetheUserdomainobjectistoalertthemtovalidationandexceptionsthattheymightencounterusingtheclass.Wecandothisthroughdocumentation,andwecandothisthroughcustomexceptions.
BycreatinganInvalidPasswordexceptionwealertpeopletothevalidationrulesaroundsettingthepasswordonauser.
Asyousawinthechapter,IcreateaclasswiththecodeforanInvalidPassword:publicclassInvalidPasswordextendsException{
publicInvalidPassword(Stringmessage){
super(message);
}
}
InmyUserclass,ImakethesetPasswordmethodthrowtheInvalidPasswordwhenitfailsthepasswordlengthcheck:publicvoidsetPassword(Stringpassword)throwsInvalidPassword{
if(password.length()<7){
thrownewInvalidPassword("Passwordmustbe>6chars");
}
this.password=password;
}
YoucanseeinthecodethatIpassinamessagetotheInvalidPasswordexceptiontodescribethecircumstancesunderwhichtheexceptionwasthrown.
Inordertocheckallofthis,Icreateaclasswith@Testmethodswhichwillcheck:
theInvalidPasswordexceptionisthrownintheconstructortheInvalidPasswordexceptionisnotthrowninthedefaultconstructortheerrormessagethrownbytheexceptioncontainsthetext“Passwordmustbe>6chars”theInvalidPasswordexceptionisthrownonsetPassword
TocheckthattheInvalidPasswordexceptionisthrownintheconstructor,Iusetheexpectedparametertocheckforthethrownexception.SincetheexceptionisacheckedexceptionIhavetoaddthethrowskeywordinthemethoddeclaration:@Test(expected=InvalidPassword.class)
publicvoidconstructUserWithException()throwsInvalidPassword{
UseraUser=newUser("username","p");
}
Tocheckthatthedefaultconstructordoesnotthrowanexception,allIdoiscreatetheUserandassertthatthedefaultpasswordwascreated.@Test
publicvoidcreateDefaultUserWithNoThrowsInvalidPasswordException(){
UseraUser=newUser();
assertEquals("password",aUser.getPassword());
}
Mythinkingaroundthiswas:
SincetheexceptionisChecked,Ican’twritethecodeiftheexceptionisthrownsinceIwouldhavetoeitheraddatrycatchblockoraddthethrowsstatementtothemethod.IassertthattheUserwascreatedcorrectlybecauseifthecreationfailedthentheassertionwouldfail.Ifanexceptionisthrownthenthe@Testmethodwillfail
Tocheckfortheerrormessage,Itryandcatchtheexception,thenchecktheerrormessage:@Test
publicvoidcreateUserWithInvalidPasswordExceptionMessages(){
UseraUser;
try{
aUser=newUser("username","p");
fail("AnInvalidPasswordExceptionshouldhavebeenthrown");
}catch(InvalidPassworde){
assertTrue(e.getMessage().startsWith("Passwordmustbe>6chars"));
}
}
NoteintheabovethatIaddafailstatementinthetryblock:
Idothisbecausetheexceptionissupposedtohavebeenthrownandthisfailstatementshouldneverbereached.IfthefailstatementisreachedthentheexceptionwasnotthrownandIneedtoforcean@Testfailure.IfIdidnotaddthefailstatementandanexceptionwasnotthrownthenthe@Testmethodwouldpass,butforthewrongreasons.
IalsomakesurethatthesetPasswordmethodthrowstheexception.@Test
publicvoidsetPasswordWithInvalidPasswordExceptionMessages(){
UseraUser=newUser();
try{
aUser.setPassword("tiny");
fail("AnInvalidPasswordExceptionshouldhavebeenthrown");
}catch(InvalidPassworde){
assertTrue(e.getMessage().startsWith("Passwordmustbe>6chars"));
}
}
Todothis,IcreatetheUserwiththedefaultconstructorsinceIknowthatwillnotthrowtheexception.ThenwrapthesetPasswordwithatrycatch.AndIrepeatthetextassertioninthecatchblock.NotethatIalsoaddthefailstatement.
Thisexerciseisagoodexampleofwhythefailstatementisimportant.Withoutthefailstatementmy@Testmethodscouldpassbecausetheydidnotthrowtheexception.
ChapterFourteen-JUnitExplored
Createan@Testmethodwhichusesalloftheasserts@Test
publicvoidjunitHasAssertions(){
assertEquals(6,3+3);
assertEquals("3+3=6",6,3+3);
assertFalse("falseisfalse",false);
assertFalse(false);
assertTrue("trueistrue",true);
assertTrue(true);
int[]oneTo10={1,2,3,4,5,6,7,8,9,10};
int[]tenToOne={10,9,8,7,6,5,4,3,2,1};
Arrays.sort(tenToOne);
assertArrayEquals(oneTo10,tenToOne);
assertNotNull("Anemptystringisnotnull","");
assertNotNull("");
assertNotSame("Anemptystringisnotnull",null,"");
assertNotSame(null,"");
assertNull("Onlynullisnull",null);
assertNull(null);
assertSame("Onlynullisnull",null,null);
assertSame(null,null);
}
ReplicatealltheJUnitAssertsusingassertThat@Test
publicvoidassertThatWithHamcrestMatchers(){
assertThat(3+3,is(6));
assertThat("3+3=6",3+3,is(6));
assertThat("falseisfalse",false,equalTo(false));
assertThat(false,is(false));
assertThat("trueistrue",true,equalTo(true));
assertThat(true,is(true));
int[]oneTo10={1,2,3,4,5,6,7,8,9,10};
int[]tenToOne={10,9,8,7,6,5,4,3,2,1};
Arrays.sort(tenToOne);
assertThat(oneTo10,equalTo(tenToOne));
assertThat("Anemptystringisnotnull","",
is(not(nullValue())));
assertThat("",is(not(nullValue())));
assertThat("",is(notNullValue()));
assertThat("Onlynullisnull",null,is(nullValue()));
assertThat(null,nullValue());
}
UsealloftheHamcrestmatcherslisted@Test
publicvoiduseTheListedHamcrestMatchers(){
assertThat(3,is(equalTo(3)));
assertThat(3,is(not(4)));
assertThat("Thisisastring",containsString("is"));
assertThat("Thisisastring",endsWith("string"));
assertThat("Thisisastring",startsWith("Thisis"));
}
ChapterFifteen-StringsRevisited
Tryusingtheotherescapecharacters@Test
publicvoidtryUsingTheOtherEscapeCharactersOutputToConsole(){
System.out.println("Newlines,andTabs");
StringfirstLine="|firstline\n";
StringsecondLine="|\tsecondline\n";
StringthirdLine="|\t\tthirdline\n";
StringfullLine=firstLine+secondLine+thirdLine;
System.out.println(fullLine);
System.out.println("Carriagereturnaftereachword");
System.out.println("one\rtwo\rthree\rfour\rfive\r");
System.out.println("Backspaceaftereachword");
System.out.println("one\btwo\bthree\bfour\bfive\b");
System.out.println("Quotesandslashes");
System.out.println("Bob\'stoysaid\"DOSuses\'\\\'\"");
}
Youprobablywon’tnoticemucheffectofsomethecharacterswhenoutputtotheconsole.i.e.\rand\b
Andsometimeswhenyououtputtexttotheconsoleyoudon’tseeexactlywhatyouexpectduetobufferingandflushingtheoutputtotheconsole,sodon’tnaturallyassumethatyourSystem.out.printlnisshowingyouabug,investigateanypotentialbuginthedebuggerorwriteanasserttocheck.
ConstructaString@Test
publicvoidcanConstructStrings(){
Stringempty=newString();
assertThat(empty.length(),is(0));
char[]cArray={'2','3'};
assertThat(newString(cArray),is("23"));
assertThat(newString(cArray,1,1),is("3"));
byte[]bArray="hellothere".getBytes();
assertThat(newString(bArray,3,3),is("lo"));
byte[]b8Array=newbyte[0];
try{
b8Array="hellothere".getBytes("UTF8");
assertThat(newString(b8Array,3,3,"UTF8"),is("lo"));
}catch(UnsupportedEncodingExceptione){
e.printStackTrace();
}
Stringhello=newString("hello"+""+"there");
assertThat(hello,is("hellothere"));
}
YoucanseethatIusedtheHamcrestmatchesandassertThattomakethecodemorereadable.
UseregionMatches@Test
publicvoidexerciseUseRegionMatches(){
Stringhello="Hellofella";
assertTrue(hello.regionMatches(true,9,"younglady",6,2));
}
IfindregionMatchespainfultouse.Imadeseveralmistakestryingtogetthematchingsyntaxlinedupwhenwritingthebookandexercises.
Remember,thefirstintegeristhestartindexintheStringwearematching,thismustmatchthefirstcharacteroftheStringwewanttofind.
Thesecondtwointegersaretheindexinthematchingstringwewantthematchingsubstringregiontostartat,andthefinalintegerthelengthofthesubstringregion.
MakesureyouwrapyourregionMatchesinanasserttocheckyoucreateditcorrectly.
FindpositionsofalloccurrencesinaStringusingindexOfprivateList<Integer>findAllOccurrences(Stringstring,
Stringsubstring){
List<Integer>results=newArrayList<Integer>();
if(string==null||substring==null){
thrownewIllegalArgumentException("Cannotsearchusingnull");
}
if(substring.isEmpty()){
thrownewIllegalArgumentException(
"CannotsearchforEmptysubstring");
}
//setsearchtothestartofthestring
intlastfoundPosition=0;
do{
//tryandfindthesubstring
lastfoundPosition=string.indexOf(substring,
lastfoundPosition);
//ifwefoundit
if(lastfoundPosition!=-1){
//addittotheresults
results.add(lastfoundPosition);
//nextstartafterthisindex
lastfoundPosition++;
}
//keeplookinguntilwecan'tfindit
}while(lastfoundPosition!=-1);
returnresults;
}
Imayhaveaddedmoreparameterchecksthanyoudid,butsinceI’mreleasingthecodeinabook,I’mtheoneonthereceivingendofemailsthatsay“Youcan’tcode.WhenIpassanemptysubstringinthenthereisaninfiniteloop”etc.etc.
Itisworthgettinginthehabitoftryingtomakeyourcodeasrobustasyoucan.
ItmightalsohelptoseethecodethatIwrotefirst,tohelpmeconstructthismethod.@Test
publicvoidcanFindAllOccurrencesInStringUsingIndexOf(){
List<Integer>results;
results=findAllOccurrences("Hellofella","l");
assertThat(results.size(),is(4));
assertThat(results.contains(2),is(true));
assertThat(results.contains(3),is(true));
assertThat(results.contains(8),is(true));
assertThat(results.contains(9),is(true));
assertThat(results.get(0),is(2));
assertThat(results.get(1),is(3));
assertThat(results.get(2),is(8));
assertThat(results.get(3),is(9));
}
IntheabovecodeyoucanseethatIhavetwochecksforthevalues,usingthe.containsassertThat(results.contains(2),is(true));
Andusingthe.getassertThat(results.get(0),is(2));
MyfeelingwasthatIfirstwantedtomakesurethatthecorrectvalueswereinthelist,andthenIwantedtocheckiftheywereintherightorder.
Thisway,ifIsomehowdidtheminthewrongorder,onlythe.getwouldfail.ButifIfailedtofindtheoccurrencethenthecontainswouldfail.
Itmightseemredundanttohavebothcontainsandget,butIthinkthatbydoingthisthe@TestmethodwillmostlikelyhelpmeinthefutureifIrefactorandsomehowgettheorderofthereturnvalueswrong.
Havingwrittentheabovecode,Istartedtothinkaboutwhatotherparametersthemethodmightbeexpectedtohandle,andwrotethe@Testmethodswhich‘stress’themethod.
Thesehelpedmeaddtheparametercheckingcode.@Test
publicvoidworksWhenNothingToFind(){
List<Integer>results;
results=findAllOccurrences("Hellofella","z");
assertThat(results.size(),is(0));
results=findAllOccurrences("","z");
assertThat(results.size(),is(0));
}
@Test(expected=IllegalArgumentException.class)
publicvoidcannotSearchForEmpty(){
List<Integer>results=findAllOccurrences("","");
}
@Test(expected=IllegalArgumentException.class)
publicvoidcannotSearchForNullString(){
List<Integer>results=findAllOccurrences(null,"hello");
}
@Test(expected=IllegalArgumentException.class)
publicvoidcannotSearchForNullSubString(){
List<Integer>results=findAllOccurrences("hello",null);
}
@Test(expected=IllegalArgumentException.class)
publicvoidcannotSearchForNulls(){
List<Integer>results=findAllOccurrences(null,null);
}
usinglastIndexOf
ToreversethelistIreliedonthelastIndexOfmethod.
Themain@TestmethodIusedwas:@Test
publicvoidcanFindAllOccurrencesInStringUsingLastIndexOf(){
List<Integer>results;
results=findAllOccurrences("Hellofella","l");
assertThat(results.size(),is(4));
assertThat(results.contains(2),is(true));
assertThat(results.contains(3),is(true));
assertThat(results.contains(8),is(true));
assertThat(results.contains(9),is(true));
assertThat(results.get(0),is(9));
assertThat(results.get(1),is(8));
assertThat(results.get(2),is(3));
assertThat(results.get(3),is(2));
}
IhavenotincludedtheadditionalmethodsthatIusedtocheckthismethod,buttheyaremuchthesameasthoseusedfortheindexOfapproach.privateList<Integer>findAllOccurrences(Stringstring,
Stringsubstring){
List<Integer>results=newArrayList<Integer>();
if(string==null||substring==null){
thrownewIllegalArgumentException("Cannotsearchusingnull");
}
if(substring.isEmpty()){
thrownewIllegalArgumentException(
"CannotsearchforEmptysubstring");
}
//setsearchtothestartofthestring
intlastfoundPosition=string.length();
do{
//tryandfindthesubstring
lastfoundPosition=string.lastIndexOf(substring,
lastfoundPosition);
//ifwefoundit
if(lastfoundPosition!=-1){
//addittotheresults
results.add(lastfoundPosition);
//nextstartbeforethisindex
lastfoundPosition--;
}
//keeplookinguntilwecan'tfindit
}while(lastfoundPosition!=-1);
returnresults;
}
RegularExpressionsforUsersetPasswordpublicvoidsetPassword(Stringpassword)throwsInvalidPassword{
if(password.length()<7){
thrownewInvalidPassword("Passwordmustbe>6chars");
}
if(!password.matches(".*[0123456789]+.*")){
thrownewInvalidPassword(
"Passwordmusthaveadigit");
}
if(!password.matches(".*[A-Z]+.*")){
thrownewInvalidPassword(
"PasswordmusthaveanUppercaseLetter");
}
this.password=password;
}
AndofcourseIhavetochangethedefaultconstructoronUseraswell,otherwiseitwillfailthevalidation:publicUser(){
this("username","Passw0rd",false);
}
Sincethedefaultpasswordhastochange,Ihadtoamendthecheckingcodesurroundingthisclassaswell.
CheckStringBuilderresizes@Test
publicvoidcapacitySizeIncreasesAutomaticallyWithAppend(){
StringBuilderbuilder=newStringBuilder(5);
assertThat(builder.capacity(),is(5));
builder.append("HelloWorld");
assertThat(builder.capacity()>5,is(true));
}
InsertintoaStringBuilder@Test
publicvoidwriteATestToInsert(){
StringBuilderbuilder=newStringBuilder();
//insertatstart
builder.insert(0,"a");
assertThat(builder.toString(),is("a"));
//inserttoend
builder.insert(builder.toString().length(),"b");
assertThat(builder.toString(),is("ab"));
//inserttomiddle
builder.insert(1,".");
assertThat(builder.toString(),is("a.b"));
}
ChapterSixteen-RandomData
Create@TestmethodsWhichConfirmRandomLimitsThebasic@TestmethodIcreatedlookslikethefollowing:@Test
publicvoidcanGenerateRandomInt(){
Randomgenerate=newRandom();
for(intx=0;x<1000;x++){
intrandomInt=generate.nextInt();
System.out.println(randomInt);
assertThat(randomInt<Integer.MAX_VALUE,is(true));
assertThat(randomInt>=Integer.MIN_VALUE,is(true));
}
}
IuseSystem.out.printlntodisplaythevaluestotheconsole,justsoIcanseetherandomrange.AndIassertontheconditionsmentionedinthedocumentation.
Allothermethodstakethesameform,withadifferentrandomgenerationapproach.
Forthebooleanchecks,Icountthetrueandfalsevaluestomakesurethatbothvaluesaregenerated,andassertonthetotal:@Test
publicvoidcanGenerateRandomBoolean(){
Randomgenerate=newRandom();
intcountTrue=0;
intcountFalse=0;
for(intx=0;x<1000;x++){
booleanrandomBoolean=generate.nextBoolean();
if(randomBoolean)
countTrue++;
if(randomBoolean==false)
countFalse++;
System.out.println(randomBoolean);
}
System.out.println(
String.format("Generated%dastrue",countTrue));
System.out.println(
String.format("Generated%dasfalse",countFalse));
assertThat(countTrue>0,is(true));
assertThat(countFalse>0,is(true));
assertThat(countTrue+countFalse,is(1000));
}
Sinceallother@Testmethodstakethesameform,Ihavenotincludedthefullcodebelow,justthesubsetthathastherandomgenerationandtheassertions.
CheckingforLonglongrandomLong=generate.nextLong();
System.out.println(randomLong);
assertThat(randomLong<Long.MAX_VALUE,is(true));
assertThat(randomLong>=Long.MIN_VALUE,is(true));
NotethatthedocumentationfornextLongreportsthatthealgorithmwillnotreturnalllongvalues.
CheckingforFloatfloatrandomFloat=generate.nextFloat();
System.out.println(randomFloat);
assertThat(randomFloat<1.0f,is(true));
assertThat(randomFloat>=0.0f,is(true));
Notethattheupperlimitcheckisexclusive(<)andthelowerlimitcheckisinclusive(>=).
CheckingforDoubledoublerandomDouble=generate.nextDouble();
System.out.println(randomDouble);
assertThat(randomDouble<1.0d,is(true));
assertThat(randomDouble>=0.0d,is(true));
Notethattheupperlimitcheckisexclusive(<)andthelowerlimitcheckisinclusive(>=).
CheckingforByte//randomlygenerateabytearraybetween0and99length
intarrayLength=generate.nextInt(100);
byte[]bytes=newbyte[arrayLength];
generate.nextBytes(bytes);//fillbyteswithrandomdata
Assert.assertEquals(arrayLength,bytes.length);
Stringviewbytes=newString(bytes);
System.out.println(bytes.length+"-"+viewbytes);
NotethatIrandomlygeneratethesizeofthebytearray.
CheckingforIntRangeintrandomIntRange=generate.nextInt(12);
System.out.println(randomIntRange);
assertThat(randomIntRange<=11,is(true));
assertThat(randomIntRange>=0,is(true));
NotethatIgeneratebelow12somyassertionisfrom0to11inclusive
Createan@Testmethodwhichgenerates1000numbersinclusivelybetween15and20@Test
publicvoidgenerateRandomIntGivenRangeNot0(){
Randomgenerate=newRandom();
intminValue=1;
intmaxValue=5;
intrandomIntRange=generate.nextInt(
maxValue-minValue+1)+minValue;
assertThat(randomIntRange<=maxValue,is(true));
assertThat(randomIntRange>=minValue,is(true));
}
Intheabovecode,Ilooparound1000timesinordertomakesurethatIdon’tjusthitoneluckynumberthatpassesmyassertions.
Istorethegeneratednumbersinaset:
thispreventsduplicatessoeachnumbergeneratedwillonlyappearoncethismeansthatthesizeofthesetisthenumberofdifferentintegersgenerated
Iassertonthesizeoftheset,becauseIknowthat6numbersaresupposedtobegenerated.
Iassertthateachofthenumbers{15,16,17,18,19,20}hasbeengenerated.
Writean@Testmethodthatshowsthedistributions@Test
publicvoidcanGenerateRandomGaussianDistributionDouble(){
Randomgenerate=newRandom();
intstandardDeviationCount1=0;
intstandardDeviationCount2=0;
intstandardDeviationCount3=0;
intstandardDeviationCount4=0;
for(intx=0;x<1000;x++){
doublerandomGaussian=generate.nextGaussian();
//System.out.println(randomValue);
if(randomGaussian>-1.0d&&randomGaussian<1.0d)
standardDeviationCount1++;
if(randomGaussian>-2.0d&&randomGaussian<2.0d)
standardDeviationCount2++;
if(randomGaussian>-3.0d&&randomGaussian<3.0d)
standardDeviationCount3++;
if(randomGaussian>-4.0d&&randomGaussian<4.0d)
standardDeviationCount4++;
}
floatsd1percentage=(standardDeviationCount1/1000f)*100f;
System.out.println("about70%onestandarddeviation="+
sd1percentage);
floatsd2percentage=(standardDeviationCount2/1000f)*100f;
System.out.println("about95%twostandarddeviation="+
sd2percentage);
floatsd3percentage=(standardDeviationCount3/1000f)*100f;
System.out.println("about99%threestandarddeviation="+
sd3percentage);
floatsd4percentage=(standardDeviationCount4/1000f)*100f;
System.out.println("about99.9%fourstandarddeviation="+
sd4percentage);
Assert.assertTrue(sd1percentage<sd2percentage);
Assert.assertTrue(sd2percentage<sd3percentage);
//Idonotassertthatsd3andsd4aredifferent
//becauseofthesmall%difference,theydooverlap
}
Writean@Testmethodwhichgenerates1000agesusingnextGaussian@Test
publicvoidcanGenerate1000AgesUsingDeviation(){
Randomgenerate=newRandom();
Map<Integer,Integer>ages=
newHashMap<Integer,Integer>();
for(intx=0;x<1000;x++){
intage=(int)(generate.nextGaussian()*5)+35;
intageCount=0;
if(ages.containsKey(age)){
ageCount=ages.get(age);
}
ageCount++;
ages.put(age,ageCount);
}
SortedSet<Integer>agesSorted=newTreeSet(ages.keySet());
for(intage:agesSorted){
System.out.println(age+":"+ages.get(age));
}
}
Createan@TestmethodforRandomwithSeed@Test
publicvoidcanGenerateRandomNumbersWithSeed(){
for(intx=0;x<10;x++){
Randomgenerate=newRandom(1234567L);
assertThat(generate.nextInt(),is(1042961893));
assertThat(generate.nextLong(),is(-6749250865724111202L));
assertThat(generate.nextDouble(),is(0.44762832574617084D));
assertThat(generate.nextGaussian(),is(-0.11571220872310763D));
assertThat(generate.nextFloat(),is(0.33144182F));
assertThat(generate.nextBoolean(),is(false));
}
}
InordertoidentifythevaluesIneededtoasserton,IfirstcreatedaSystem.out.printlnforeachofthelines,thenusedthevalueoutputtotheconsoleasthevaluetoasserton.
GenerateaRandomString100charslong@Test
publicvoidgenerateARandomString(){
StringvalidValues="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuilderrString;
Randomrandom=newRandom();
rString=newStringBuilder();
for(intx=0;x<100;x++){
intrndIndex=random.nextInt(validValues.length());
charrChar=validValues.charAt(rndIndex);
rString.append(rChar);
}
System.out.println(rString.toString());
Assert.assertTrue(rString.length()==100);
Assert.assertTrue(rString.toString().matches("[A-Z]+"));
}
YoucanseethatIassertonthelengthoftheString,andusearegularexpressiontocheckthatthecharactersinthestringarefromA-Zorspacei.e.“[A-Z]+”
IalsouseaStringBuildertohelpmeconstructthestringbyappendingeachoftherandomlygeneratedcharacters.
ChapterSeventeen-Dates&Times
Re-writethetiming@TestmethodusingnanoTime@Test
publicvoidnanoTime(){
longstartTime=System.nanoTime();
for(intx=0;x<10;x++){
System.out.println("CurrentTime"+System.nanoTime());
}
longendTime=System.nanoTime();
System.out.println("TotalTime"+(endTime-startTime));
}
UsecurrentTimeMillistocreateauniquenamewithnonumbersTherearelotsofwaysofimplementingthisexercise.1@Test
2publicvoidcreateAUniqueUserIDAllChars(){
3
4StringinitialUserID="user"+System.currentTimeMillis();
5System.out.println(initialUserID);
6
7StringuserID=initialUserID;
8
9for(intx=0;x<10;x++){
10StringcharReplacement=""+((char)('A'+x));
11StringintToReplace=String.valueOf(x);
12userID=userID.replace(intToReplace,charReplacement);
13}
14
15assertThat(userID.contains("0"),is(false));
16assertThat(userID.contains("1"),is(false));
17assertThat(userID.contains("2"),is(false));
18assertThat(userID.contains("3"),is(false));
19assertThat(userID.contains("4"),is(false));
20assertThat(userID.contains("5"),is(false));
21assertThat(userID.contains("6"),is(false));
22assertThat(userID.contains("7"),is(false));
23assertThat(userID.contains("8"),is(false));
24assertThat(userID.contains("9"),is(false));
25
26assertThat(initialUserID.length(),is(userID.length()));
27
28System.out.println(userID);
29}
line10-Imadeitsimpleandeasybyusingthefactthat‘A’(achar)canbeaddedtoanintegertogetanewasciicharacter,thencasttheinttoacharandthenconcatenateitwithanemptyStringtocreateacharacterstringthatrepresentsanumber.line11-IconverttheinttoaStringline12-IthenreplacealltheintegerrepresentationsintheStringwiththiscalculatedcharactere.g.
'A'+0wouldequal'A',andIwouldreplaceall0intheStringwith'A''A'+1wouldequal'B',andIwouldreplaceall1intheStringwith'B'etc.
Therestofthecodecontainsassertionstocheckthatnodigitsareinthename.
WritethetoStringtoconsole@Test
publicvoidwriteCalendarToStringToConsole(){
Calendarcal=Calendar.getInstance();
System.out.println(cal.toString());
}
UsetheotherCalendarconstants@Test
publicvoiduseOtherCalendarConstants(){
Calendarcal=Calendar.getInstance();
cal.set(2013,Calendar.DECEMBER,15,23,39,54);
assertThat(cal.get(Calendar.MONTH),is(Calendar.DECEMBER));
assertThat(cal.get(Calendar.YEAR),is(2013));
assertThat(cal.get(Calendar.DAY_OF_MONTH),is(15));
assertThat(cal.get(Calendar.HOUR_OF_DAY),is(23));
assertThat(cal.get(Calendar.MINUTE),is(39));
assertThat(cal.get(Calendar.HOUR),is(11));
assertThat(cal.get(Calendar.AM_PM),is(Calendar.PM));
}
Experimentwithotherconstants@Test
publicvoidexperimentWithCalendarConstants(){
Calendarcal=Calendar.getInstance();
cal.set(2013,Calendar.DECEMBER,15,23,39,54);
assertThat(cal.get(Calendar.DAY_OF_WEEK),is(1));
assertThat(cal.get(Calendar.DAY_OF_WEEK),is(Calendar.SUNDAY));
assertThat(cal.get(Calendar.WEEK_OF_MONTH),is(2));
assertThat(cal.get(Calendar.WEEK_OF_YEAR),is(50));
assertThat(cal.get(Calendar.DAY_OF_YEAR),is(349));
}
IncrementandDecrementotherFields@Test
publicvoidincrementAndDecrementOtherFields(){
Calendarcal=Calendar.getInstance();
cal.set(2013,Calendar.DECEMBER,15,23,39,54);
cal.add(Calendar.YEAR,-2);
cal.add(Calendar.MONTH,-6);
cal.add(Calendar.DAY_OF_MONTH,-12);
assertThat(cal.get(Calendar.YEAR),is(2011));
assertThat(cal.get(Calendar.MONTH),is(Calendar.JUNE));
assertThat(cal.get(Calendar.DAY_OF_MONTH),is(3));
cal.set(2013,Calendar.DECEMBER,15,23,39,54);
//bumpitforwardto3rdJune2014,
//thenpullitback
cal.add(Calendar.DAY_OF_MONTH,19);
cal.add(Calendar.MONTH,5);
cal.add(Calendar.YEAR,-3);
assertThat(cal.get(Calendar.YEAR),is(2011));
assertThat(cal.get(Calendar.MONTH),is(Calendar.JUNE));
assertThat(cal.get(Calendar.DAY_OF_MONTH),is(3));
}
ConfirmaddMovestheYear@Test
publicvoidrollCalendar(){
Calendarcal=Calendar.getInstance();
cal.set(2013,Calendar.DECEMBER,15,23,39,54);
cal.roll(Calendar.DAY_OF_MONTH,17);
assertThat(cal.get(Calendar.YEAR),is(2013));
assertThat(cal.get(Calendar.MONTH),is(Calendar.DECEMBER));
assertThat(cal.get(Calendar.DAY_OF_MONTH),is(1));
cal.set(2013,Calendar.DECEMBER,15,23,39,54);
cal.add(Calendar.DAY_OF_MONTH,17);
assertThat(cal.get(Calendar.YEAR),is(2014));
assertThat(cal.get(Calendar.MONTH),is(Calendar.JANUARY));
assertThat(cal.get(Calendar.DAY_OF_MONTH),is(1));
}
ChapterEighteen-PropertiesandPropertyFiles
CreateandListaPropertiesobject@Test
publicvoidcanCreateAndListTheProperties(){
Propertiesproperties=newProperties();
properties.setProperty("name","bob");
properties.setProperty("gender","male");
properties.setProperty("password","paSSw0rd");
assertThat(properties.stringPropertyNames().size(),is(3));
for(Stringkey:properties.stringPropertyNames()){
System.out.println("Key:"+key+""+
"Value:"+properties.getProperty(key));
}
properties.list(System.out);
Assert.assertTrue(properties.containsKey("gender"));
Assert.assertEquals("bob",properties.getProperty("name"));
Assert.assertEquals("Admin",
properties.getProperty("permission","Admin"));
}
StoreandLoadaSavedPropertiesFile@Test
publicvoidcanSaveAndLoadAPropertiesFile()throwsIOException{
StringtempDirectory=System.getProperty("java.io.tmpdir");
StringtempResourceFilePath=tempDirectory+
System.currentTimeMillis()+
System.nanoTime()+
".properties";
Propertiessaved=newProperties();
longnanoTime=System.nanoTime();
longmillis=System.currentTimeMillis();
saved.setProperty("nanoTime",String.valueOf(nanoTime));
saved.setProperty("millis",String.valueOf(millis));
FileOutputStreamoutputFile=
newFileOutputStream(tempResourceFilePath);
saved.store(outputFile,"TimeDataWhenFileWritten");
outputFile.close();
FileReaderpropertyFileReader=
newFileReader(tempResourceFilePath);
Propertiesloaded=newProperties();
try{
loaded.load(propertyFileReader);
}finally{
propertyFileReader.close();
}
assertThat(loaded.getProperty("nanoTime"),
is(String.valueOf(nanoTime)));
assertThat(loaded.getProperty("millis"),
is(String.valueOf(millis)));
newFile(tempResourceFilePath).delete();
}
ChapterNineteen-Files
CreateaTempFileandVarytheParameters@Test
publicvoidcreateTempFileVaryTheParameters()throwsIOException{
//onwindowsthesefilesarein%TEMP%
Filetemp1=File.createTempFile("temp1",null);
Filetemp2=File.createTempFile("temp2OutFile",".out");
assertThat(temp1.exists(),is(true));
assertThat(temp2.exists(),is(true));
temp1.deleteOnExit();
temp2.deleteOnExit();
}
YoucanseethatIcheatedandusedtheexistsmethodtocheckforexistence,andIusedthedeleteOnExittoremovethecreatedtempfileswhenthecodeexecutioncompletes.
Butnotethat,hadsomethinggonewrongduringtheexecutionandanexceptionthrown,thefilesprobablywouldnothavebeendeleted.Ishouldreallyuseatry/finallyblockwhenworkingwithfiles.
Writeouttheroots@Test
publicvoidwriteOutTheFileListRoots(){
File[]roots=File.listRoots();
Assert.assertTrue(roots.length>0);
for(FileaFile:roots){
System.out.println(aFile.getAbsolutePath());
}
}
CreateaTemporaryFileWithCustomCode@Test
publicvoidcreateATempFileWithCustomCode()throwsIOException{
Stringdirectory=System.getProperty("java.io.tmpdir");
StringfileName="prefix"+System.currentTimeMillis()+".tmp";
FileaTempFile=newFile(directory,fileName);
assertThat(aTempFile.exists(),is(false));
aTempFile.createNewFile();
assertThat(aTempFile.exists(),is(true));
aTempFile.delete();
assertThat(aTempFile.exists(),is(false));
}
Writean@TestmethodToCheckCanonicalConversion
@Test
publicvoidwriteATestToCheckCanonicalConversion()throwsIOException{
Fileabsolute1=newFile("C:/1/2/3/4/../../..");
Fileabsolute2=newFile("C:/1/2/../../1");
Filecanonical=newFile("C:/1");
assertThat(canonical.getAbsolutePath(),
is(canonical.getCanonicalPath()));
assertThat(canonical.getAbsolutePath(),
is(absolute1.getCanonicalPath()));
assertThat(canonical.getAbsolutePath(),
is(absolute2.getCanonicalPath()));
assertThat(absolute1.getAbsolutePath().contains(".."),is(true));
assertThat(absolute2.getAbsolutePath().contains(".."),is(true));
}
CheckthattheTempDirectoryisaDirectory@Test
publicvoidcheckThatTheTempDirectoryIsADirectory(){
FiletempDir=newFile(System.getProperty("java.io.tmpdir"));
assertThat(tempDir.isDirectory(),is(true));
assertThat(tempDir.isFile(),is(false));
}
WritetoaPrintWriterthenAppend@Test
publicvoidexerciseWriteToAPrintWriterThenAppend()throwsIOException{
FileoutputFile=File.createTempFile("printWriterPrint",null);
System.out.println("Checkfile"+outputFile.getAbsolutePath());
FileWriterwriter=newFileWriter(outputFile);
BufferedWriterbuffer=newBufferedWriter(writer);
PrintWriterprint=newPrintWriter(buffer);
print.println("AppendPrinttoBufferedWriter");
print.close();
//appendtothefile
writer=newFileWriter(outputFile,true);
buffer=newBufferedWriter(writer);
print=newPrintWriter(buffer);
print.println("===============================");
print.close();
StringlineEnd=System.lineSeparator();
longfileLen=62L+lineEnd.length()+lineEnd.length();
assertThat(outputFile.length(),is(fileLen));
}
CreateaFileandCalculatethelength
@Test
publicvoidspaceMethods()throwsIOException{
Filetemp=newFile(System.getProperty("java.io.tmpdir"));
longfreeSpace=temp.getFreeSpace();
longtotalSpace=temp.getTotalSpace();
longusableSpace=temp.getUsableSpace();
FileoutputFile=writeTheTestDataFile(5);
assertThat(outputFile.length(),is(expectedFileSize(5)));
System.out.println("Length"+outputFile.length());
System.out.println("Free"+freeSpace);
System.out.println("Total"+totalSpace);
System.out.println("Usable"+usableSpace);
}
privatelongexpectedFileSize(intlines){
StringlineEnd=System.lineSeparator();
return(("linex".length()+lineEnd.length())*lines);
}
privateFilewriteTheTestDataFile(intlines)throwsIOException{
FileoutputFile=File.createTempFile(
"forReading"+lines+"_",null);
PrintWriterprint=newPrintWriter(
newBufferedWriter(
newFileWriter(outputFile)));
for(intline=0;line<lines;line++){
print.println("line"+lines);
}
print.close();
returnoutputFile;
}
UselistFilestoshowtheTempDirectorycontents@Test
publicvoidlistTempDirectory(){
FiletempDir=newFile(System.getProperty("java.io.tmpdir"));
File[]fileList=tempDir.listFiles();
for(FilefileInList:fileList){
StringoutputString="";
if(fileInList.isDirectory()){
outputString=outputString+"DIR:";
}else{
outputString=outputString+"FIL:";
}
outputString=outputString+fileInList.getName();
System.out.println(outputString);
}
}
OutputAttributesofFilesInTempDirectory
@Test
publicvoidlistTempDirectoryAttribs(){
FiletempDir=newFile(System.getProperty("java.io.tmpdir"));
File[]fileList=tempDir.listFiles();
for(FilefileInList:fileList){
StringoutputString="";
if(fileInList.isDirectory()){
outputString=outputString+"DIR:";
}else{
outputString=outputString+"FIL:";
}
if(fileInList.canRead()){
outputString=outputString+"r";
}else{
outputString=outputString+"-";
}
if(fileInList.canWrite()){
outputString=outputString+"w";
}else{
outputString=outputString+"-";
}
if(fileInList.canExecute()){
outputString=outputString+"x";
}else{
outputString=outputString+"-";
}
outputString=outputString+"-"+fileInList.getName();
SimpleDateFormatsdf=newSimpleDateFormat("yMdHH:mm:ss.SSS");
StringlastModified=
sdf.format(newDate(fileInList.lastModified()));
outputString=outputString+"=>"+lastModified;
System.out.println(outputString);
}
}
copyAndmoveaFile@Test
publicvoidcopyFile()throwsIOException{
FilecopyThis=writeTheTestDataFile();
FiletoThis=newFile(copyThis.getCanonicalPath()+".copy");
assertThat(toThis.exists(),is(false));
Files.copy(copyThis.toPath(),toThis.toPath());
assertThat(toThis.exists(),is(true));
assertThat(copyThis.length(),is(toThis.length()));
}
@Test
publicvoidmoveFile()throwsIOException{
FilemoveThis=writeTheTestDataFile();
FiletoThis=newFile(moveThis.getCanonicalPath()+".moved");
assertThat(moveThis.exists(),is(true));
assertThat(toThis.exists(),is(false));
Files.move(moveThis.toPath(),toThis.toPath(),
REPLACE_EXISTING,ATOMIC_MOVE);
assertThat(toThis.exists(),is(true));
assertThat(moveThis.exists(),is(false));
}
privateFilewriteTheTestDataFile()throwsIOException{
FileoutputFile=File.createTempFile("forReading",null);
PrintWriterprint=newPrintWriter(
newBufferedWriter(
newFileWriter(outputFile)));
for(intlineNumber=1;lineNumber<6;lineNumber++){
print.println("line"+lineNumber);
}
print.close();
returnoutputFile;
}
ChapterTwenty-MathandBigDecimal
ConvinceYourselfofBigDecimalorint@Test
publicvoidconvinceYourselfOfBigDecimalUsage(){
try{
doubletotal=5-0.3-0.47-1.73;
System.out.println("2.5!="+total);
assertThat(total,is(2.5));
fail("Expectedtheasserttofail");
}catch(java.lang.AssertionErrore){}
intinPennies=500-30-47-173;
assertThat(inPennies,is(250));
BigDecimalbdTotal=newBigDecimal("5").
subtract(newBigDecimal("0.30")).
subtract(newBigDecimal(("0.47"))).
subtract(newBigDecimal("1.73"));
assertThat(bdTotal,is(newBigDecimal("2.50")));
}
BasicArithmeticwithBigDecimal@Test
publicvoidbasicArithmeticWithBigDecimal(){
BigDecimalbd=BigDecimal.ZERO;
bd=bd.add(BigDecimal.TEN);
bd=bd.multiply(BigDecimal.valueOf(2L));
bd=bd.subtract((BigDecimal.TEN));
bd=bd.divide(BigDecimal.valueOf(2L));
assertThat(bd,is(BigDecimal.valueOf(5L)));
}
Onmysystem,theresultofthedoublecalculationcameto"2.5000000000000004"whichwouldnotequal2.5.SoalwaysremembertouseBigDecimalwhencomparingwiththeresultsofexternalsystemsorforfinancialandcurrencytransactions.
CompareTENandONE@Test
publicvoidbigDecimalCompareTenAndOne(){
assertTrue(BigDecimal.TEN.compareTo(BigDecimal.ONE)>0);
assertTrue(BigDecimal.ONE.compareTo(BigDecimal.TEN)<0);
assertTrue(BigDecimal.TEN.compareTo(BigDecimal.TEN)==0);
assertTrue(BigDecimal.TEN.compareTo(BigDecimal.ONE)!=0);
assertTrue(BigDecimal.TEN.compareTo(BigDecimal.ONE)>=0);
assertTrue(BigDecimal.TEN.compareTo(BigDecimal.TEN)>=0);
assertTrue(BigDecimal.TEN.compareTo(BigDecimal.TEN)<=0);
assertTrue(BigDecimal.ONE.compareTo(BigDecimal.TEN)<=0);
}
ChapterTwentyOne-CollectionsRevisited
Removeif(val==0)userSortedList.add(bob);
userSortedList.add(dupebob);
userSortedList.add(rich);
userSortedList.add(dupebob2);
assertEquals(2,userSortedList.size());
userSortedList.add(mrBeer);
assertEquals("MrBeercouldnotbeadded",2,userSortedList.size());
Withouttheval==0linesintheComparatorIcannotaddthemrBeerobjecttotheSortedSet
//if(val==0){
//val=user1.getUsername().compareTo(user2.getUsername());
//}
DisallowDuplicateUserNamesThecodeIcreated:@Test
publicvoidsortedSetWithComparatorForUser(){
Userbob=newUser("Bob","pA55Word");//11
Userdupebob=newUser("Bob","hello");
Userrich=newUser("Richie","RichieRichieRich");//22
Userdupebob2=newUser("Bob","BobsMightyBigBobPassword");
UsermrBeer=newUser("Stafford","sys");//11
SortedSet<User>userSortedList=
newTreeSet<User>(newUserComparatorDisallowDupes());
userSortedList.add(bob);
userSortedList.add(dupebob);
userSortedList.add(rich);
userSortedList.add(dupebob2);
userSortedList.add(mrBeer);
assertEquals(3,userSortedList.size());
User[]users=newUser[userSortedList.size()];
userSortedList.toArray(users);
assertEquals(bob.getUsername(),users[0].getUsername());
assertEquals(mrBeer.getUsername(),users[1].getUsername());
assertEquals(rich.getUsername(),users[2].getUsername());
}
AndtheassociatedUserComparatorDisallowDupesclass:publicclassUserComparatorDisallowDupesimplementsComparator{
publicintcompare(ObjectoUser1,ObjectoUser2){
Useruser1=(User)oUser1;
Useruser2=(User)oUser2;
if(user1.getUsername().compareTo(user2.getUsername())==0){
return0;
}
intuser1Comparator=user1.getPassword().length()+
user1.getUsername().length();
intuser2Comparator=user2.getPassword().length()+
user2.getUsername().length();
intval=user1Comparator-user2Comparator;
if(val==0){
val=user1.getUsername().compareTo(user2.getUsername());
}
returnval;
}
}
UserclassimplementsComparableThebasicchangesImadetotheUserclassweretotheclassdefinition:publicclassUserimplementsComparable{
ThenIalsoaddedthecompareTomethod:@Override
publicintcompareTo(ObjectoUser2){
Useruser2=(User)oUser2;
if(this.getUsername().compareTo(user2.getUsername())==0){
return0;
}
intuser1Comparator=this.getPassword().length()+
this.getUsername().length();
intuser2Comparator=user2.getPassword().length()+
user2.getUsername().length();
intval=user1Comparator-user2Comparator;
if(val==0){
val=this.getUsername().compareTo(user2.getUsername());
}
returnval;
}
ThenIcreateda@Testtousedemonstrateit:@Test
publicvoidsortedSetWithComparableUser(){
Userbob=newUser("Bob","pA55Word");//11
Userdupebob=newUser("Bob","hello");
Userrich=newUser("Richie","RichieRichieRich");//22
Userdupebob2=newUser("Bob","BobsMightyBigBobPassword");
UsermrBeer=newUser("Stafford","sys");//11
SortedSet<User>userSortedList=newTreeSet<User>();
userSortedList.add(bob);
userSortedList.add(dupebob);
userSortedList.add(rich);
userSortedList.add(dupebob2);
userSortedList.add(mrBeer);
assertEquals(3,userSortedList.size());
User[]users=newUser[userSortedList.size()];
userSortedList.toArray(users);
assertEquals(bob.getUsername(),users[0].getUsername());
assertEquals(mrBeer.getUsername(),users[1].getUsername());
assertEquals(rich.getUsername(),users[2].getUsername());
}
SeethesortinactionWhenIaddedtheline:System.out.println("Compare"+user1.getUsername()+
"with"+user2.getUsername()+"="+val);
Theoutputfromtheexecutionshowed:1CompareRichiewithBob=11
2CompareStaffordwithBob=17
3CompareStaffordwithRichie=-11
ThismeansthatIonlyreachedthe‘dupe’checkforthreeaddcalls.Alltheothercallstheresultofthecomparisonwasbasedontheduplicateusernamecheck.
AccessValuesinMapinKeyorder
@Test
publicvoidexerciseCanGetAllKeysAsSortedSet(){
Map<String,String>map=newHashMap<>();
map.put("key4","value4");
map.put("key2","value2");
map.put("key1","value1");
map.put("key3","value3");
SortedSet<String>keys=newTreeSet<String>(map.keySet());
intvalSuffix=1;
for(Stringkey:keys){
assertEquals("value"+valSuffix,
map.get(key));
valSuffix+=1;
}
}
IntheabovecodeIaddthevaluesoutoforderintoaMap.NotaSortedMap,soIknowIcan’trelyontheorder.
IconstructaTreeSetfromtheSetreturnedbymap.keySet(),soInowhaveaSortedSetofkeys.
Todemonstratethatthesorthasworked,IpredictthevalueIexpectbyincrementingvalSuffixfrom1to4,theniterateoverthekeystocheckthatthevaluefromthemapisthevalueIpredicted.