Java For Testers - DropPDF1.droppdf.com/files/JH9ax/java-for-testers-learn-java-fundamentals... ·...

Post on 31-Jan-2018

223 views 1 download

Transcript of Java For Testers - DropPDF1.droppdf.com/files/JH9ax/java-for-testers-learn-java-fundamentals... ·...

JavaForTesters

LearnJavafundamentalsfastThisversionwaspublishedon2015-02-27

TherightofAlanRichardsontobeidentifiedastheauthorofthisworkhasbeenassertedbyhiminaccordancewiththeCopyright,DesignandPatentsAct1988.

Theviewsexpressedinthisbookarethoseoftheauthor.

FirstpublishedinGreatBritainin2015by:

CompendiumDevelopmentshttp://www.compendiumdev.co.uk

contactdetails:

alan@compendiumdev.co.uk

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{

}

Thenaddan@Testmethod.I’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"withnullandrunthe@Testmethod.Whathappens?

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,sothatthe@Testmethodcanpass.publicStringgetUsername(){

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.