1.03 Variablen 1: Einführung & Typen

Einführung

Variablen vom Typ int

Variablen gehören zu den wichtigsten Werkzeugen beim Programmieren, egal mit welcher Programmiersprache. Daher sehen wir uns hier genau an, was sich dahinter verbirgt.

Eine Variable können wir uns wie einen kleinen Kasten vorstellen:

Eine einfache Darstellung eines Kastens mit den Aufschriften „int“ und „meineZahl“.
Eine Variable stellen wir uns als einen Kasten vor.

In so einem Kasten können wir Daten ablegen, verändern und später auch wieder auslesen.

Wie wir in der Abbildung schon sehen, besitzt so ein Kasten zwei Beschriftungen. In diesem Fall haben sie die folgenden Bedeutungen:

  • int steht für den Datentyp Integer; das ist einfach das englische Wort für ganze Zahl. Wir dürfen hier daher nur ganze Zahlen ablegen.
  • meineZahl ist der Name des Kastens bzw. der Variablen. Dieser ist wichtig, damit wir auf sie zugreifen können.

Wir wollen nun in unserer ersten Variablen den Wert 5 ablegen und danach einfach wieder ausgeben lassen.

Der Kasten von eben mit einem Zettel mit der Aufschrift „5“.
Die Zahl 5 wurde abgelegt.

Sehen wir uns an, wie dies in Java funktioniert:

public class VariablenEinfuehrung {

  public static void main(String[] args) {
    
    int meineZahl; // Deklarieren
    meineZahl = 5; // Initialisieren
    
    System.out.println(meineZahl);

  }

}

Beim sogenannten Deklarieren wird die Variable erst einmal angelegt. Bildlich gesprochen wird der leere Kasten bereitgestellt. Legt man das erste Mal einen Wert in der Variablen ab, spricht man vom Initialisieren dieser Variablen.

Uns sollte hier die etwas ungewöhnliche Schreibweise des Namens der Variablen meineZahl ins Auge fallen. Diese hält sich an die Konvention für sauberes Programmieren mit Java. Diese sagt:

  • Der Name einer Variablen sollte immer mit einem kleinen Buchstaben beginnen.
  • Wird der Name aus mehreren Wörtern zusammengesetzt, wird der erste Buchstabe eines neuen Wortes groß geschrieben.
  • Der Name sollte aussagekräftig sein!

Natürlich hätten wir auch den Namen mZ oder einfach x verwenden können. Aber damit würden wir unser Programm für andere schwer lesbar machen. Wenn wir uns einmal in Foren oder anderen Tutorien Beispiele für Programme ansehen, werden wir schnell merken, wie viel angenehmer ein Quelltext zu lesen ist, in dem klare Namen verwendet werden!


Hintergrundinfo:

Wir könnten das Deklarieren und Initialisieren auch in einem Schritt erledigen:

int meineZahl = 5;  // Deklarieren und Initialisieren

Meiner Erfahrung nach ist es aber gerade für Programmiereinsteiger günstiger, diese beiden Schritte zu trennen. Zum einen werden sie später (beim objektorientierten Programmieren) auch meist getrennt sein. Zum anderen ist es gerade beim Einstieg ins Programmieren eher ungünstig, für denselben Vorgang mehrere Varianten zu lernen. Da aber in vielen anderen Quellen zu Java diese Schreibweise vorzufinden ist, wollte ich sie hier zumindest einmal erwähnen.


Oben haben wir ja bereits erwähnt, dass der Wert einer Variablen auch verändert werden kann. Sehen wir uns ein Beispiel an:

public class VariablenEinfuehrung_02 {

  public static void main(String[] args) {
    
    int meineZahl;
    meineZahl = 5;
    
    int deineZahl;
    deineZahl = 10;

    meineZahl = meineZahl + 2;
    
    deineZahl = meineZahl * deineZahl;
    
    meineZahl = meineZahl + deineZahl;
    
    System.out.println(meineZahl);
    System.out.println(deineZahl);
    
  }

}

Wir sehen, dass hier zunächst die beiden Variablen meineZahl und deineZahl eingeführt werden. Die erste erhält den Startwert 5 und die zweite den Startwert 10. Durch

meineZahl = meineZahl + 2;

