Programmieren in Java Einführung in die (imperative) Programmierung
Name: Patrick Förster
Programmieren in Java
Wiederholung: Allgemein Hohe Programmiersprache
Compiler
Interpreter
Maschinensprache Zielsystem
Name: Patrick Förster
2
Programmieren in Java
Wiederholung: Java Java Compiler JRE
Bytecode Just-In-Time
Interpreter
Maschinensprache
Name: Patrick Förster
3
Programmieren in Java
Wiederholung (Satzbau) • Programmiersprachen gehorchen einer Grammatik • Nur grammatikalisch richtige Sätze können „compiliert“ werden • Jeder Satz kann in sogenannte „Tokens“ eingeteilt werden • Bezeichner • Literale • Schlüsselwörter • Operatoren • Separatoren • Codeblöcke: • Prolog + beliebige Anzahl Sätze umschlössen von { } • Bilden „semantische Einheit“, definiert durch den Prolog • Syntax des Prologs ist abhängig von der gewünschten Semantik
Name: Patrick Förster
4
Programmieren in Java
Wiederholung (Code-Rahmen) • Java-Code: class Program { public static void main(String[] args){
Programmfluss } }
• Der „class-Block“ muss vorerst hingenommen werden • Der Name der Klasse ist allerdings frei-wählbar • Ebenso hinzunehmen: Der-main-Block
• „Progammierung“ findet (vorerst) in dem blauen Bereich statt • Der Code muss sich in einer Datei befinden, die den Namen der Klasse hat
Name: Patrick Förster
5
Programmieren in Java
Datentypen • Programme basieren immer auf der Manipulation von bestimmten Daten • Daten werden beschrieben durch konkrete Werte • 27: Eine natürliche ganze Zahl größer Null • 'A': Ein Buchstabe • Je nach Wert ändert sich die Semantik eines Satzes/Ausdruckes: 999 + 1 'A' + 'B'
== ? == ?
• Programmiersprachen erwarten das Werte kategorisierbar sind • Ein Datentyp beschreibt eine Menge von Werten der gleichen Art • Der Datentyp legt fest, was als Operation auf seinen Werten erlaubt ist • Nur so kann festgestellt werden, ob ein Satz syntaktisch korrekt ist
Name: Patrick Förster
6
Programmieren in Java
Datentypen (Beispiel in Java) • Im Ausdruck 999 + 1 sind 999 und 1 Werte des Datentyps int • Für int-Werte ist der +Operator die natürliche Addition 999 + 1
== 1000
• In 'A' + 'B' sind A und B Werte des Datentyps char System.out.println('A' + 'B'); 131
• char beschreib alle Unicode-Zeichen • Jedem Zeichen ist ein eindeutiger Code zwischen 0…65.635 zugeteilt 'A' == 65 'B' == 66 65 + 66 == 131
• Für char-Werte ist der +Operator demnach die Addition in [0…65.635]
Name: Patrick Förster
7
Programmieren in Java
Primitive Datentypen • Als „primitiv“ wird ein Datentyp bezeichnet, dessen Werte nicht weiter zerlegt werden können • Datentypen zur Beschreibung numerischer Werte: • byte: {-128...127} (8 Bit) • int: {-2.147.483.648... 2.147.483.647} (32 Bit) • float: {-1,4E-45 ... 3,4E+38} (32 Bit) • … • Häufig auch: • Logischer Datentyp: boolean {true, false} • Datentyp für Zeichen: char [0…65.635] • Datentyp für Zeichenketten: String
Name: Patrick Förster
8
Programmieren in Java
Primitive Datentypen (2) • Achtung:
1. Nicht all diese Typen tauchen zwangsläufig in jeder Sprache auf • boolean wird häufig einfach als {0, 1} betrachtet • Zeichen kann wie gesehen als numerischer Wert dargestellt werden 2. Nicht all diese Typen müssen zwangsläufig „primitiv“ sein • Ein Wert des Datentyps String kann auch als Kette von Werten des Datentyps char verstanden werden 3. In vielen Sprachen können Teilmengen von int als neue primitive Datentypen definiert werden (sogenannte: Enums)
Name: Patrick Förster
9
Programmieren in Java
Primitive Datentypen (Java) • byte: {-128...127} (8 Bit) • short: {- 32768... 32767} (16 Bit) • int: {-2.147.483.648... 2.147.483.647} (32 Bit) • long: {-9223372036854775808... 9223372036854775807} (64 Bit) • float: {-1,4E-45 ... 3,4E+38} (32 Bit) • double: {-4,9E-324 ... -1,7E+308} (64 Bit} • boolean: {true, false} • char: Unicode-Zeichen (16 Bit) • byte, short und int Literale können nicht explizit von einander unterschieden werden • Werte aus dem Bereich long werden mit einem „L“ notiert: 999L • Werte aus dem Bereich float werden mit einem „f“ notiert: 0.5f • Java kennt den Datentyp String, dieser ist allerdings nicht primitiv • Java kennt enums, allerdings sind auch diese nicht primitiv
Name: Patrick Förster
10
Programmieren in Java
Variablen • Wiederholung: Zuweisungs-Operator = Schlüsselwort|Bezeichner
Bezeichner
=
WERT|AUSDRUCK
;
• Nicht zu verwechseln mit ==, dem Vergleichsoperator! • erwartet auf der linken Seite einen Bezeichner, rechtes einen Wert • Schlüsselwort|Bezeicher kann nun genauer definiert werden: DATENTYP
Bezeichner
=
WERT|AUSDRUCK
;
• Der Wert rechts muss vom Datentyp links sein • Bezeichner myNumber wird als Variable des Datentyps int bezeichnet
Name: Patrick Förster
11
Programmieren in Java
Typsystem (statisch) Wenn eine Variable für Werte eines bestimmten Typs deklariert wurde, kann sie im weiteren Programmverlauf keinen Wert eines anderen Typs annehmen • Beispiel: int n1 = 27; n1 = 1000; n1 = "Hello World";
// Ok! // Fehler!
• Nur die Deklaration definiert den Typ • Jede weitere Zuweisung überschreibt den alten Wert • Das Literal 1000 ist vom Typ int, die zweite Zuweisung ist demnach ok • "Hello World" ist vom Typ String, die Zuweisung schlägt also fehl • Ein so geformtes Programm ist in statisch typisierten Programmiersprachen nicht compilierbar
Name: Patrick Förster
12
Programmieren in Java
Typsystem (dynamisch) Jede Variable kann für Werte eines beliebigen Typs eingesetzt werden. Der Typ der Variablen ergibt sich zur Laufzeit aus seiner letzten Zuweisung. • Beispiel: var n1 = 27; n1 = 1000; n1 = "Hello World";
// Ok! // Ok!
• Häufig wird eine Deklaration durch ein Schlüsselwort eingeleitet (var) • Der Zuweisungsoperator benötigt keine Angabe eines Typs • Beispielsprachen: JavaScript, PHP, Phyton • Nachteil solcher Sprachen ist häufig das später Erkennen von Typfehlern: var myVariable = 27; // Variablen-Deklaration … myVariable = "Test"; // Wert –und Typeüberschreibung! … var nonsense = myVariable * 27 + 1; // Was soll Test * 27 sein? (meist: Fehler)
Name: Patrick Förster
13
Programmieren in Java
Wichtig
Java ist statisch typisiert
Name: Patrick Förster
14
Programmieren in Java
Variablen/Deklaration (Java) • Deklaration einer Variablen: • Ohne Initialisierung: DATENTYP
Bezeichner
;
• Mit Initialisierung DATENTYP
Bezeichner
=
WERT|AUSDRUCK
DATENTYP
;
• Zuweisung Bezeichner
=
WERT|AUSDRUCK
DATENTYP
;
• Beispiel: int result; int number1 = 27; int number2 = 37; result = number1 * number2 + 1; System.out.println(result); // 1000
number = 10; int number = "Test"; int number1; int number2 = number1 * 27 + 1;
• Vor der ersten „Nutzung“ der Variablen muss sie einen Wert haben! Name: Patrick Förster
15
Programmieren in Java
Operatorüberladung • Der Typ des Resultates eines Operators ergibt sich entweder • aus seiner Definition int intNumber1 = 27; int intNumber2 = 37; bolean areEqual = intNumber1 == intNumber2; // == liefert unabhängig von den Operanden boolean (also: true oder false)
• oder aus seinen Operanden int intResult; int intNumber1 = 27; int intNumber2 = 37; intResult = intNumber1 * intNumber2; // * liefert int, da beide Operanden vom Typ int
float floatResult; float floatNumber1 = 27.0f; float floatNumber2 = 37.0f; floatResult = number1 * number2; * liefert float, da … vom Typ float
• In letzterem Fall spricht man von Operatorüberladung • Nicht alle Operatoren können auf allen Datentypen angewandt werden boolean nonsenseBooleanValue = false + true; Error: bad operand types for binary operator '+'
Name: Patrick Förster
// Was soll das auch sein?
16
Programmieren in Java
Operator-Überladung II • Mit den Zuweisungen der vorherigen Seite liefert System.out.println(intResult == floatResult) true
• Die Werte von intResult und floatResult sind also gleich • Aber folgende Zuweisung lässt sich nicht compilieren: intResult = floatResult;
• Warum? • Syntax-Regel bei Zuweisung sagt: • Der Wert rechts muss vom Typ der Deklaration sein • Der Compiler sagt: • Error: possible loss of precision • Was passiert wenn die Typen der Operanden ebenfalls verschieden sind? ?
number
=
int
*
float
;
?
number
=
37
*
27f
;
Name: Patrick Förster
17
Programmieren in Java
Coercion (Java) • Trotz des statischen Typsystems verbietet Java nicht alles: int iValue = 37; long lValue = iValue;
float fValue = 37f; double dValue = fValue;
long lValue = 37L; double dValue = lValue;
• Der Compiler merkt selbständig, dass die zweite Zuweisung möglich ist, da der Wert der rechten Seite zu einem Typ auswertet, der Teilmenge des Typs der linken Seite ist • Diese Umwandlung wird „implizite Typanpassung“ bzw. Coercion genannt Typ (Wert)
Mögliche implizite Umwandlung (Variablentyp)
byte
short, int, long, float, double
short
int, long, float, double
char
int, long, float, double
int
long, float, double
long
float, double
float
double
Name: Patrick Förster
18
Programmieren in Java
Cast (Java) • Wie gesehen ist die Rückrichtung in Java (und allgemein meist) nicht erlaubt • Ein Compiler will nicht freiwillig von float zu int umwandeln, denn:
• Die Umwandlung könnte mit einem Genauigkeitsverlust verbunden sein • Was ist 9223372036854775797.0f im int-Wertebereich? • Man kann selbst die Verantwortung übernehmen und den Compiler zwingen (
DATENTYP
)
WERT|AUSDRUCK|BEZEICHNER
long lValue = 37L; int iValue = (int) lValue;
• Diese Art der expliziten Umwandlung wird Cast genannt
• Auch durch einen Cast kann ein Wert seinen Datentyp nicht verlassen! • Ein Cast ist nur anwendbar, wenn die beteiligen Typen kompatible sind! int iValue = (boolean)true;
Name: Patrick Förster
19
Programmieren in Java
Cast/Coersion/Überladung • Was ist hier nun die Lösung? ?
number
=
int
*
float
;
?
number
=
37
*
27f
;
• Bei verschieden Typen wird immer der größeren Wertebereich angenommen 37
*
27f
==
999f
float
• Wird keine explizite Umwandlung durchgeführt, compiliert also nur float
number
=
37
37
*
27.0f
;
• Möchte man int, muss ein Cast erfolgen int
number
=
(
int
)
(
37
*
27.0f
)
• 37*27.0f muss geklammert sein, ansonsten würde der Cast nur 37 angewandt werden!
Name: Patrick Förster
;
20
Programmieren in Java
Scope • Jede Variable hat einen Gültigkeitsbereich , genannt Scope • Nur in diesem Bereich ist die Variable nutzbar • Ein Scope definiert also die Lebensdauer einer Variablen • Erweiterung der Syntaxregel für Deklaration in statisch typisierten Sprachen: Innerhalb eines Scopes kann es keine Deklaration zweier Variablen mit gleichen Namen geben
• Damit ergibt sich allgemein für statisch typisierte Sprachen Wenn eine Variable für Werte eines bestimmten Typs deklariert wurde, kann sie innerhalb ihres Scopes keinen Wert eines anderen Typs annehmen
Name: Patrick Förster
21
Programmieren in Java
Scope (Java) • In Java bilden Codeblöcke Gültigkeitsbereiche PROLOG
{
SATZ; | BLOCK
}
• Zur Erinnerung: Codeblöcke können geschachtelt werden • Die Scope einer Variablen ist der Codeblock in dem sie definiert wurde {
SCOPE I int number = 27; {
SCOPE II int secondNumber = number * number ; float number = 37f;
// Error!
} float secondNumber = 3.14159265359f;
// Ok!
}
• number: Scope I inkludiert Scope II und demnach kann number in Scope II nicht überschrieben werden • secondNumber: Scope II ist der Gültigkeitsbereich von secondNumber und dieser endet noch vor der Neudefinition von secondNumber als float Name: Patrick Förster
22
Programmieren in Java
Variablen und jetzt? • Wozu Variablen? • In der Regel sind die Daten auf denen gearbeitet wird unbekannt • Variablen dienen zur Abstraktion von eben diesen unbekannten • Mit dem Typ einer Variablen werden allerdings bereits zur Compilezeit Annahmen über die Form der Daten getroffen • Damit werden die möglichen Operationen auf den Daten festgelegt • Was ist bis hierhin möglich: • Variablen deklarieren und Werte zuweisen • „Berechnungen“ auf Basis der Java-Operatoren • Ausgabe von Daten
Name: Patrick Förster
23
Programmieren in Java
Wichtig Für das Verständnis: Solange noch keine Möglichkeit bekannt ist beliebige Daten zu verarbeiten (bspw. durch Eingabe) stehen konstante Wertzuweisungen als Beispieldaten. int number = 27;
int square = number * number ; System.out.println(square);
Beispieldaten Programm
• Obiges ist natürlich relativ sinnfreier Code • Das Quadrat muss nicht durch das Programm berechnet werden, wenn die Werte vorher klar sind! • Aktuell werden aber noch „hardkodierte“ Werte benötigt, um „was zu sehen“
Name: Patrick Förster
24
Programmieren in Java
Verzwickte Lage • Bisher kennt ein Programm nur eine Richtung • Wie würde man folgende Problemstellung programmieren: int falls number gerade
System.out.println("gerade");
number
=
? falls number ungerade
System.out.println("gerade");
• Es gibt aktuell keine Möglichkeit den Programmverlauf zu verzweigen • Ohne Verzweigung lässt sich obiges Problem allerdings nicht lösen Es wird ein Konstrukt benötigt, um den Verlauf von einer Bedingung abhängig zu machen
Name: Patrick Förster
25
Programmieren in Java
Bedinge Anweisung • Die if-else-Anweisung: if
BEDINGUNG
(
)
{
int number = ?; if (number % 2 == 0) {
SATZ; | BLOCK
} else
System.out.println("Gerade"); } else {
{
System.out.println("Ungerade");
SATZ; | BLOCK }
}
BEDINGUNG
==
WERT | VARIABLE | AUSDRUCK
boolean
• Syntax: • Die Bedingung muss geklammert werden • Der else-Teil ist optional • Beinhaltet der Code-Teil (if oder else) nur einen Satz so können auch die geschweiften Klammern weggelassen werden
Name: Patrick Förster
26
Programmieren in Java
Boolesche Operatoren • Im Beispiel wird Vergleichsoperator (==) verwendet: • true falls linker und rechter Operant übereinstimmen, ansonsten false • Weiter wichtige boolesche Operatoren inkl. Wahrheitstabelle: &
true
false
true
true
false
false
false
false
Und
|
true
false
true
true
true
false
true
false
Oder
^
true
false
true
false
true
true
false
false
true
false
false
true
Ausschließendes Oder(xor)
!
Negation
• Für & bzw. | bietet Java die Möglichkeit der Kurzschluss-Semantik an: • Wenn der erste Operant für oder true bzw. für und false liefert, muss der zweite nicht mehr ausgewertet werden • Kurzschluss-Semantik wird mit doppelten oder/und (&&/||) notiert if (number % 2 == 0 && number > 100) …
• In der Regel sind die Kurzschluss-Operatoren vorzuziehen Name: Patrick Förster
27
Programmieren in Java
Aufgaben • Was liefert ein Cast von float zu int? float floatNumber = ?; int intNumber = (float) floatNumber; System.out.println(floatNumber);
• Schreiben Sie ein Programm, dass zu einer beliebigen Zahl number vom Typ float die größte ganze Zahl (int) kleiner gleich number ausgibt. float number = ?; int intValue; … System.out.println(intValue);
• Schreiben Sie ein Programm das zwei beliebige Zahle dividiert, aber zuvor überprüft, dass der Divisor nicht gleich 0 ist und in diesem Fall "Division durch 0" ausgibt float dividet = ?; float divisor = ?; …
Name: Patrick Förster
28