Java Programmering - 5. del

Tags:    java
Skrevet af Bruger #4487 @ 07.12.2010

Indledning


Vi har indtil nu, lavet Java kode, hvor brugeren, ikke rigtigt havde noget at skulle have sagt. Alle vores elementer i vores ArrayList'er, har været for programmeret, og stod ikke til at kunne ændres. I denne del, skal vi se lidt på hvordan man kan få brugeren til at agere sammen med vores program. Vi kunne kalde programmet for en slags Tech-Support System, hvor brugeren, kan spørge om ting, og der bliver så givet et autogenereret svar til brugeren. Da dette er en helt så let sag, som det lyder, kan vi ikke undgå teorien, men frygt ej, da teorien er vigtig for at blive en god programmør.

Tech Support System


Systemet består af tre klasser, nemlig en InputReader klasse, som har til formål at læse det input, som brugeren giver. Den næste klasse er en Responder klasse, som har til formål at autogenerere et svar til brugeren, ud fra hans input. Den sidste klasse er en slags controller klasse, som skal holde styr på input og output, og er derfor også vores 'Main' klasse. Denne klasse kunne vi kalde TechSupportSystem. Lad os komme i gang med vores System.

HashSet og Scanner klasserne


Vi skal i gang med vores første klasse, som var InputReader. Denne klasse for brug for at importere to forskellige klasser, fra vores Java bibliotek. De to klasser hedder henholdsvis HashSet og Scanner. Lad os starte med at finde ud af hvad klassen HashSet, er for en størrelse.

Mini Opgave - Åben dit Java Bibliotek, og find klassen HashSet. Prøv nu at læse dokumentationen for klassen, og se om du kan finde ud hvad denne klasse kan bruges til. Hvis du alligevel ikke kan gennemskue hvad denne klasse kan bruges til, så kan du med fordel læse videre.

Som du måske har læst dig til, så er HashSet klassen en kollektion klasse, akkurat ligesom vores ArrayList var en kollektion. Forskellen er at hvor en ArrayList var ordnet med et strikt indeks, så er HashSet ikke ordnet. Dette betyder at kollektionen ikke bruger et såkaldt indeks, og kollektionen er derfor uordnet. Det gør at elementerne (altså Objekterne) i vores HashSet kollektion, kan forekomme i forskellig rækkefølge/orden, hver eneste gang vi forsøger at gennemsøge vores kollektion. HashSet kollektionen kræver som du måske har set i dokumentationen en generisk type. Da vi ved at en generisk type, kan være en hvilken som helst slags type, kan vi når vi skal bruge denne kollektion bruge typen String, da vi gerne vil have kollektionen til at indeholde en masse 'ord', altså Strings.

Nu ved vi lidt om kollektions klassen HashSet, og vi kan gå videre til den anden klasse, som vi skal kende lidt til, nemlig Scanner klassen.

Mini Opgave - Åben dit Java Bibliotek, og find klassen Scanner. Prøv nu at læse dokumentationen for klassen, og se om du kan finde ud af hvad denne klasse kan bruges til. Hvis du alligevel ikke kan gennemskue hvad denne klasse kan bruges til, så kan du med fordel læse videre.

Som du måske har læst dig til, så er Scanner klassen en klasse, som kan læse/scanne input der er givet fra en bruger. Det er egentlig en meget simpel funktion, nemlig at den læser det input, som den for skudt i hovedet, hvorefter vi så kan bruge det input videre i vores program.

Videre til vores program


Nu da vi ved noget om to særdeles vigtige klasser, for dette system, så kan vi begynde på vores kodning. Vi skal nu have lavet vores klasse InputReader, som sagt tidligere, skal læse vores input fra brugeren.

Opgave - Lav en ny mappe til dit system (kald den f.eks. SupportSystem), og lav så en klasse der hedder InputReader. Giv klassen en konstruktør med en tom krop, og importer herefter vores to klasser, som vi skal benytte, HashSet og Scanner.

Vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Det næste skridt er at vi skal have deklareret et felt, som kan indeholde et objekt af vores Scanner klasse. Feltet skal selvfølgelig blive initialiseret i vores konstruktør, hvor vi laver et nyt objekt af klassen Scanner. Du skal dog i Scanner objektets konstruktør huske at angive en parameter, som skal være værdien System.in, da den skal læse input fra vores kommandoprompt/tekst terminal. Vores kode ser nu ud som følgende.
Fold kodeboks ind/udJava kode 