wird der Wert von meineZahl um 2 erhöht. Genauer gesagt, bedeutet diese Anweisung „Setze den neuen Wert von meineZahl auf den alten Wert von meineZahl plus zwei“.

Hier sollten wir uns darüber bewusst sein, dass das Gleichheitszeichen nicht ganz dem Gleichheitszeichen aus der Mathematik entspricht. Es bedeutet nicht „meineZahl ist gleich meineZahl plus zwei“ – dann müsste ja null gleich zwei sein! Es ist als der Befehl „setze den neuen Wert“ zu verstehen. In anderen Programmiersprachen wird dies deutlich, indem dort statt des Gleichheitszeichens ein := geschrieben wird.

Beim Gleichheitszeichen in Java müssen wir daher auch die Reihenfolge beachten. D.h., die folgende Anweisung dürfen wir nicht machen:

meineZahl + 2 = meineZahl; // Fehler!

Was passiert im weiteren Verlauf des Beispielprogramms eigentlich noch? Die Variable meineZahl wurde nun auf 7 erhöht. Im nächsten Schritt wird deineZahl auf das Produkt der beiden Variablen gesetzt, d.h., deineZahl erhält den Wert 70. Schließlich wird meineZahl die Summe beider Variablen zugewiesen, so dass sie den Wert 77 hat. Die beiden Ausgaben am Ende werden dies bestätigen.

 


Hintergrundinfo:

Neben dem Datentyp int gibt es noch weitere Datenytpen für ganze Zahlen. Sie unterscheiden sich darin, wie groß die Zahlen werden dürfen, die sie speichern können. Im Abschnitt „Übersicht der primitiven Datentypen“ gehen wir darauf nochmal ein. Für den Anfang müssen wir uns um die anderen Datentypen aber keine Sorgen machen und können ruhig immer auf den populärsten Datentyp int zurückgreifen.


Typsicherheit

Java ist eine typsichere Programmiersprache. Das bedeutet, dass Java sehr streng ist, was die Angabe von Datentypen angeht. Das sehen wir, wenn wir etwa folgendes versuchen:

public class Typsicherheit {

  public static void main(String[] args) {
    
    int meineZahl;
    meineZahl = 2.5; // Fehler!

  }

}

Wir erhalten eine Fehlermeldung, da eine Dezimalzahl nicht in einer Variablen vom Typ int abgelegt werden darf. Das ist keine unnötige Gängelung von Java, sondern dient dazu, dass wir sehr gewissenhaft programmieren und mögliche Fehler, die sonst erst bei Ausführung des Programms auftreten könnten, schon im Vorfeld vermeiden.

Variablen vom Typ double

Wir haben schon gesehen, dass wir in Variablen vom Typ int keine Dezimalzahlen ablegen können. Für diese können wir Variablen vom Typ double verwenden:

public class VariablenEinfuehrung_03 {

  public static void main(String[] args) {
    
    double meineKommazahl;
    meineKommazahl = 2.5;
    
    meineKommazahl = meineKommazahl * 2;
    
    System.out.println(meineKommazahl); 
    
  }

}

Bei diesem Programm erhalten wir als Ausgabe 5.0 (und nicht einfach 5), so dass wir an der Ausgabe erkennen, dass nicht mit ganzen Zahlen gearbeitet wurde, obwohl das Ergebnis eine glatte Zahl ist.


Hintergundinfo:

Neben dem Datentyp double steht uns auch noch der Typ float für Dezimalzahlen zur Verfügung. Die beiden unterscheiden sich in ihrer Genauigkeit. Bei der Verwendung von float können wir von einer Genauigkeit von etwa sieben Nachkommastellen ausgehen, bei double von etwa 15 Nachkommastellen. Im Abschnitt „Übersicht der primitiven Datentypen“ gehen wir nochmal darauf ein. Wir können uns aber schon merken, dass wir ruhig immer mit double-Werten arbeiten können.


Kommen wir zum Abschluss noch zu einem kleinem Anwendungsbeispiel. Nehmen wir an, wir haben momentan 100,00 € auf unserem Konto. Für Mathenachhilfe bekommen wir von drei Nachhilfeschülern jeweils 12,50 € überwiesen. Anschließend heben wir 20,00 € vom Konto ab. Dann sind am Ende des Monats noch Zinsen fällig, sagen wir 1% – von solchen Zinsen kann man im echten Leben natürlich nur träumen, aber hier geht es ja nur um ein Rechenbeispiel 😉

