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