Herefter kan vi gå igang med den eneste metode, som vi skal have i denne klasse. Metodens formål er at læse input givet af brugeren, for derefter at splitte hvert eneste ord op, og derefter gemme hvert ord i vores kollektions klasse HashSet. Den vil herefter returnere kollektionen af alle de ord brugeren har indtastet i hans/hendes sætning, som vi så kan bruge i vores andre klasser i programmet.

Udfordrings Opgave - Lav denne nye accessor metode, som skal være public. Datatypen skal være HashSet med den generiske type String, da denne kollektion skal kunne indeholde tekststykker, og i dette tilfælde enkelte ord. Kald metoden for getInput, og lad kroppen til denne metode være tom for nu. Vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Nu til metodens indhold. Det første vi skal gøre er at læse/scanne brugerens input, som han/hun har skrevet på linjen i vores kommandoprompt. Hvis du ikke allerede vidste det, kan vi se i under metoderne for klassen Scanner i vores Java Bibliotek, at der er en metode, som hedder nextLine(). Denne metode scanner/læser altså linjen som brugeren har indtastet, og returnerer herefter en String værdi med brugerens input. Resultatet, som denne metode giver os, gemmer vi en en lokal variabel, som har datatypen String. Variablen kunne vi f.eks. kalde inputLine. Vores metode ser nu således ud.
Fold kodeboks ind/udJava kode 

Da brugerens input aldrig er helt til at forudsige, kan der nemt ske fejl. Det kunne være at brugeren i starten eller måske i slutningen kom til at skrive et mellemrum. mellemrum er usynlige karakterer, for det menneskelige øje, men for computeren betyder det en stor del. Det kunne også være at brugeren startede sætningen, eller måske skrev et ord med nogle store bogstaver ind i mellem, her ville vi heller ikke kunne læse ordet korrekt, da computere ikke er så smart indrettede, så de kan ikke skelne imellem store og små bogstaver. Heldigvis er der nogle programmører, som har løst disse problemer for os. Da vores lokale variabel inputLine er af datatypen String, kan vi benytte 2 fremragende metoder fra klassen String, til netop at løse disse to problemstillinger. Den første metode hedder trim(), og fjerner mellemrummet i starten og slutningen af ens String, så vi ikke kommer ud for sådan et problem. Den anden metode hedder toLowerCase(), og laver simpelthen hele vores String om til små bogstaver, så selvom vores bruger skriver store bogstaver i sætningen, vil computeren sagtens kunne læse dette, da alle bogstaverne bliver genereret til små bogstaver.

Mini Opgave - Brug nu dot notation til at kalde henholdsvis trim() metoden og toLowerCase() metoden i din lokale variabel inputLine. Husk at tildele det til den lokale variabel inputLine igen, så vi stadig har alle metoderne i vores lokale variabel (brug en tildelings sæting 'Assignment Statement'). Når opgaven er løst, tjek koden med min nedenunder.
Fold kodeboks ind/udJava kode 

Herefter skal vi 'splitte' hvert ord fra hindanden, så vi for opdelt sætningen til enkelte ord. Måden man kan splitte en sætning ad på, er ved at benytte metoden split(), også fra klassen String. Metoden split() kræver kun en parameter, nemlig en String, som angiver hvornår metoden skal splitte sætningen ad. Metodens parameter kunne f.eks. være " ". Metoden vil nu hver eneste gang den møder 'et mellemrum' i vores sætning lave et split af sætningen, og da vi i normal tekst kun laver et mellemrum mellem hvert ord, vil denne funktion være perfekt.

Udfordrings Opgave - Lav en lokal variabel som kan indholde et fikseret Array med typen String. Kald Array'et for f.eks. wordArray. Denne lokale variabel initialisere du til at indeholde din variabel inputLine, som bruger dot notation til vores split() metode. Husk at parameteren i metoden split(), skal være " ". Når opgaven er fuldført, så tjek din kode med min.
Fold kodeboks ind/udJava kode 

Herefter skal vi lave et nyt objekt af vores HashSet, og lægge det endnu en lokal variabel med datatypen HashSet<String>. Vi skal herefter køre en løkke som automatisk tilføjer hvert enkelt ord til vores HashSet kollektion.

For Each Løkken


