Springe zum Inhalt oder Footer
SerloDie freie Lernplattform

Kurs

Fallunterscheidungen, Schleifen und Kommentare

1 Fallunterscheidungen

Bis jetzt haben wir in den Beispielaufgaben nur Code verwendet, der immer gleich, der Reihe nach und komplett ausgeführt wird.

Es gibt mehrere Möglichkeiten, zwischen verschiedenen Fällen zu differenzieren, die if()-Abfrage ist eine der am häufigsten verwendeten.

Der Syntax lautet:

if(boolscher Wert) {
    Anweisungen
}else {
    Anweisungen
}

In der Klammer hinter dem if muss ein boolscher Wert stehen, das könnte eine Variable oder ein Vergleich sein. Die Anweisungen im Block nach dem if werden also nur ausgeführt, wenn der boolsche Wert true ergibt.

Beispiel:

Beispiel Kuchen: Code mit Fallunterscheidung

Der else-Bereich könnte natürlich leer sein, dann kann man ihn auch einfach weglassen und schreibt

if(boolscher Wert) {
    Anweisungen
}

Die Einrückung, die ich oben im if- und im else-Block gemacht habe, dient der Übersichtlichkeit.

Wir haben zwei Strings definiert und in Abhängigkeit davon, ob magKuchen true oder false ist, wird der eine oder der andere ausgegeben.

In der if Abfrage können auch Werte verglichen werden:

  • <, > kleiner oder größer

  • <=, >= kleiner-gleich, größer-gleich

  • == ist gleich (Wichtig: wenn man nur ein = verwendet, denkt Java, es wäre eine Variablenzuweisung !!! Fehlergefahr)

  • != ungleich

Aufgabe 1:

Du hast drei Zahlen, a,b und c gegeben.

Erziele folgende Ausgabe:

Die größte Zahl ist: + Buchstabe + Wert: + Wert

Wenn zwei Zahlen gleich groß sind, ist es egal welche ausgegeben wird.

Tipp: teste deinen Code mit verschiedenen Werten.

Ineinander verschachtelte if-Abfragen müssen jedoch nicht immer dann verwendet werden, wenn man mehrere Dinge überprüfen will, die logischen Operatoren, die in Kurzeinführung in die Informatik erklärt werden, können hier verwendet werden:

  • && Logisches Und

  • || Logisches Oder Hinweis: dieses Zeichen lässt sich mit rechts-alt + < erzeugen

  • ! Logisches Nicht

Beispiel:

if(b1 && !(!b2 || !b3)) {
    System.exit(0);
}

System.exit(0); sorgt übrigens dafür, dass das Programm beendet wird.

Wer sich mit logischen Vergleichen etwas genauer auskennt weiß, dass

(b1 && !(!b2 || !b3)) = (b1 && b2 && b3).

Es kann sich also durchaus lohnen sich mit diesem Thema zu befassen.

Aufgabe 2:

Schreibe ein kurzes Programm, das die Zahlen a und b enthält. Wenn a größer als 4 ist, soll a / b ausgegeben werden.

Tipp: Darf b alle Werte annehmen?

Die beiden Dinge, die überprüft werden müssen, können je geklammert sein, müssen es aber nicht. Java wertet die Operatoren in folgender Reihenfolge aus:

Operatorenpriorität:

(absteigende Priorität)

Klammern

()

Einstellige Operationen

- (als Vorzeichen), ++, --, !, (cast)

Multiplikative Operationen

*, /, %

Additive Operationen

+, -

Vergleichsoperationen

==, !=, <, >, <=, >=

Konjunktion

&&

Disjunktion

Zwei senkrechte Striche

Zuweisungsoperationen

=, +=, -=, *=, /=, %=

In dieser Tabelle kommen einige Dinge vor, die den meisten Lesern unbekannt sein dürften:

  • ++, -- diese Operatoren (Inkrement und Dekrement) verändern den Wert einer Variable um 1, beispiel einInt++; würde den Wert von einInt um 1 erhöhen.

  • % Berechnet den Rest einer Division, also z.B. 12 % 5 = 2.

  • +=, -=, *=, /=, %= Da man recht oft auf Variablen herumrechnet, kann man statt a = a + b; auch a += b; schreiben, analoges gilt auch für die anderen Rechenarten, wichtig ist hierbei, dass die Variable, die geändert wird, an vorderer Stelle steht.