Diesen Ablauf können wir in Java so simulieren:

public class Konto {

  public static void main(String[] args) {
    
    double meinKonto;
    meinKonto = 100;				// Startguthaben
    
    meinKonto = meinKonto + 3*12.5;	// Nachhilfe

    meinKonto = meinKonto - 20;		// Abheben
    
    meinKonto = meinKonto * 1.01;	// Zinsen
    
    System.out.println(meinKonto);
  }

}

Wir sehen, dass die Variable meinKonto schließlich den Wert 118,675 hat. Natürlich sollte der Wert besser auf zwei Nachkommastellen gerundet werden. Zu solchen Feinheiten werden wir zu einem späteren Zeitpunkt noch kommen.

Vergleichsoperatoren

Haben wir in einer Variablen eine Zahl abgelegt, können wir damit nicht nur rechnen, sondern auch überprüfen, ob sie einen bestimmten Wert hat oder kleiner oder größer ist als ein gegebener Wert:

public class Vergleichsoperatoren_01 {

  public static void main(String[] args) {
  
    int meineZahl;
    meineZahl = 5;
    
    System.out.println(meineZahl == 7); // gleich?
    System.out.println(meineZahl != 7); // ungleich?
    
    System.out.println(meineZahl < 7);  // kleiner?
    System.out.println(meineZahl <= 7); // kleiner oder gleich?
    
    System.out.println(meineZahl > 7);  // groesser?
    System.out.println(meineZahl >= 7); // groesser oder gleich?
        
  }

}

Sehr häufig werden wir das doppelte Gleichheitszeichen verwenden. Mit diesem fragen wir, ob unsere Variable gleich einem bestimmten Wert ist. In diesem Fall erhalten wir an dieser Stelle die Ausgabe false, denn die Variable hat einen anderen Wert.


Tipp:

Bei Einsteigern führt das Verwechseln des einfachen Gleichheitszeichens = und des doppelten Gleichheitszeichens == sehr oft zu einem kleinen und schwer zu findenden Fehler in einem Programm. Das einfache Gleichheitszeichen dient einer Wertzuweisung, das doppelte einem Vergleich. Daher sollten wir immer genau kontrollieren, ob wir das richtige Gleichheitszeichen geschrieben haben!


Statt zu fragen, ob der Wert der Variablen gleich einem bestimmten Wert ist, können wir auch mit != fragen, ob er ungleich ist. Hier erhalten wir im Beispiel die Antwort true.

Generell erhalten wir als Antwort auf einen Vergleich immer einen der beiden Wahrheitswerte true oder false – logisch, die Antwort kann schließlich nur Ja oder Nein lauten!

Die übrigen Vergleichsoperatoren dürften sicher aus dem Matheunterricht bekannt und recht selbsterklärend sein.

Wohl am häufigsten sind solche Vergleiche in Situationen zu finden, in denen abhängig vom Ergebnis des Vergleichs das Programm auf unterschiedlichen Weise fortgesetzt werden soll. Mehr dazu werden wir in der ersten Lektion über Kontrollstrukturen sehen.

Statt eine Variable mit einem festen Wert zu vergleichen, können wir auch zwei Variablen miteinander vergleichen:

public class Vergleichsoperatoren_02 {

  public static void main(String[] args) {
  
    double meineZahl;
    meineZahl = 5;
    
    double deineZahl;
    deineZahl = 10;
    
    System.out.println(meineZahl < deineZahl);
        
  }

}

Hier sehen wir auch, dass nicht nur ganze Zahlen, sondern auch Kommazahlen verglichen werden können. Dabei müssen wir uns aber daran erinnern, dass bei Dezimalzahlen immer Rundungsfehler auftreten können. Hier ein Beispiel dazu:

public class RundungsfehlerBeimVergleich {


  public static void main(String[] args) {
    
    double meineZahl = 10 % 4.8;
    
    System.out.println(meineZahl == 0.4);
    
    System.out.println(10 == 2*4.8 + 0.4);

  }

}

Eigentlich müsste nach dem Initialisieren meineZahl den Wert 0,4 haben. Die Ausgabe liefert wegen eines Rundungsfehlers aber false. Die Kontrollrechnung darunter zeigt nochmal, dass 0,4 aber tatsächlich der richtige Wert sein sollte. Ärgerlich, aber nicht vermeidbar.