Løkken som vi skal bruge til denne opgave hedder en for each løkke, og er så smart indrettet at den hverken behøver en betingelse og et tællerskridt/forøgelse. Løkkens signatur/header ser således ud teoretisk - for (Datatype lokal variabels navn : variabel/felt med vores kollektion) - Den første del er den del, som står før kolon tegnet ( : ), og den del laver en lokal variabel, som kan indeholde objekter af den datatype, som er i vores kollektion. Da vores HashSet kollektion skal kunne indeholde data af typen String, skal denne lokale variabel selvfølgelig også være af typen String. variablens navn er bare et vilkårligt navn, og det kunne i vores tilfælde være navnet word, da vores kollektion skal kunne indeholde ord fra brugerens input, som nu er gemt i vores array wordArray. Delen efter vores kolon, er den del, som skal kunne indeholde vores kollektion, altså hvilken kollektion skal denne løkke lede/undersøge sig igennem. I vores tilfælde skal løkken gennemsøge kollektionen i vores wordArray, da den jo skal finde hvert enkelt ord. vores løkkes signatur ser nu således ud - for (String word : wordArray) - og med menneskelige ord, kunne man sige at for hver (for each) word med typen String, i vores kollektion wordArray, skal den køre løkken. Vores metode ser nu således ud, bemærk at løkkens krop stadig er tom.
Fold kodeboks ind/udJava kode 

Vores løkke skal nu lægge de elementer vi får ud af vores kollektion wordArray ind i vores kollektion, som jeg i mit eksempel har kaldt words, som jo var af typen HashSet. kollektions klassen HashSet har en metode der hedder add(), som lægger et objekt ind i vores HashSet. Objekterne der skulle lægges ind var jo vores word, som jo heldigvis for os er af typen String, da vores HashSet kun kan indeholde objekter af typen String. Så vi bruger dot notation til at kalde metoden add, og giver metoden word som parameter, da vores første del i løkkens signatur var en lokal variabel med navnet word, som er her alle de enkelte ord havner.
Fold kodeboks ind/udJava kode 

Til sidst skal vi bare returnere noget. Husk at vi jo lavede en accessor metode, og accessor metoder returnerer altid noget. Det vi gerne vil returnere med denne metode, var jo vores HashSet kollektion med de enkelte ord fra brugerens input lagt i. Vores HashSet kollektion lå jo i den lokale variabel words, som vi med løkken lige har lagt elementer i. så vores return statement ser således ud - return words; - og vores metode ser nu således ud.
Fold kodeboks ind/udJava kode 

Nu er vores klasse inputReader færdig, og vi kan gå i gang med klassen Responder, som har til formål at returnere et autogenereret svar til brugeren.

Responder klassen


Vi skal nu lave en klasse som skal generere diverse automatiske svar, som brugeren kan få i henhold til hvilket spørgsmål han indtaster som input.
Opgave - Lav nu en ny klasse i vores SupportSystem, som hedder Responder. Giv den en tom konstruktør, og importer disse klasser - HashSet, ArrayList og Random - Din kode skulle nu gerne se således ud.
Fold kodeboks ind/udJava kode 

Faktisk er vores klasse ikke helt klar, da vi skal importere to ting mere til vores klasse.

Iterator og HashMap


De to ting vi skal importere yderligere til vores Responder klasse er Iterator og HashMap.

Mini Opgave - Åben dit Java Bibliotek, og find Iterator. Læs nu dokumentationen for Iterator, og find ud af hvilke metoder den har. Når du har gjort dette, så læs videre.

En iterator kan under en gennemsøgning af en kollektion stoppe op midt i kollektionen og ændre på indholdet. Dette kan også gøres uden en Iterator, men processen med en Iterator er langt bedre og nemmere. Som du måske har lagt mærke til står der ikke class Iterator<E> som overskrift, men derimod Interface Iterator<E>. Jeg vil ikke gå i detaljer med et interface lige nu, men det du skal vide er at dette satdig er en slags klasse, som alle andre, men det er også en speciel klasse. Ellers skal du ikke tænke mere over det, da det i denne sammenhæng ikke betyder så meget lige nu. Vi kan se at en Iterator har tre forskellige metoder. Den første hedder hasNext() og returnerer en boolean værdi (sand eller falsk). Den returnerer sandt, hver eneste gang der er et objekt mere i vores kollektion. Den anden metode hedder next() og er den metode, som henter vores objekt fra kollektionen som vores hasNext() metode lige har sagt var der. Den sidste metode hedder remove(), og er den metode, som kan fjerne et givent objekt fra kollektionen. Med den viden i baghånden, kan vi gå videre til vores HashMap klasse.