Alles in allem ist es im Zweifelsfall oder der Übersichtlichkeit halber nie verkehrt, Klammern zu verwenden.

Aufgabe 3:

Gegeben:

int a = 0;
int b = 0;

Erhöhe den Wert von a um 5, indem du lediglich den Inkrement-Operator verwendest. Erhöhe den Wert von b um 5, indem du lediglich den +=-Operator verwendest.

Man kann den Inkrement, bzw Dekrement Operator auch in einer Rechnung verwenden:

int a = 3;
int b = a++ + 10;
int c = ++a + 10;

System.out.println("b: " + b + ", c: " + c);

erzeugt die Ausgabe:

b: 13, c: 15

Wenn der Operator also vor der Variable steht, so wird er ausgeführt, bevor die Variable in der Rechnung verwertet wird, wenn er dahinter steht, erst danach.

Um verwirrenden Code zu vermeiden, empfiehlt es sich daher, die Änderungen an Operatoren immer in eine eigene Zeile/Anweisung zu packen:

int a = 3;
int b = a + 10;
a++;
a++;
int c = a + 10;

Das ist deutlich übersichtlicher als das vorherige Beispiel.

Dieser Artikel handelt von Fallunterscheidungen, nehmen wir uns also ein etwas komplexeres Beispiel:

Aufgabe 4:

gegeben:

int hausPreis = x;

erreiche abhängig vom Wert von x folgende Ausgabe:

  • < 150.000: Das Haus ist geschenkt

  • < 250.000: Das Haus ist günstig

  • < 450.000: Das Haus hat einen durchschnittlichen Preis

  • < 600.000: Das Haus ist anspruchsvoll

  • >= 600.000: Das Haus ist teuer

Um nur eine Ausgabe zu erreichen wäre eine geschachtelte if-Abfrage nötig. Um diesen Mehraufwand zu verhindern gibt es die else if Konstruktion:

if(b1) {
    Anweisungsblock;
}else if(b2) {
    Anweisungsblock;
}else {
    Anweisungsblock;
}

Hierbei können beliebig viele else-if Abfragen verwendet werden, es wird also nur ein Anweisungsblock insgesamt ausgeführt. Selbstverständlich ist auch hier die else-Anweisung optional.