Wahrheitswerte

Kurze Einführung in die Logik

Dieses Tutorium richtet sich auch an Neueinsteiger ins Programmieren. Daher sehen wir uns einmal die wichtigsten Grundlagen zur Logik an. Wer damit vertraut, kann dem ersten Teil natürlich überspringen.

In der Logik, wie wir sie hier verwenden, betrachten wir Aussagen. Eine Aussage zeichnet sich dadurch aus, dass sie entweder wahr oder falsch ist. Beispiele sind:

  • Heute ist Montag.
  • Köln ist die Hauptstadt von NRW.
  • Ich habe mehr als 10 € bei mir.
  • Die Sonne scheint.

Aus solchen Aussagen können wir mit verschiedenen Verknüpfungen kompliziertere Aussagen konstruieren. Beispielsweise mit der Verknüpfung UND:

Die Sonne scheint und ich habe mehr als 10 € bei mir.

Ob diese Gesamtaussage wahr ist, hängt davon ab, ob ihre beiden Bausteine – oder wie man auch sagt, die beiden Elementaraussagen – wahr oder falsch sind. Nur, wenn beide Teilaussagen wahr sind, ist auch die gesamte Aussage war.

Eine weitere Verknüpfung ist das ODER. Damit könnten wir dies konstruieren:

Heute ist Montag oder die Sonne scheint.

Diese Aussage ist wahr, sobald mindestens eine der beiden Teilaussagen wahr ist.

Schließlich gibt es auch noch die NEGATION mit dem Wort NICHT. Die fällt etwas aus der Reihe, da hier nur eine Aussage benötigt wird:

Köln ist nicht die Hauptstadt von Düsseldorf.

Diese Aussage ist wahr, da die ursprüngliche Aussage falsch ist. Eine wahre Aussage wird durch Negation hingegen falsch.

Mittels dieser drei Verknüpfungen können wir beliebig komplexe Aussagen konstruieren:

Heute ist nicht Montag und die Sonne scheint oder ich habe mehr als 10 € bei mir.

Um diese Aussage korrekt auszuwerten müssen wir wissen, dass es wie in der Mathematik auch hier Vorfahrtregeln gibt:
(1) Negation geht immer vor.
(2) Dann kommt UND.
(3) Zuletzt kommt ODER.

So ähnlich wie bei der Regel Punkt-vor-Strich gilt also UND-vor-ODER. Die Aussage oben ist wahr, falls einerseits heute nicht Montag ist und die Sonne scheint oder ich andererseits mehr als 10 € bei mir habe (oder falls beides erfüllt ist).

Wir könnten die Aussagenlogik hier noch sehr ausgiebig betrachten, aber diese kurze Einführung soll uns genügen.

Der Datentyp boolean

Wahrheitswerte, also true oder false, können wir in Variablen vom Typ boolean ablegen:

public class Logik {
 
    public static void main(String[] args) {
        
        boolean heuteIstMontag;
        boolean dieSonneScheint;
        boolean mehrAlsZehnEuro;
        
        // Welche Werte gelten heute?
        heuteIstMontag = false;
        dieSonneScheint = true;
        mehrAlsZehnEuro = true;
        
        System.out.println(!heuteIstMontag && dieSonneScheint || mehrAlsZehnEuro);
 
    }
 
}

Hier werden drei solcher Variablen angelegt. Anschließend können wir die heute gültigen Wert eingeben, also zum Beispiel, ob heute Montag ist oder nicht. Schließlich erhalten wir die Auswertung der Aussage, die wir oben schon als Beispiel betrachtet haben.

Wie wir sehen, werden in Java dabei nicht die Wörter UND, ODER und NICHT verwendet. Stattdessen verknüpfen wir die Variablen mit den Symbolen &&, || und !. Diese sind so zu verstehen:

Symbol Bedeutung
&& UND
|| ODER
! NICHT

Betrachten wir noch ein Beispiel:

public class Logik {
 
    public static void main(String[] args) {
        
        boolean dieSonneScheint;
        boolean mehrAlsZehnEuro;
        boolean eisEssen;
        
        dieSonneScheint = true;
        mehrAlsZehnEuro = true;
        
        eisEssen = dieSonneScheint && mehrAlsZehnEuro;
        
        System.out.print("Gehe ich ein Eis essen? ");
        System.out.println(eisEssen);
 
    }
 
}