En HashMap er en anden slags kollektions klasse, ligesom ArrayList og HashSet. Nu kan du jo tænke at hvorfor skal vi kende endnu en kollektions klasse, når vi allerede kender disse 2, som fungerer helt aldeles udmærket?

Mini Opgave - Åben dit Java Bibliotek, og find klassen HashMap. Læs nu dokumentationen for denne klasse, og gennemgå nogle af metoderne i denne klasse. Kan du finde ud af hvilke metoder, som man skal bruge til at lægge ting ind i kollektionen, og hvilken man skal bruge for at hente ting fra kollektionen. Når du har læst dokumentationen, så gå videre og jeg kan prøve at forklare dig hvad et HashMap egentlig gør.

Et HashMap er en speciel kollektion, som akkurat ligesom et HashSet ikke har et indeks til sine objekter. Objekterne gemmes altså i en ikke ordnet kollektion, men det er ikke engang det bedste ved et HashMap. Det bedste ved et HashMap er at hvor man kun kunne gemme et objekt i hvert rum/indeks i en ArrayList eller et HashSet, kan vi i et HashMap gemme to objekter i samme rum. Den bedste måde at sammenligne et HashMap med virkeligheden på, er ved at tænke på en telefonbog. I en telefonbog, står der en masse telefonnumre, og til hvert telefonnummer er knyttet et specifikt navn, på det enkelte telefonnummer. Vi kan så slå op i telefonbogen og finde et specifikt navn, for derefter at få fat i telefonnummeret. Et HashMap fungerer på akkurat samme måde. Et HashMap skal nemlig bruge to generiske typer, hvor dan første type er en key, og den næste er en value. Vores key i telefonbog eksemplet er det navn vi leder efter i telefonbogen. Det navn, har så en specifik value, som er telefonnummeret. Vi kan så bruge metoderne put() til at lægge indhold ind i vores key og value rum. Metoden til at hente en value hedder så get(), og parameteren i metoden er den specifikke key som er angivet. Det betyder så også at vores key i et HashMap aldrig må være ens, da den jo så ikke ved hvilken value den skal hente.

Tilbage til koden


Nu har vi fået noget mere vigtig information, som vi skal bruge i vores Responder klasse. Lad os først importere vores Iterator og HashMap til klassen. Herefter skal vi deklarere tre felter i klassen, hvor den første skal kunne indeholde en ArrayList, som har den generiske type String. Det andet felt skal kunne indeholde data af typen HashMap, som har de to generiske typer String som key og String som value. Det tredje felt skal kunne indeholde data af typen Random. Vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Mini Opgave - Initialiser nu vores nye felter med objekter af den type data som de kan indeholde. Initialiser dem som altid i vores konstruktør. Når opgaven er udført, så tjek din kode med min.

Fold kodeboks ind/udJava kode 

Nu skal vi have lavet nogle metoder i vores Responder klasse. De metoder vi skal bruge er nogle metoder, som fylder vores ArrayList og HashMap med nogle autogenerede svar. Vi skal have en metode, som udsender et vilkårligt svar hvis ikke nøgle af de nøgleord, som vi laver om lidt findes. Til sidst skal vi lave en metode, som returnerer det autogenerede svar, som vi vil give til brugeren.

Lad os begynde på de to første og letteste metoder. Nemlig de metoder, som skal udfylde vores ArrayList og HashMap med objekter, i dette tilfælde objekter af typen String.

Udfordrings Opgave - Lav en mutator metode, som er private, der hedder fillDefaultResponses(). Metoden skal lægge String objekter ind i vores ArrayList kaldet defaultResponses. Tænk over nogle 'standard' svar, som passer til alle typer af spørgsmål, og som ikke rigtig siger noget - et eksempel kunne være Det lyder underligt, kan du beskrive problemet yderligere?. Når du har lavet denne metode, så sammenlign din kode med min.

Fold kodeboks ind/udJava kode 

Nu har vi udfyldt vores ArrayList med nogle defaultResponses så at sige, altså nogle svar, som skal bruges når vi ikke kan finde et nøgleord fra vores HashMap, som skal laves nu.

Udfordrings Opgave - Lav nu en ny mutator metode, som er private, og hedder fillResponseMap(). Metoden skal lægge keys og values ind i vores HashMap, som er gemt i feltet responseMap. Brug metoden put() fra HashMap klassen til at lægge et key og en value ind i vores HashMap. Vores key i dette tilfælde er vores nøgleord vi skal lede efter i brugerens input. Det kunne være nøgleord som f.eks. langsom, bug, installation og crash. Vores value skal så være en passende response til vores nøgleord. Når du har løst opgaven, så sammenlign den med min.

