Algoritmer og datastrukturer
E − Løkker i Java
E  Løkker i Java


Til Avsnitt E.2 - While-løkker   E.1   For-løkker
En for-løkke består av de fire delene initialisering, betingelse, oppdatering og kropp (eng: body). Et typisk eksempel er en for-løkke som traverserer en tabell a:

  for (int i = 0; i < a.length; i++)
  {
    // kroppen
  }
                   Programkode E.1 a)

Her er initialiseringen gitt ved int i = 0, betingelsen er i < a.length og oppdateringen i++. Det som står i blokken innrammet av krøllparentesene { }, er for-løkkens kropp. Den består normalt av en eller flere programsetninger.

En generell for-løkke ser slik ut:

  for (<initialisering>; <betingelse>; <oppdatering>)
  {
    // kroppen
  }
                   Programkode E.1 b)

I flg. eksempel brukes en for-løkke til å travsere en generisk liste ved hjelp av en iterator. La f.eks. listens generiske parametertype være String:

  for (Iterator<String> i = liste.iterator(); i.hasNext(); )
  {
    String s = i.next();

    // øvrige programsetninger
  }
                   Programkode E.1 c)

Hvis kroppen har kun én setning, trengs ingen blokk, dvs. innramming av krøllparenteser:

  for (int i = 0; i < a.length; i++) <programsetning>;

Det er lurt å ha en blokk selv med kun én setning. Da er blokken klar hvis det senere trengs flere setninger. Ellers er det fort gjort at en ny setning havner utenfor for-løkken. Noen liker å ha alt på én linje hvis det er kun en kort setning. Da droppes blokken.

Variabelen som initialiseres kalles generelt en «tellevariabel» (eng: counter). En står helt fritt til å velge navn på den, men hvis for-løkken arbeider i en tabell, brukes ofte navn som i, j, k, m og n. Det kommer nok av at de samme bokstavene brukes i summeformler i matematikk. Bokstaven l brukes vanligvis ikke siden den i mange tegnsett ligner for mye på sifferet 1.

Det kan være situasjoner der en trenger flere «tellevariabler». Da må det være komma mellom dem og ikke semikolon. I flg. eksempel kopieres innholdet av tabellen a over i tabellen b, men i motsatt rekkefølge:

  int[] a = {1,2,3,4,5};
  int[] b = new int[a.length];      // like lang som a

  for (int i = 0, j = b.length - 1; i < a.length; i++, j--)
  {
    b[j] = a[i];    // kopierer fra a til b
  }

  System.out.println(Arrays.toString(b));  // Utskrift: [5, 4, 3, 2, 1]

                   Programkode E.1 d)

Rekkevidden (eng: scope) til en «tellevariabel» er for-løkkens blokk. I noen situasjoner kan det være gunstig å bryte av (break) en for-løkke når noe spesielt inntreffer. Hvis vi da oppretter tellevariabelen foran for-løkken, vil vi kunne få tak i dens verdi etterpå:

  int i = 0;
  for ( ; i < a.length; i++)
  {
    // programsetninger

    if <et eller annet> break;
  }

  // Nå kan vi få tak i verdien til i

                   Programkode E.1 e)

Dette betyr at en eller flere av for-løkkens deler kan være tomme, dvs. ingen kode. Det mest ekstreme er at hverken initialiseringen, betingelsen eller oppdateringen har kode:

  for ( ; ; )
  {
    // kropp
  }

Denne konstruksjonen omtales som en «evig løkke». Det er situasjoner der det er gunstig å sette i gang en løkke på denne måten. Men da må det finnes kode blant programsetningene i kroppen som gjør at løkken garantert brytes på et eller annet tidspunkt.

For-løkker er så vanlige at de fleste utviklingsverktøy har maler (eng: templates) for dem. Hvis en bruker NetBeans, har en tabell med navn tabell og trenger en for-løkke som skal arbeide i den, kan en først skrive fori og så trykke tabulator-tasten. Da kommer dette:

  for (int i = 0; i < tabell.length; i++)
  {
    int j = tabell[i];

  }

I Eclipse kan en skrive for og så trykke CTRL+mellomrom. Da kommer det tilbud om flere maler. Velges for - iterate over array, kommer dette:

  for (int i = 0; i < tabell.length; i++)
  {

  }

Netbeans og Eclipse har flere maler enn dette for for-løkker.



Til Avsnitt E.3 - While-løkker   E.2   For-alle-løkker
En for-alle-løkke (eng: for-each loop) brukes til å traversere en hel datastruktur. Det gjelder:

En generell for-alle-løkke ser slik ut:

  for (<datatype> <navn> : <objekt>)
  {
    // programsetninger
  }