Hier legen wir zunächst die Werte zweier booleschen Variablen fest und berechnen dann damit den Wert der dritten, die uns mitteilt, ob wir ein Eis essen gehen. Das machen wir in diesem Beispiel genau dann, wenn die Sonne scheint und wir mehr als 10 € bei uns haben.

Vielleicht lesen wir hier zwischen den Zeilen schon heraus, dass solche Wahrheitswerte sehr schön geeignet sind, „Wenn-Dann“-Bedingungen zu formulieren. Genau das werden wir uns in Kürze auch ansehen!

Im Clip wird ebenfalls kurz in die Aussagenlogik eingeführt, allerdings mit anderen Beispielen, damit wir die Gelegenheit haben, mit verschiedenen Erklärungen dieses Thema besser zu verstehen. Anschließend werden ebenfalls boolesche Variablen in Java vorgestellt.

Übersicht über die primitiven Datentypen

Wir haben bereits die Datentypen int, double und boolean kennengelernt. Bei allen dreien handelt es sich um sogenannte primitive Datentypen. Das bedeutet, dass sie zu den Grundbausteinen gehören, aus denen wir später noch komplexere Datentypen konstruieren werden.

Primitive Datentypen für ganze Zahlen

Neben dem Datentyp int gibt es noch weitere Typen zum Speichern von ganzzahligen Werten:

Name Speicher Werte
byte 8 Bit -128 – 127
short 16 Bit -32.768 – 32.767
int 32 Bit -2.147.483.648 – 2.147.483.647
long 64 Bit -263 – 263-1

Die vier Datentypen unterscheiden sich in der Größe des Speicherplatzes, der für sie reserviert wird. Dadurch können sie auch unterschiedlich große Werte speichern. Gerade wenn wir hier aber unsere ersten Schritte in Java gehen, müssen wir uns erst einmal keine allzu großen Gedanken darum machen. Es ist für den Anfang vollkommen in Ordnung, wenn wir einfach konsequent immer auf den Standardtyp int zurückgreifen.

Primitive Datentypen für Gleitkommazahlen

Neben dem Typ double gibt es noch den etwas kleineren Typ float:

Name Speicher Werte
float 32 Bit +/-1,4E-45 bis +/-3,4E+38
double 64 Bit +/-4,9E-324 bis +/-1,7E+308

Der Typ float deckt einerseits einen kleineren Zahlenbereich ab und ist andererseits auch ungenauer, d.h., die Rundungsfehler sind bei ihm größer. Die Faustregel sagt, dass der Typ double auf etwa 15 Stellen hinter dem Komma genau rechnet, der Typ float hingegen nur auf etwa 7 Stellen.

Der Typ double hat sich hier als Standardwahl etabliert, so dass wir einfach auch immer ihn verwenden werden.

Primitiver Datentyp für Wahrheitswerte

Hier gibt es nur den Typ boolean, den wir bereits kennen.

Primitiver Datentyp für Schriftzeichen

In einer Variablen vom Typ char können wir ein einzelnes Schriftzeichen ablegen:

public class DatentypChar {
  
  public static void main(String[] args) {
    
    char meinZeichen = 'x';
    System.out.println(meinZeichen);
    
    meinZeichen = 77;
    System.out.println(meinZeichen);
    
  }	

}

Wir können entweder das Schriftzeichen direkt in einfachen Anführungsstrichen angeben oder seinen Zahlencode gemäß Unicode.


Hintergrundinfo

Unicode ordnet jedem Schriftzeichen einen Zahlenwert zu, durch den das Schriftzeichen gespeichert werden kann. Im Netz findet man zahlreiche Tabellen mit allen darstellbaren Zeichen und deren Codierung. Beispielsweise diese: http://unicode-table.com/de/

Neben den gewöhnlichen Buchstaben, Zahlen und Satzzeichen, findet wir dort auch Befehle wie „neue Zeile“ oder weitere (für uns) exotische Zeichen.


Eine dritte Möglichkeit, ein Schriftzeichen anzugeben, besteht auch darin, die Unicode-Position als Hexadezimalzahl anzugeben:

char meinZeichen = 0x00A9;