Da die Bedingungen der Reihe nach überprüft werden, ist z.B. beim Erreichen der (hausPreis Bedingung schon klar, dass der Preis größer als 250k sein muss.

Die Unterstriche in den Zahlen erhöhen die Übersichtlichkeit zusätzlich. Wenn bei IntelliJ hierbei jedoch ein Fehler angezeigt wird, so muss das language-level des Projekts erhöht werden:

File - Project Structure - Project

dort auf mindestens 7.0 setzen.

Project Structure

switch-case

Es gibt eine weitere Möglichkeit für Fallunterscheidungen:

switch(zahl) {
    case 500:
        Anweisungen
        break;
    case 100:
        Anweisungen
        break;
    default:
        Anweisungen
        break;
}

Der default-Block entspricht dem else-Block. Da bei einer switch-case Abfrage nur feste Werte überprüft werden können, ist es für einige Fälle, wie z.B. unsere Hauspreis-Analyse ungeeignet.

Die break-Anweisungen bewirken, dass die Befehlsausführung erst nach dem switch-Block forgesetzt wird, ihre Verwendung ist notwendig, da sonst alle folgenden Anweisungen ausgeführt werden würden.

Zur Auswertung können byte, short, char, int und Strings herangezogen werden.

2 Schleifen und Kommentare

Wir wollen uns nun eine sinnvollere Aufgabe überlegen:

Aufgabe 1:

Vorgegeben:

int x;

Ziel: Ausgeben, ob x eine Primzahl ist.

Hilfestellung:

for(A; B; C) {
    Anweisungen
}

Schleifen sind dazu da um Anweisungen wiederholt auszuführen.

A, B und C sind Anweisungen, sie sind im Vergleich zu den Semikolons zwischen ihnen optional.

Anweisung A ist eine Initialisierungsanweisung, hier wird meist eine Laufvariable initialisiert, int i = 0 zum Beispiel.

B ist eine Abbruchbedingung, ein Beispiel ist i < 100.

C ist ein für gewöhnlich eine Inkrement/Dekrement-Anweisung i++.

Ein Beispiel für eine Schleife, die alle Zahlen von 1 bis 100 ausgibt:

for(int i = 1; i < 101; i++) {
    System.out.println(i);
}

Der Vorteil von i < 101 gegenüber i <= 100 ist, dass bei < 101 der Wert der Abbruchbedingung minus den Initialisierungswert die Anzahl der Iterationen entspricht: 101 - 1 = 100! Durch einen solchen Stil kann man Fehler vermeiden.

Wichtig ist außerdem noch, dass vor jedem Schleifendurchlauf zuerst überprüft wird, ob die Abbruchbedingung erfüllt ist.

Wenn nicht, wird die Schleife und anschließend die Inkrement/Dekrement Anweisung ausgeführt, dann beginnt dasselbe von vorn.

Viel Erfolg bei der Aufgabe!

Bevor wir den Code untersuchen, wollen wir uns die Definition einer Primzahl ansehen:

Eine Zahl, die nur durch sich selbst und Eins ohne Rest und ganzzahlig teilbar ist.

Eine Zahl x lässt sich also am Einfachsten auf diese Definition überprüfen, indem man sie durch alle Zahlen von 2 bis x-1 teilt. Wenn immer ein Rest übrig bleibt, dann handelt es sich um eine Primzahl.

Da das Teilen von x durch eine Zahl z mit z > x/2 und z < x stets ein Ergebnis zwischen 1 und 2 zur Folge hat, reicht es alle Zahlen von 2 bis x/2 zu überprüfen.

Zeile 4:

for(int i = 2; (i <= x / 2) && prim; i++) {

Wir wollen x durch einige Zahlen ab der 2 teilen, also initialisieren wir i mit dieser Zahl.

Außerdem haben wir soeben festgestellt, dass wir alle Werte bis x/2 überprüfen wollen, daher geben wir als Abbruchbedingung i <= x/2 an; auf den Teil && prim werden wir gleich genauer eingehen.

Da wir x durch jede natürliche Zahl teilen wollen, wählen wir als Inkrement ein klassisches i++.

Zeile 5:


if(x % i == 0) {

Zu gut deutsch: wenn man x durch i ohne Rest teilen kann.

Zeile 6:

prim = false;

Wir haben uns dazu entschieden eine boolsche Variable zu verwenden. Wenn nun nach der Schleife prim false ist, dann wissen wir, dass ein Teiler gefunden wurde und dass x keine Primzahl ist.

Dadurch, dass wir in Zeile 4 && prim überprüfe, bricht die Schleife nach dem ersten gefundenen Teiler ab.

Aufgabe 2:

  1. Erweitere das Programm so, dass der Benutzer eine Zahl eingibt und für jede Zahl bis hin zur eingegebenen wird ermittelt, ob es sich um eine Primzahl handelt.

  2. Kommentiere den Code so, dass eine dritte Person sofort erkennt, was jener für eine Funktion hat.

Mit

Scanner sc = new Scanner(System.in);
int y = sc.nextInt();

können Zahleneingaben abgefragt werden, zusätzlich muss die Anweisung import java.util.Scanner; oberhalb der Klasse stehen:

package serlo;
import java.util.Scanner;
public class Testklasse {

In Java können im Quellcode Kommentare mit // platziert werden:

// Das ist ein Kommentar, der bei der Programmausführung ignoriert wird.

Mehrzeilige Kommentare können mit /* */ platziert werden.

Die Kommentierung in dieser Lösung ist selbstverständlich übertrieben, wichtig beim Kommentieren ist, dass man seinen eigenen Code auch nach einigen Monaten lesen kann.

Vor allem bei komplizierten Konstrukten ist das Kommentieren wichtig, später werden wir noch etwas genau darauf eingehen.

Der Code sollte recht verständlich sein, mit etwas Farbe lässt sich dies sogar noch steigern:

Bild

Bei IntelliJ lässt sich die Farbe mit File --> Settings und dann weiter unter Editor --> Colors & Fonts --> Java anpassen. Wer eine andere Version oder eine andere Entwicklungsumgebung verwendet, wird zur Not sicher im Internet fündig.

Bild

Aufgabe 3:

Reduziere die Kommentare auf ein sinnvolles Maß und teste das Programm mit der Eingabe 100.000einmal mit (i <= x / 2) && prim und einmal mit i < x als Abbruchbedingung.

Versuch den Code weiter zu optimieren.

Tipp: Entwicklungsumgebungen haben in der Konsole für gewöhnlich einen roten, quadratischen Stopp-Knopf, um die Codeausführung vorzeitig abzubrechen.

Andere Schleifentypen:

Neben der for()-Schleife gibt es auch noch die while()- und die do-while()-Schleife:

for(int i = 0; i < 10; i++) {
    System.out.print(i);
}

System.out.println();

int i = 0;
while(i < 10) {
    System.out.print(i);
    i++;
}

System.out.println();

i = 0;
do {
    System.out.print(i);
    i++;
} while(i < 10);

Die do-while Schleife wird meist verwendet, wenn man den Schleifenkörper mindestens einmal ausführen möchte.

Aufgabe 4:

k=7666k10\displaystyle \sum_{k=7}^{666} \frac{k}{10}

Lass diese Summe mit Hilfe einer Schleife berechnen und gib das Ergebnis aus.

Hier noch ein Link für diejenigen unter euch, denen das Summenzeichen unbekannt ist: Summenzeichen.

Aufgabe 5:

Schleifen eignen sich ideal dafür um mit Arrays zu arbeiten.

Erziele die folgende Bilschirmausgabe

Montag ist der 1. Tag der Woche.
[]
Sonntag ist der 7. Tag der Woche.

Verwende zur Bildschirmausgabe nur die folgende Zeile: System.out.println(woche[i]);.

3 JavaDoc Kommentare

Wir haben uns soeben schon mit dem Thema Kommentare beschäftigt:

// Das ist ein Kommentar, er ist ausschließlich für die Programmierenden gedacht.
/* Dies ist ein mehrzeiliger Kommentar,
   er kann über beliebig viele Zeilen gehen.
   Allerdings sollte man vorsichtig sein, da man ihn nicht verschachteln kann,
   es ist somit sinnvoll, Codezeilen, die man gerade nicht verwenden will,
   mit einzeiligen Kommentaren zu neutralisieren, das bietet den Vorteil, dass man,
   wenn man kurzzeitig einige duzende oder hunderte Zeilen auskommentieren will,
   diese mit einem mehrzeiligen Kommentar umklammern kann */

/** 
* Eine weitere Möglichkeit mehrzeilige Kommentare zu erstellen, stellen die sogenannten JavaDoc-
* Kommentare dar, sie bieten die Möglichkeit den Code auf eine Art und Weise zu kommentieren,
* welche das Programmieren sehr vereinfacht. Der einzige Unterschied gegenüber normalen,
* mehrzeiligen Kommentaren ist der zweite Stern am Anfang, die Sterne am Anfang jeder neuen 
* Zeile sind optional aber üblich.
*/

Wenn man im Quellcode auf eine Variable, Methode oder Klasse (dazu später noch mehr) klickt und anschließend Strg + Q drückt, erscheint ein kleines Popup mit einer hoffentlich hilfreichen Javadoc Kommentation. Bei Eclipse muss man bei Standardeinstellungen mit dem Mauszeiger nur auf ein solches Element hovern, um die Dokumentation dazu einzublenden.

JavaDoc Kommentare werden bei größeren Projekten sehr wichtig, sie werden vor eine Variable, Methode oder Klasse geschrieben.

package serlo;

// import java.util.Scanner;

/**
 *Testklasse um diverses Zeug zu testen
 *@since 17.03.2015
 */
public class Testklasse {

   /**
    *Zeugs
    *@param args
    *@since 17.03.2015
    */
    public static void main(String[] args) {
       /** Eine supergeheime Variable */
       int illuminati = 420;

       System.out.println(illuminati);
    }
}

@param o.ä. wird als Tag bezeichnet, damit lassen sich Zusatzinformationen speichern.

Wenn man gute JavaDoc-Kommentare gemacht hat, kann man später bei großen Projekten eine sogenannte JavaDoc-Dokumentation erstellen lassen, welche anderen Programmierern dann erklärt, welche Methoden was erledigen (somit kann man den Code von anderen Leuten verwenden, ohne sich die Methoden ansehen zu müssen).


Dieses Werk steht unter der freien Lizenz
CC BY-SA 4.0Was bedeutet das?