Dette kan vi lese slik: for alle verdier navn av typen datatype fra objekt osv. Her må objekt være en tabell av den gitte typen eller en instans av en generisk klasse som er Iterable.

Eksempel med en tabell:

  int[] a = {1,2,3,4,5,6,7,8,9,10};

  for (int k : a) System.out.print(k + " ");

  // Utskrift: 1 2 3 4 5 6 7 8 9 10

                   Programkode E.2 a)

Eksempel med en liste:

  List<Character> liste = new LinkedList<>();

  liste.add('A'); liste.add('B'); liste.add('C');

  for (Character c : liste) System.out.print(c + " ");

  // Utskrift: A B C

                   Programkode E.2 b)

LinkedList er Iterable siden LinkedList implementerer List, den arver (eng: extends) Collection og Collection arver Iterable. Alle disse tre er grensesnitt (eng: interface). Når en klasse er Iterable har den garantert metoden iterator(), dvs. en metode som returnerer en Iterator. Det er den som brukes implisitt i for-alle løkken.

Java har mange Iterable-klasser. F.eks. flg. fra java.util: ArrayDeque, ArrayList, HashSet, LinkedHashSet, LinkedList, PriorityQueue, Stack, TreeSet og Vector.

Eksempel med tabell og mengde (eng: set):

  int[] a = {5,9,2,4,7,10,8,1,3,6};              // en tabell

  Set<Integer> s = new TreeSet<>();              // en mengde (TreeSet)

  for (int k : a) s.add(k);                      // fra tabell til mengde

  for (int k : s) System.out.print(k + " ");     // skriver ut

  // Utskrift: 1 2 3 4 5 6 7 8 9 10

                   Programkode E.2 c)


Til Avsnitt E.4 - Do-while-løkker   E.3   While-løkker
En while-løkke har en betingelse og en kropp (eng: body) og ser generelt slik ut:

  while (<betingelse>)
  {
    // kropp
  }

While-løkken går så lenge som betingelsen er oppfylt. Alt vi kan få til med en for-løkke kan vi få til med en while-løkke, og omvendt. Programkode E.1 a) viser en for-løkke som traverserer en tabell. Dette løses slik ved hjelp av en while-løkke:

  int i = 0;

  while (i < a.length)
  {
    // kropp

    i++;
  }
                   Programkode E.3 a)

Som nevnt i Avsnitt E.1, kan det av og til være gunstig å sette i gang en «evig løkke». Da må selvfølgelig løkkens «kropp» inneholde kode som gjør at løkken før eller senere brytes (break eller return). En «evig» while-løkke lages slik:

  while (true)
  {
    // kropp
  }

Ved fil-lesing brukes ofte en while-løkke. I flg. eksempel finner vi antall linjer på en tekstfil:

  FileReader fil = new FileReader("fil.txt");
  try (BufferedReader inn = new BufferedReader(fil))
  {
    String s;  // skal romme en linje fra filen
    int antall = 0;

    while ((s = inn.readLine()) != null)
    {
      antall++;
    }

    inn.close();

    // variabelen antall inneholder nå antall linjer på filen
  }
                   Programkode E.3 b)

Konstruksjonen over er litt spesiell. Det er linje != null som er betingelsen, men det utføres en innlesing før den testes. Dette kunne vært løst slik med en for-løkke:

  int antall = 0;

  for (String s = inn.readLine(); s != null; s = inn.readLine())
  {
    antall++;
  }


Til starten på delkapitlet   E.4   Do-while-løkker
I både for-løkker og while-løkker sjekkes betingelsen før programsetningene i løkkens kropp utføres. I noen situasjoner kan det være aktuelt å utføre setningene én gang før betingelsen sjekkes. En do-while-løkke er laget for det formålet. En slik løkke består av en kropp (eng: body) og en betingelse og ser generelt slik ut:

  do
  {
    // kropp
  }
  while (<betingelse>);

I Programkode E.3 b) brukte vi en while-løkke til å telle opp antall linjer på en tekstfil. Dette kan også løses ved en do-while-løkke. Legg merke til at variabelen antall nå blir initiert til -1. Det kommer av at setningen antall++ blir utført én gang selv om filen ikke skulle ha noen linjer, dvs. den er tom.

  FileReader fil = new FileReader("fil.txt");
  try (BufferedReader inn = new BufferedReader(fil))
  {
    String s;  // skal romme en linje fra filen
    int antall = -1;

    do
    {
      s = inn.readLine();
      antall++;
    }
    while (s != null);

    inn.close();

    // variabelen antall inneholder nå antall linjer på filen
  }
                   Programkode E.4 a)


Valid XHTML 1.0 Strict