Fold kodeboks ind/udJava kode 

Nu har vi udfyldt de svar, som skal gives hvis vi møder et af vores nøgleord i brugerens input. Nu skal vi så lave en lille metode, som udskriver et vilkårligt svar fra vores ArrayList.

Udfordrings Opgave - Lav en accessor metode, som er private og hedder getDefaultResponse(). Return typen til denne metode skal være String. Lav nu en lokal variabel med datatypen int, og initialiser den med din randomGenerator til at genere et tal imellem 0 og størrelsen på vores ArrayList (brug metoden nextInt() fra Random klassen, og brug så ArrayList'ens metode size() som parameter til denne metode). Vores statement til den lokale variabel skal så se således ud - int index = randomGenerator.nextInt(defaultResponses.size()); - og returner så det objekt med det vilkårligt generede indeks i vores ArrayList, med metoden get(). Vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Nu skal vi til den sidste og mest betydningsfulde metode i denne klasse. Det er også den metode, som er mest vanskelig at lave, men vi skal nok komme igennem det.

Udfordrings Opgave - Lav en ny accessor metode, som er public. Kald metoden for generateResponses() og dens return type skal være String. Metoden skal bruge en parameter, nemlig parameteren - HashSet<String> words - Som var vores HashSet vi lavede i InputReader klassen. Skriv ikke noget i metodens krop endnu, og vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Vi skal nu i vores metode have tilført en Iterator til vores kollektion. Iteratoren gør det nemmere for os at få adgang til hvert enkelt objekt i vores kollektion, for derefter at kunne bruge objektet inden vi gennemsøger videre i kollektionen. Vores []HashSet klasse har en metode, som hedder iterator. Metoden henter en Iterator til denne kollektion, og vi kan herefter gemme det i en lokal variabel med datatypen Iterator<String>. Vores metode ser nu således ud.
Fold kodeboks ind/udJava kode 

Når vi har valgt at bruge en Iterator med denne kollektion, så kan vi herefter bruge Iterator's metoder. Vi skal jo gennemsøge kollektionen for nøgleord som er gemt i vores HashMap. Til dette formål kan vi benytte en while løkke. Vi behøver ikke at initialisere en lokal variabel til denne løkke, da løkken skal køre indtil vores boolean værdi returnerer falskt. I vores Iterator, var der en metode som hed hasNext(). Denne metode returnerede sandt så længe der var flere objekter i vores kollektion. Så snart den var nået igennem alle objekterne ville den returnere falskt, og derfor afslutter løkken sig selv. Så vi bruger denne metode som løkkens betingelse, og behøver derfor heller ikke noget tællerskridt.

Mini Opgave - Lav en while løkke, som bruger vores Iterator metode, hasNext() som betingelse. lad løkkens krop være tom for nu.

Fold kodeboks ind/udJava kode 

Løkkens mangler nu noget kode i sin krop. Det som vi gerne vil have løkken til er at tage objektet ud af kollektionen for en stund og gemme det i en lokal variabel. Herefter skal vi tjekke om ordet i vores kollektion matcher en af vores keys i vores HashMap. Herefter gemmer vi det resultat i en anden lokal variabel. Nu tænker du måske, hvad skal vi dog gemme hvis ikke ordene matcher en af vores keys. Til dette kan jeg svare at Java automatisk gemmer værdien null, da et HashMap også kan returnere null værdier, hvis ikke der bliver fundet den rigtige key. Ordet null betyder simpelthen bare intet objekt/ingenting. Så hvis ordet null forekommer, så er der altså ikke noget objekt i vores resultat. Dette er smart, da vi så nemt kan tjekke om den fandt noget eller ej.

Opgave I løkkens krop lav en lokal variabel med datatypen String, og benyt så Iterator'ens metode next() til at hente det næste objekt i kollektionen. Herefter laver du endnu en lokal varaibel, også med datatypen String, hvor du bruger metoden get() fra HashMap klassen. I metoden get()'s parameter, skal du skrive navnet på den første lokale variabel du lavede i løkken. Din kode skulle nu gerne se således ud.
Fold kodeboks ind/udJava kode 

Nu skal vi så tjekke om resultatet fra vores HashMap var null eller ej. Hvis resultatet ikke var null, så betød det at der var et match, altså at et af ordene matchede vores key. Til at lave dette tjek med skal vi benytte et if statement.

Opgave - I din løkke lav et if statement, som tjekker om resultatet i din lokale variabel (i mit eksempel variablen response), ikke indeholder værdien null. Måden du tjekker om noget ikke er lig med noget andet, er ved at bruge operatoren ! (udråbstegn). Udråbstegnet betyder not, så i if statementets betingelse, kan du skrive - response != null - som betyder at den skal køre statementets indhold hvis indholdet i response ikke er lig med (not equal too) null. Inde i if statementets krop skal du så lave en return statement, som returnerer indholdet af response. Vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Nu er vores løkke færdig men vi er ikke helt færdige med metoden, fordi hvad nu hvis metoden hele tiden returnerede værdien null, så ville den jo aldrig køre if statementet. Det er det vi skal rode bod på nu. lav nu uden for din løkke, altså efter løkken en return statement, som returnerer indholdet fra metoden getDefaultResponse(), som vi lavede tidligere. Vores metode ser nu således ud.
Fold kodeboks ind/udJava kode 

hele klassen Responder ser nu således ud.
Fold kodeboks ind/udJava kode 


TechSupportSystem


Nu skal vi til vores sidste klasse, nemlig TechSupportSystem. Så lav en klasse med dette navn, og gem den sammen med dine andre filer. husk at lave en konstruktør klar, så vi kan bruge den til at initialisere felter med.

Formålet med denne metode er at kontrollere de to klasser vi lige har lavet, og bruge dem sammen. Vi skal derfor deklarere to felter, som kan indeholde henholdsvis et objekt af typen InputReader og Responder. husk at initialisere dem med et objekt i konstruktøren, vores klasse ser nu således ud.
Fold kodeboks ind/udJava kode 

Lad os nu gøre de metoder vi skal lave klar. Det vil sige at vi skriver metodernes signatur i klassen, uden at skrive noget i kroppen. Vi skal bruge tre metoder. Den første skal hedder start(), og den skal være en mutator metode, som har en access modifier der er public. Herefter skal vi have to metoder, som hedder henholdsvis printWelcome() og printGoodbye(). De skal også være mutator metoder, men have en access modifier som er private. Lige som den sidste ting inden vi kigger på vores kode igen, skal du importere klassen HashSet i starten. vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Lad os starte med at lave de to nederste metoder, da de er ret så simple. Metoden printWelcome(), skal bare udskrive en velkomst besked som køres hver gang programmet startes. Find selv på en Sjov besked. Den anden metode printGoodbye(), skal bare printe en afslutnings besked, som køres når programmet lukkes. Find også her selv på en sjov og passende besked. Programmet ser nu således ud.
Fold kodeboks ind/udJava kode 

Nu skal vi så i gang med metoden start(). Metoden skal køre en løkke, der køre så længe programmet er aktivt (indtil vi har skrevet en afslutningskommando). Derfor skal vi deklarere en lokal variabel, som har datatypen boolean. Så vi skal altså gøre.

Udfordrings Opgave - I starten af metoden lav en lokal variabel med datatypen boolean og kald variablen for finished. initialiser variablen med værdien false. Lav så et internt metode kald til metoden printWelcome(). Herefter laver du en while løkke, som har betingelsen !finished (not finished), så løkken køre indtil værdien i finished ændres til true. lad løkkens krop være tom. Efter løkken laver du så et internt metode kald til metoden printGoodbye(). Din kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Vi skal nu lave lidt kode i løkken. Koden i løkken, er noget, som køres hele tiden, indtil vi for vores afslutningskommando. Det er derfor her vi skal lave tjekket for om vores afslutningskommando har været der. Hvis du har læst min printWelcome() besked, vil du se at vores afslutningskommando er afslut. Det vil sige at vi skal bruge en if statement i vores løkke til at tjekke om brugerens input indeholdt ordet afslut. For at tjekke om brugerens input indeholder et bestemt ord, findes en speciel metode i String klassen, som hedder contains(). Metoden returnerer sandt eller falskt hvis ordet er der eller ej. Men for at finde order, skal vi lige have fat i vores input fra brugere, så vi laver en lokal variabel, der henter metoden getInput fra klassen InputReader. Hvis vi husker tilbage, kan vi huske at denne metode havde en return type som var HashSet<String>, hvilket betyder at datatypen for vores lokale variabel, skal være en HashSet<String>. Men nu tilbage til vores if statement. Vi bruger altså metoden contains() til vores lokale variabel, som indeholder objekter af String's, og tjekker med contains() metodens parameter om et af ordene fra vores HashSet kollektion er ordet afslut. Vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Nu skal vi bare udfylde vores krop i if statementet. Formålet med if statementet var jo at tjekke om inputtet indeholdt ordet afslut, og hvis den gjorde dette, skal den køre koden i statementet. Kommandoen afslut skulle jo afslutte programmet, og herved vores løkke. så i if statementets krop initialisere vi bare vores finished variabel til true. Men lige sker der kun noget i løkken hvis if statementet er sandt, så vi skal have lavet en else part til if statementet, som kører hver eneste gang løkken er falsk, altså hver eneste finished ikke er true, og hver eneste gang der ikke er et ord med kommandoen afslut. så du skriver efter if statementets krop else, og laver en ny krop. Den vil nu køre else parten, hver eneste gang if statementet ikke køres. Vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

I vores else part skal vi generere et response ud fra brugerens input, som vi allerede har gemt i et HashSet. Så vi laver i else delen en lokal variabel med datatypen String, og kalder den f.eks. response. Herefter initialisere du variablen til at køre metoden fra Responder klassen, som hed generateRespond(). Hvis du husker tilbage, skulle denne metode bruge en parameter, nemlig en kollektion af String's i et HashSet. Du vi allerede har en HashSet kollektion med navnet input i vores metode, kan vi bare bruge dette som parameter. Herefter skal du udskrive variablen reponse's indhold. Vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Nu er vores system færdigt, og vi kan udarbejde en main klasse, med en main metode, som laver et objekt af TechSupportSystem klassen, og kalder metoden start() via dot notation. Vores Main klasse ser sådan her ud.
Fold kodeboks ind/udJava kode 

Vi ar midt i al vores kodning glemt noget, men det kan vi hurtigt rette. Vi skal i vores Responder klasse lave to kald til dens interne metoder i konstruktøren. Metoderne vi skal kalde er - fillDefaultResponses() og fillResponseMap - Grunden til dette er at vi jo skal have udfyldt vores kollektionerne med de auto genererede svar, ellers kan vi jo ikke få noget svar ud af dem. Vores Responder ser nu således ud.
Fold kodeboks ind/udJava kode 


Færdig


Nu er vores Tech Support System færdigt, og du kan nu kompilerer dine Java filer, og herefter køre Main klassen. Dit output kunne nu se således ud, men det er ikke helt sikkert, da det også afhænger af brugerens input. prøv engang at skrive noget input, og brug gerne nogle af de ord som vi lavede i vores HashMap's key - langsom, bug, installation og crash - men prøv også sætninger uden disse ord for at få et vilkårligt genereret defaultResponse. Prøv dig frem, og skriv så afslut, for at afslutte programmet.



Nu blev programmeringen en tant mere interessant, da vi kan bruge programmet, med nogle input fra en bruger, uden at vi kender indholdet. Vi kunne simpelthen læse/scanne indholdet ved hjælp af vores Scanner klasse, og gemme indholdet i en HashSet kollektion. Vi har også lært om Hvad fordelene ved et HashMap var, nemlig at man kunne gemme 2 objekter i stedet for 1, også bruge det ene objekt som en key, til at få adgang til det andet objekt. Vi har set på hvordan man kan bruge en Iterator til at gennemgå objekterne i en kollektion en for en, meget nemmere. Alt i alt, har vi lært en hel masse, faktisk forholdsvis sværere teori end man lige skulle tro, og jeg håber at du vil følge med i den 6. del af denne Java artikel kavalkade.

Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (7)

User
Bruger #16945 @ 04.02.12 17:11
Hej! Forstår ikke den del med for'each-løkken. Hvordan ender elementerne i wordArray i HashSet-kollektionen words? words er jo tom fra starten af. " words.add(word); " tilføjer den ikke bare elementer fra wordArray TIL word? Kan jeg få det forklaret på en lidt mere idiotvenlig måde? :)

PS. Er endnu ikke begyndt med klassen "Responder", men tænkte at jeg først lige ville være sikker på "inputReader" klassen, før jeg begyndte på den næste klasse.
User
Bruger #4487 @ 05.02.12 12:30
Vi har et almindeligt String Array med navnet wordArray
Fold kodeboks ind/udJava kode 

Her tager vi så linjen skrevet af brugeren, og splitter denne hver eneste gang der er et mellemrum. Vi har nu fyldt vores array op med ord (words). Det næste vi gør er at deklarere og initalisere (oprette) et objekt af klassen HashSet, som vi ligger ind i en lokal variabel kaldet words.
Fold kodeboks ind/udJava kode 

Nu har vi to forskellige kollektioner, og vi kan nu benytte en løkke, til at tage ordene fra den ene kollektion/array (wordArray), og lægge disse ind i vores anden kollektion (words (vores HashSet)). Jeg har i eksemplet valgt at bruge en for each løkke, da vi skulle se hvordan sådan en virkede.

Måden den virker på er at vi har en lokal variabel i løkkens hoved, samt den kollektion, som den skal køre igennem. F.eks. kunne den se således ud - for (String element : kollektion) { } - Her har vi i løkkens hoved datatypen String samt ordet element. Ordet element er bare et valgfrit navn, da String element er en deklaration af en lokal variabel. Formålet med denne lokale variabel er at vi har et sted hvor hvert element bliver gemt fra vores kollektion. En for each løkke kører nemlig så længe at der er elementer tilbage i vores kollektion/array, og hver eneste gang den møder et nyt element, lægger den dette ind i vores lokale variabel element, som vi deklarerede i løkkens hoved. Efter kolonnet ( : ), har vi ordet kollektion. Dette er her du skal indsætte navnet på den kollektion, som vi skal gå igennem. Lad os se det eksempel der var i artiklen.
Fold kodeboks ind/udJava kode 

Som du kan se i vores eksempel, så har vi en lokal variabel med navnet word. Vi ønsker at kører igennem vores kollektion med navnet wordArray, hvilket betyder at så længe der er elementer tilbage i dette array, så vil løkken køre. Hvis wordArray nu indeholdt 10 ord, vil løkken altså køre ti gange. Det betyder at vores variabel word vil blive fyldt med et nyt element (ord) 10 gange. Inde i løkkens kode, kalder vi en metode, med navnet add(). Denne metode er at finde i HashSet klassen, og parameteren den kræver er den værdi, som den skal lægge ind i vores HashSet kollektion. linjen - words.add( word ); - Tager altså værdien i vores lokale variabel word, og lægger denne ind i vores HashSet kollektion.

Hvis vi skulle lave det samme med en anden løkke, f.eks. en while løkke, så ville eksemplet se således ud
Fold kodeboks ind/udJava kode 

While løkken her laver også en lokal variabel, med navnet word, men denne variabel er bare deklareret i løkkens krop, og ikke i dens hoved. Håber at det hjalp lidt mere til forståelsen for hvordan for each løkken fungere, og hvordan vi får elementer fra wordArray over i vores HashSet kollektion 'words'.
User
Bruger #16945 @ 05.02.12 12:42
Mange tak! Håber du en eller anden dag bliver Java'lærer på et universitet, for du er meget god til at forklare hvordan Java fungerer!

Så det der sker i for each løkken er:

Fold kodeboks ind/udKode 


Og add() metoden fungere således:
Fold kodeboks ind/udKode 


Har jeg forstået det korrekt?

User
Bruger #4487 @ 05.02.12 14:21
Ja næsten.. Den putter ikke alle elementerne ind i den loakel variabel på¨en gang, men gør det hver gang at løkken kører, altså 10 gange hvis ens kollektion indeholder 10 elementer.
User
Bruger #4487 @ 05.02.12 14:22
add() metoden tilføjer bare et nyt element til vores HashSet kollektion.
User
Bruger #16945 @ 06.02.12 20:48
Men den add'ere jo word IND i Words 10 gange, fordi løkken bliver løbet igennem 10 gange, vil det ikke betyde at der kommer 65 elementer ind i words? For, for hver gang løkken bliver løbet igennem, kommer der et element mere ind i word, som så bagefter på ny, bliver tilføjet til words?
User
Bruger #4487 @ 06.02.12 21:51
Nej, Variablen word for et nyt element hver gang løkken kører.

Første gang løkken kører lægges det første element fra wordArray ind variablen word. Vi benytter nu metoden add(), til at tilføje værdien i variablen word til vores words kollektion (HashSet).

Næste gang løkken kører lægges det næste element ind i variablen word (den overskriver altså det gamle element). Metoden add() tilføjer nu elementet til vores words kollektion, så dan nu kommer til at indeholde to elementer. Sådan gør den indtil at wordArray er tom for elementer.

Hvis wordArray indeholder 10 elementer, f.eks. {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}, så vil vores løkke køre 10 gange (fordi wordArray indeholder 10 elementer), og vi tager nu hvert element og lægger ind i vores HashSet ved hjælp af metoden add().
Du skal være logget ind for at skrive en kommentar.
t