if
-setninger
og if-else
-setningerDersom ikke annet er bestemt, vil instruksjonene i et program bli utført
i den rekkefølge de står, altså sekvensielt. For et applikasjonsprogram
begynner utførelsen med første instruksjon i main
-metoden.
I praksis vil det imidlertid være kun for de aller enkleste programmene
at instruksjonene alltid skal utføres i en bestemt rekkefølge når programmet
blir kjørt, en rekkefølge som programmereren kjenner til når programmet blir
skrevet. Svært ofte vil det være ønskelig å kunne ha alternative rekkefølger
for instruksjonene, avhengig av hva som skjer når programmet blir kjørt.
I dette kapitlet og det neste skal vi se nærmere på hvilke muligheter vi har for
å få til dette.
Ønskelige endringer for rekkefølgen for utførelsen av instruksjonene kan være av to hovedtyper:
Vi skal ta for oss språkkonstruksjoner som du kan bruke for å oppnå disse ønskene.
if
-setninger og
if-else
-setningerVi har allerede (se kapittel 2) tatt for oss den enkle if-setningen som har formen
if ( betingelse ) instruksjon;
Vi kan si at her oppnår vi valget mellom alternativet at noe utføres og
at det ikke utføres. I mange situasjoner er det imidlertid slik at dersom
ett alternativ ikke skal utføres, så er det et annet som skal utføres isteden.
Det får vi til ved å utvide if
-setningen med
en else
-grein. En slik konstruksjon har
denne formen:
if ( betingelse ) instruksjon1; else instruksjon2;
Merk at det også her, som alltid ellers, er slik at hver instruksjon skal
avsluttes med semikolon. En slik
if-else
-setning
har følgende virkning: Dersom betingelse
har verdi true
, vil
instruksjon1 bli utført, men ikke
instruksjon2. Dersom
betingelse har verdi
false
, vil ikke
instruksjon1 bli utført, men derimot
instruksjon2.
Vi antar at int
-variablene
a, b
og max
er
blitt deklarert, samt at a
og
b
er blitt tilordnet verdi. Vi ønsker at
variabelen max
skal få samme verdi som den
største av a
og
b
. Da kan vi skrive følgende kode:
if ( a <= b ) max = b; else max = a;
Merk deg at vi kunne oppnådd samme resultat ved å skrive slik:
if ( a <= b ) max = b; if ( a > b ) max = a;
Men dersom vi hadde skrevet slik, ville begge
sammenlikningsoperasjonene
a <= b
og
a > b
bli utført, noe som er unødvendig.
For dersom den første ikke er oppfylt, så må nødvendigvis den andre
være oppfylt!
if-else
-alternativet er derfor
mer effektivt (siden vi sparer oss for en sammenlikningsoperasjon), og bør
på grunn av dette foretrekkes. Dessuten har det en klarere logisk struktur.
Da du skrev program for oppgave 14 i kapittel 2,
brukte du trolig to if
-setninger for å få riktig utskrift fra
programmet. Gjør om programmet ditt slik at du isteden bruker en
if-else
-setning.
***
Det er tillatt å utvide
if-else
-strukturen
med flere greiner, slik det er vist i neste eksempel.
For porto på innenlandske brev (A-post) gjelder (2014) følgende takster:
Vekt i g til og med | 20 | 50 | 100 | 350 | 1000 | 2000 |
---|---|---|---|---|---|---|
Porto | 10.00 | 15.00 | 19.00 | 30.00 | 60.00 | 95.00 |
Største tillatte vekt er altså 2000 gram.
Vi tenker oss at int
-variabelen
vekt
inneholder vekten til et slikt brev
(i antall hele gram).
Vi skal skrive kode som tilordner variabelen
porto
riktig portoverdi. Dersom brevet er for
tungt, skal porto
tilordnes verdien 0.0 som
indikasjon på dette. Følgende java-kode kan da brukes:
double porto = 0.0; if ( vekt <= 20 ) porto = 10.00; else if ( vekt <= 50 ) porto = 15.00; else if ( vekt <= 100 ) porto = 19.00; else if ( vekt <= 350 ) porto = 30.00; else if ( vekt <= 1000 ) porto = 60.00; else if ( vekt <= 2000 ) porto = 95.00;
Variabelen
porto
vil bli tilordnet verdi så snart
programutførelsen kommer til en if
-test som
resulterer i true
. Eventuelle gjenstående
if
-tester vil da bli hoppet over, siden det
står else
foran alle disse. Dersom variabelen
vekt
har en verdi større enn 2000, vil ingen
av if
-testene resultere i
true
. Variabelen
porto
vil i så fall beholde sin startverdi 0.0.
Legg ellers merke til at dersom vi ikke hadde skrevet
else
foran alle
if
-tester (unntatt den første), ville
programkoden ikke virket riktig. Dersom da for eksempel
vekt
hadde hatt verdien 18, ville
porto
fått verdien 145.00, mens riktig verdi
(som den vil få slik det står ovenfor), ville være 9.00.
Lag et applikasjonsprogram som leser inn vekten til et brev i antall hele gram og
som skriver ut riktig porto (på grunnlag av portotabellen ovenfor).
Dersom brevet er for tungt, skal melding om dette
skrives ut istedenfor portoen.
(Gjør bruk av if
- og/eller
if
-else
-setninger.)
Operatoren som består av de to symbolene ? og : kan brukes som et alternativ
til en if-else
-instruksjon
(som har bare én else
-grein.)
Istedenfor if-else
-instruksjonen
i eksempel 1 ovenfor kunne
vi skrevet
max = ( a <= b ) ? b : a;
Det at ?: er en operator, betyr at den returnerer en verdi. Verdien blir
i dette tilfelle tilordnet variabelen max
. Hvilken verdi som blir
returnert er bestemt av det logiske uttrykket foran ?. Dersom dette uttrykket
har verdi true
, er det verdien bak ? som blir returnert, i vårt
eksempel b
. I motsatt tilfelle er det verdien bak : som blir
returnert, i vårt eksempel a
.
En blokk i et java-program er en programbit som er avgrenset av
krøllparenteser { og }. En blokk kan inneholde ingen, én, eller
flere instruksjoner. Vanligvis inneholder den flere instruksjoner. Vi kan bruke
en blokk alle steder der vi ellers kan bruke én instruksjon. Dersom
det for eksempel er mer enn én instruksjon som skal utføres i tilfelle en
if
-betingelse er oppfylt, putter vi
instruksjonene inn i en blokk.
Anta at vi i eksempel 1 ovenfor, i tillegg til det som er gjort med å
gi variabelen max
den største av verdiene
a
og b
, også
ville registrere i en tekst hvilken det var av
a
eller b
som
hadde størst verdi. Da kunne vi endre koden til det følgende:
String størst = ""; if ( a <= b ) { max = b; størst = "b har størst verdi"; } else { max = a; størst = "a har størst verdi"; }
Programmeringsfeil kan vi dele inn i to hovedtyper: Syntaksfeil og logiske feil.
Syntaksfeil er brudd på programmeringsspråkets regler, dets syntaks. De svarer til grammatiske feil i vanlig språk. Feilene fører til at vi ikke får kompilert programmet. Kompilatoren skriver ut feilmeldinger når vi prøver å kompilere det. Feilene blir derfor også kalt kompileringsfeil. Feilmeldingene inneholder opplysninger som gir oss god hjelp til å finne feilene og rette dem opp.
Logiske feil er feil som gjør at programmet ikke virker slik vi har til
hensikt at det skal gjøre. Det virker kanskje riktig for det meste av det det skal utføre,
men ikke for alt. Slike feil kan være ganske vanskelige å finne. Vi skal i denne omgang
ta for oss noen typiske feil som det er vanlig å gjøre i forbindelse med
if
-setninger og
if-else
-setninger.
Dersom det til en betingelse bare hører til én enkelt instruksjon, er det ikke nødvendig å ramme inn instruksjonen med krøllparenteser { og } slik at vi får opprettet en blokk. Dette er for eksempel tilfelle med instruksjonen
if (antall > 0)
snitt = sum / antall;
der vi tenker oss at vi skal regne ut et snitt etter å ha fått summert opp et antall verdier. Hensikten med betingelsen er å unngå divisjon med null. Vi hadde fått nøyaktig samme virkning om vi isteden hadde skrevet instruksjonen på denne måten:
if (antall > 0)
{
snitt = sum / antall;
}
der det er satt inn blokkparenteser. Dersom det er mer enn én
instruksjon som hører til
if
-betingelsen, er vi nødt
til å ramme inn instruksjonene med krøllparenteser for at programmet skal virke
riktig. Som et eksempel på dette går vi tilbake til
kapittel 2, oppgave 5. Oppgaven går ut på å lage
et program som leser inn radien til en sirkel og skrive ut sirkelens areal.
Som radius er det mulig å skrive inn et hvilket som helst desimaltall, også negative
tall. Vi vet at ingen sirkel har negativ radius og at det derfor også er meningsløst
å snakke om arealet til en slik sirkel. Nå som vi har lært om
if
-setninger, tenker vi oss at
vi skal legge inn en test på radien før vi beregner og skriver ut arealet.
Glemmer vi krøllparenteser, kan koden for dette komme til å se ut slik:
if (radius >= 0) areal = pi * radius * radius; JOptionPane.showMessageDialog(null, "Areal: " + areal);
Men dette vil virke feil i tilfelle radien er negativ! Utskriftsinstruksjonen
vil nemlig bli utført også for negativ verdi av radius
, for det er
bare instruksjonen for beregning av areal som er knyttet til
if
-setningen. For å få korrekt
program også for negative radier, må vi skrive slik:
if (radius >= 0) { areal = pi * radius * radius; JOptionPane.showMessageDialog(null, "Areal: " + areal); }
if
-betingelseEn vanlig feil, særlig for nybegynnere, er å plassere et semikolon ; på slutten
av if
-linja, slik som i følgende
eksempel:
if (radius > 0); { areal = pi * radius * radius; JOptionPane.showMessageDialog(null, "Areal: " + areal); }
Dette gir ingen kompileringsfeil, men er likeverdig med følgende kode:
if (radius > 0) {//Tom blokk!}; { areal = pi * radius * radius; JOptionPane.showMessageDialog(null, "Areal: " + areal); }
Feilen kan være svært vanskelig å oppdage. Som du ser, vil det i virkeligheten
være en tom blokk, det vil si ingen instruksjon, som er knyttet til
if
-betingelsen, mens den
blokka som du hadde tenkt skulle høre til betingelsen ikke vil være knyttet til
noen betingelse i det hele tatt og derfor vil bli utført uansett.
else
-setning knyttet
til gal if
-betingelseVi tenker oss at det fra brukeren skal leses inn et månedsnummer, det vil si en verdi fra 1 til 12. Brukeren skal få melding tilbake om innlest verdi kunne godtas eller ikke. Som utgangspunkt tar vi for oss følgende kodebit for dette:
String måned = JOptionPane.showInputDialog("Skriv månedsnummer:"); int mnd = Integer.parseInt(måned); if (mnd >= 0) if (mnd <= 12) JOptionPane.showMessageDialog(null, "Månedsnummer OK"); else JOptionPane.showMessageDialog(null, "Gal verdi. Månedsnummer må være fra 1 til 12");
Det vi kan lure på her, er hvilken av
if
-setningene
else
-setningen hører til.
Slik innrykkene er plassert, ser det ut til at den hører til den første
if
-setningen. Regelen for dette
er imidlertid slik: En else
-setning
hører alltid til den nærmest foregående
if
-setning som ikke allerede
er matchet med en else
-setning.
I dette tilfelle er det faktisk den siste av
if
-setningene. Koden ovenfor
er nemlig likeverdig med følgende, der det også er korrekt bruk av innrykk (indentering):
String måned = JOptionPane.showInputDialog("Skriv månedsnummer:"); int mnd = Integer.parseInt(måned); if (mnd >= 0) if (mnd <= 12) JOptionPane.showMessageDialog(null, "Månedsnummer OK"); else JOptionPane.showMessageDialog(null, "Gal verdi. Månedsnummer må være fra 1 til 12");
Ser vi litt nøyere på denne koden, vil vi se at det ikke vil bli skrevet ut noe som helst
dersom innlest månedsnummer er 0 eller negativt. For verdier fra 1 til 12 vil korrekt
tilbakemelding bli skrevet ut, mens det bare er for verdier større enn 12 at meldingen i
else
-delen vil bli skrevet ut.
For styre hvilken if
-setning en bestemt
else
-setning skal tilhøre,
kan vi legge inn parenteser, slik som i følgende kode:
String måned = JOptionPane.showInputDialog("Skriv månedsnummer:"); int mnd = Integer.parseInt(måned); if (mnd >= 0) { if (mnd <= 12) JOptionPane.showMessageDialog(null, "Månedsnummer OK"); } else JOptionPane.showMessageDialog(null, "Gal verdi. Månedsnummer må være fra 1 til 12");
Slik det nå står, vil else
-setningen vår
høre til den første if
-setningen.
Men vil koden nå virke riktig? La oss sjekke i hodet: For verdier mindre enn eller lik null
vil feilmeldingen bli skrevet ut. For verdier fra 1 til 12 vil vi også få riktig utskrift
om at verdien er OK. Men hva med verdier større enn 12? Da vil vi faktisk ikke få skrevet ut
noe som helst! En mulig måte å fikse dette på, kan være følgende:
String måned = JOptionPane.showInputDialog("Skriv månedsnummer:"); int mnd = Integer.parseInt(måned); if (mnd >= 0) { if (mnd <= 12) JOptionPane.showMessageDialog(null, "Månedsnummer OK"); else JOptionPane.showMessageDialog(null, "Innlest verdi er større enn 12!"); } else JOptionPane.showMessageDialog(null, "Innlest verdi er mindre enn 1!");
Merk deg for øvrig at vi aldri kan ha en løsrevet
else
-setning. Den må være
knyttet til en foregående if
.
Hadde vi derfor i koden ovenfor droppet krøllparentesene, ville vi fått kompileringsfeil.
Merknad Problemet ovenfor, der innlest verdi skal være mellom to grenser, kan vi løse på en annen måte når vi har lært om logiske operatorer, det kommer seinere.
Under Vanlig feil 1 ovenfor ble det som eksempel brukt beregning av snitt for et antall verdier som er telt opp og summert. Anta nå at vi ønsker å informere brukeren om det opptelte antallet er et partall eller ikke. En mulig "rett fram"-kodebit for dette kan være følgende:
boolean partall; if ( (antall % 2) == 0 ) //beregner rest ved divisjon med 2 partall = true; else partall = false; if (partall == true) JOptionPane.showMessageDialog(null, "Antallet er et partall."); else JOptionPane.showMessageDialog(null, "Antallet er et oddetall.");
Det er ikke noe feil i denne koden, men det er en del unødvendig testing. Merk deg for det første at uttrykket
(antall % 2) == 0
har verdi true
eller
false
.
Istedenfor den første if
-else
kunne vi derfor kort og godt skrevet
boolean partall = (antall % 2) == 0;
Det er for øvrig også tillatt å droppe parentesene som er brukt, men de bidrar til å klargjøre strukturen i instruksjonen.
I den andre if
-testen har
variabelen partall
allerede fått riktig
verdi true
eller
false
.
Det er ikke nødvendig å teste på den. Derfor kunne vi kort
og godt skrevet
if (partall) JOptionPane.showMessageDialog(null, "Antallet er et partall."); else JOptionPane.showMessageDialog(null, "Antallet er et oddetall.");
En løkke består av én eller flere instruksjoner som skal utføres gjentatte ganger inntil en eller annen betingelse ikke lenger er oppfylt.
I java finnes det flere typer av slike løkker. Den mest generelle av dem
er while
-løkka. Den har følgende form:
while ( betingelse ) instruksjon;
Tilsvarende som betingelsen i en if
-setning
må også betingelsen i en while
-løkke være et
logisk uttrykk, altså et uttrykk som har verdi true
eller false
. Det som ovenfor er kalt
instruksjon kan selvsagt være en blokk
bestående av flere instruksjoner. For øvrig er det slik både her og ellers,
at selv om det står bare én instruksjon, er det tillatt å plassere denne
inni en blokk, slik at vi isteden kunne skrive
while ( betingelse ) { instruksjon; }
En while
-løkke virker på følgende måte:
Instruksjonen(e) som står etter betingelsen utføres om og om igjen så lenge
betingelsen har verdi true
. (Foran hver ny
utførelse blir det sjekket om betingelsen fortsatt har verdi
true
.)
Det betyr blant
annet at dersom betingelsen har verdi false
når programutførelsen kommer til while
-løkka,
så blir ikke instruksjonen(e) som hører til
while
-løkka utført i det hele tatt.
Kommer programutførelsen inn i while
-løkka,
så kommer den ikke ut av den igjen før betingelsen skifter verdi til
false
. Skjer ikke dette, vil programmet 'henge
seg opp' fordi vi har fått det som kalles en evig (eller uendelig) løkke.
Vi må derfor sørge for at det er instruksjoner som endrer på betingelsen slik
at den får verdi false
når løkka ikke skal
utføres flere ganger.
while
-løkker bruker vi når vi ikke på
forhånd vet hvor mange ganger instruksjonen(e) som står inni løkka skal
gjentas, eventuelt om de skal utføres en eneste gang.
Vi skal lage et program som gjentatte ganger leser inn et antall sekunder og skriver ut dette konvertert til timer, minutter og sekunder. Programmet skal avsluttes når brukeren skriver et negativt tall.
Merknad: Begrepet algoritme
Ordet algoritme brukes generelt som betegnelse på en bestemt
framgangsmåte som kan følges for å oppnå et bestemt resultat. Vi kan tenke
på en algoritme som en form for 'kokebokoppskrift'. I en kokebokoppskrift er
det imidlertid som regel litt rom for 'slumsing': vi trenger ikke alltid følge den
helt til punkt og prikke for å kunne oppnå et bra resultat. En algoritme
gir ikke rom for noen 'slumsing': Vi må følge den til punkt og prikke for
at resultatet skal være garantert.
For det nevnte programmet vårt kan vi sette opp følgende algoritme
uttrykt i pseudo-kode, der variabelen tid
er det antall
sekunder som skal konverteres:
while ( tid >= 0 ) { < konverter tid > < skriv ut resultat > < les inn tid > }
Her støter vi imidlertid på et problem: variabelen
tid
brukes for å teste om programutførelsen
skal gå inn i while
-løkka. Det krever at den
på forhånd har fått en verdi som det kan testes på. En mulighet er at
brukeren skriver inn en tid allerede før programmet kommer til
while
-løkka. Med denne løsningen kan vi
utvide pseudo-koden vår til følgende skisse:
int tid; < les inn tid > while ( tid >= 0 ) { < konverter tid > < skriv ut resultat > < les inn tid > }
En annen mulighet er at vi (i egenskap av programmerer) gir variabelen
tid
en startverdi som sikrer at programmet
kommer inn i while
-løkka. Denne startverdien
vil i så fall bare være en hjelpeverdi for å komme inn i løkka, ikke en
verdi som programmet skal konvertere til timer, minutter og sekunder.
For å unngå at dette skjer, må vi endre noe på den opprinnelige løkka.
Vi kan for eksempel skrive som skissert i følgende pseudo-kode:
int tid = 0; while ( tid >= 0 ) { < les inn tid > if ( tid >= 0 ) { < konverter tid > < skriv ut resultat > } }
Begge de nevnte muligheter kan brukes av programmet vårt. De er stort sett
likeverdige, men ser vi litt mer kritisk på dem, ser vi at i den siste
versjonen må vi utføre testen
tid >= 0
to ganger. Det er unødvendig i
den første versjonen. Den vil derfor være å foretrekke dersom vi ønsker
at programmet skal være mest mulig effektivt med hensyn på kjøretid.
Et annet problem er hvordan vi skal få foretatt selve konverteringen
av et innlest antall sekunder til timer, minutter og sekunder. Til det
kan vi bruke javas divisjonsoperator og restoperator (modulusoperator).
Fra tidligere vet vi at dersom begge operander er av heltallstype, så
vil divisjonsoperatoren /
utføre heltallsdivisjon.
Dersom variabelen tid
inneholder det innleste
antall sekunder, vil derfor uttrykket tid / 3600
gi antall hele timer, siden det er 3600 sekunder i hver time. Antallet timer
må vi selvsagt lagre i en variabel til bruk ved utskriften. Når antall hele
timer er beregnet, må vi finne ut hvor mange overskytende sekunder det er,
det vil si antall sekunder som i neste omgang skal fordeles på minutter og
sekunder. En mulighet for å finne dette overskytende antallet, er at vi
skriver instruksjonen
tid = tid - timer * 3600;
der timer
er variabelen vi har brukt
for å lagre antall hele timer som er regnet ut. Men det er enklere og mer
elegant å bruke javas operator %
for beregning
av rest ved heltallsdivisjon. For antall overskytende sekunder er nettopp
resten som vi får ved divisjonen for å beregne antall hele timer. Istedenfor
instruksjonen ovenfor, kan vi derfor heller skrive
tid = tid % 3600;
På tilsvarende måte går vi fram når vi skal finne antall minutter og til slutt det overskytende antall sekunder. Forskjellen blir at vi nå må dividere med andre tall.
I oppgave 3 nedenfor får du som oppgave å lage et fullstendig program på grunnlag av det som er skissert ovenfor.
Det å kunne skrive en korrekt løkke er ikke noen lett oppgave for nybegynnere i programmering. Her er noen retningslinjer som kanskje kan være til hjelp:
while
-løkke
du skal bruke):
while (true) { < Instruksjoner >; }
while (løkke-betingelse) { < Instruksjoner >; < Tilleggsinstruksjoner for løkke-kontrollen >; }
Som du har sett av diskusjonen ovenfor vil imidlertid detaljene og rekkefølgen av instruksjonene avhenge av hvordan vi velger å løse enkelte av detaljene knyttet til startverdier og løkkebetingelse.
Skriv et fullstendig program for eksempel 4 ovenfor.
Lag en forbedret versjon av programmet fra oppgave 3. Forbedringen skal gå
ut på at dersom det innleste antall sekunder er mindre enn 3600, er det bare
antall minutter og sekunder som skal skrives ut. Dersom det innleste antall
sekunder er mindre enn 60, skal heller ikke antall minutter skrives ut. Da
er det altså bare det innleste antall sekunder som skal skrives ut. (For å
få til denne forbedringen, er det greiest å opprette en egen
String
-variabel for utskriften.)
Lag en ny versjon av programmet du lagde for oppgave 2 ovenfor. I den nye versjonen skal innlesing av brevets vekt og utskrift av porto utføres gjentatte ganger inntil det leses inn en negativ verdi for vekten.
I kapittel 2, oppgave 5 skulle du lage et
program som leste inn radien til en sirkel og skrev ut sirkelens areal.
Lag en ny versjon av dette programmet ved at programmet også beregner og
skriver ut sirkelens omkrets. (Formelen for omkrets er
2 * Π * r
.) Dessuten skal innlesing av radius og utskrift
av areal og omkrets foretas gjentatte ganger, inntil det leses inn en negativ
verdi for radien. (Utskrift av areal og omkrets kan gjøres i en og samme
dialogboks.)
En vanlig situasjon er at vi på forhånd, det vil si allerede når vi skriver
programmet, vet hvor mange ganger en løkke skal gjennomløpes. For å styre
løkka er det da naturlig å bruke en tellevariabel som teller opp antall
løkkegjennomløp. Det går greit å bruke en
while
-løkke i slike
situasjoner, men et bedre alternativ er det å bruke en
for
-løkke, som nettopp
er spesialtilpasset slike situasjoner. Den løkketypen tar vi for oss i
begynnelsen av neste kapittel.
Som vi har sett eksempler på, blir desimaltall (det vil si verdier av
type double
) i utgangspunktet skrevet ut
med maksimalt antall desimaler, som er inntil 16 desimaler. Unntaket er
at eventuelle 0-er på slutten blir sløyfet i utskriften. Ofte vil det virke
meningsløst å få skrevet ut desimaltall med 16 desimaler. Som regel ønsker vi selv
å kunne kontrollere hvor mange desimaler som skal skrives ut. Til dette formål
kan vi bruke klassen
DecimalFormat
fra javas
klassebibliotek. Den ligger i pakken java.text
.
Vi må derfor importere den ved at vi forrest i java-fila skriver
import java.text.DecimalFormat;
når vi vil bruke denne klassen i et program.
Formatering dreier seg om hvordan vi ønsker at utskriften skal se ut. Formatering berører ikke verdien til den variabelen som skal skrives ut. Formatering dreier seg også om tilpasning til lokale forhold. I Norge for eksempel, bruker vi komma som desimaltegn. Ved gruppering av sifre i grupper på tre ved utskrift av tall med mange sifre, brukes i Norge mellomrom mellom gruppene, ikke komma som brukes i USA. Et eksempel på standard formatering hos oss i Norge er
32 476,3789
Ved bruk av java-klassen DecimalFormat
finnes det mange muligheter for å bestemme formateringen. Dersom vi ikke
har angitt noe annet, vil DecimalFormat
bruke
den standard som gjelder i det land der java er installert. For eksempel vil
hos oss i Norge
gruppering og desimaltegn være som vist i eksemplet ovenfor. For angivelse
av formatering for øvrig, finnes det noen spesialtegn. De viktigste er
som følger:
0 | Indikerer et siffer. Sifferet vises alltid, også når det er 0. |
# | Indikerer et siffer. Sifferet vises ikke når det er ledende 0 eller en 0 på slutten. |
. | Indikerer plassering av desimaltegn. Desimaltegn er i Norge komma. |
, | Indikerer plassering av gruppeseparator. Gruppeseparator er i Norge mellomrom. |
% | Indikerer multiplikasjon med 100 og visning som en prosentstørrelse. |
Når vi skal bruke klassen DecimalFormat
til
å formatere en double
-variabel
x
(som på forhånd er blitt tilordnet en verdi),
må vi skrive kode på følgende form (uttrykt i pseudo-kode):
String formateringsstreng = < en streng som bestemmer ønsket formatering >; DecimalFormat formateringsobjekt = new DecimalFormat( formateringsstreng ); String utskrift = formateringsobjekt.format( x );
String
-variabelen
utskrift
vil nå inneholde verdien til
x
formatert slik vil ønsker og kan brukes
til utskrift på vanlig måte, for eksempel i en meldingsboks.
På grunnlag av det vi lærte i kapittel 3 om klasser, objekter og konstruktører, kan vi nå tolke instruksjonen
DecimalFormat formateringsobjekt = new DecimalFormat( formateringsstreng );
på følgende måte: Vi oppretter et objekt av type
DecimalFormat
. Strengen formateringsstreng
blir
i form av konstruktørparameter overført som verdi til et av datafeltene i
objektet. Variabelen formateringsobjekt
blir satt til å
referere til (peke på) objektet.
"0.00" //gir to desimaler som alltid vises, selv om de er 0 "0.00#" //gir inntil tre desimaler. Den siste vises ikke dersom den er 0 "##,##0.0000" //vil blant annet gi 32 476,3789
Noen ganger ønsker vi for eksempel at et heltall skal oppfattes som et desimaltall.
Vi ønsker å regne ut snittet av noen heltall i form av en desimaltallsverdi.
Vi tenker oss da at int
-variabelen
sum
inneholder summen av
n
slike heltall. Dersom vi da skriver
for eksempel
double snitt = sum / n;
for å beregne snittet, vil det på høyre side av tilordningsoperatoren bli
foretatt en heltallsdivisjon, siden både sum
og n
er av type int
.
Dersom for eksempel sum
er lik 17 og
n
er lik 3, vil resultatet av divisjonen bli 5.
Ved tilordningsoperasjonen vil 5 automatisk bli konvertert til type
double
, slik at
snitt
vil få verdien 5.0.
For å få foretatt en divisjon mellom desimaltall ved beregning av snittet,
kan vi før divisjonen foreta en konvertering av enten
sum
eller n
til
type double
. Har vi skrevet kode for å
konvertere den ene av disse, vil også den andre automatisk bli konvertert.
Divisjonen blir da mellom desimaltall, slik at vi får beregnet snittet på den
måten vi ønsker.
Typekonvertering får vi generelt utført ved at vi rett foran den variabel som ønskes konvertert skriver inni en parentes den datatypen vi ønsker konvertering til. I vårt tilfelle får vi derfor riktig snittberegning ved å skrive instruksjonen
double snitt = (double) sum / n;
Merknader Operatoren () for typekonvertering har høyere prioritet
enn divisjon. Typekonverteringen vil derfor bli utført før
divisjonen. (Dersom du er i tvil om prioriteten, er det tryggest å sette inn
ekstra parenteser, slik at du sikrer deg at det som står mellom disse
parentesene utføres først.) Variabelen sum
vil
ikke bli berørt av typekonverteringen. Den vil fortsatt være av type
int
og vil beholde den verdien den hadde
før typekonverteringen. Typekonverteringen medfører bare at det blir opprettet
en midlertidig verdi av den type vi har spesifisert. Denne midlertidige verdien
brukes (i vårt eksempel) ved divisjonen. Det er selvsagt ikke tillatt å
konvertere helt fritt mellom hvilke som helst datatyper. Dersom den typekonverteringen
vi prøver å foreta ikke er tillatt, vil den resultere i en kompileringsfeil.
I programmer forekommer det forholdsvis ofte tilordningsinstruksjoner av formen
variabel = variabel + verdi;
(variabel
kan være av numerisk type eller
String
). En slik instruksjon kan forkortes til
variabel += verdi;
På tilsvarende måte kan vi for numeriske variable
x
og y
skrive
x -= y;
istedenfor
x = x - y;
x *= y;
istedenfor
x = x * y;
x /= y;
istedenfor
x = x / y;
x %= y;
istedenfor
x = x % y;
(de to siste forutsatt at y != 0
).
I tilfelle tellevariable har vi ofte bruk for instruksjoner av formen
antall = antall + 1;
eller
antall = antall - 1;
Disse kan forkortes til henholdsvis
antall++; antall--;
Det er også tillatt å skrive henholdsvis
++antall; --antall;
Dersom disse står som egne instruksjoner, slik de gjør ovenfor, vil det være likegyldig om vi bruker det første eller det andre av disse to alternativene. Men dersom vedkommende variabel med en av disse operatorene foran eller bak inngår som del av et uttrykk, vil det bli forskjellig virkning: Står operatoren bak variabelen, er det den gamle verdien til variabelen som brukes ved beregning av uttrykket. Økningen eller minkningen av variabelen foretas først etterpå. Dersom operatoren står foran variabelen, er det motsatt. Da økes eller minkes denne først. Deretter foretas beregning av uttrykket som den inngår i.
Anta at vi har to int
-variable antall
og
variabel
som på forhånd er blitt tilordnet verdier. Dersom vi
da skriver instruksjonen
variabel = antall++;
så vil dette gi samme resultat som de to instruksjonene
variabel = antall; antall = antall + 1;
Skriver vi isteden instruksjonen
variabel = ++antall;
så vil dette gi samme resultat som de to instruksjonene
antall = antall + 1; variabel = antall;
altså motsatt rekkefølge.
Copyright © Kjetil Grønning og Eva Hadler Vihovde, revidert 2014