Ja, kann ich mir vorstellen. Aber jetzt sitzen wir ja alle hier.
Jetzt nutzen wir die Gelegenheit und machen ein bisschen Informatik.
Ich will nochmal eben ein paar Worte sagen zu SA1.
Am Wochenende war das Erstsemesterwochenende. Da waren die Lehrerinnen des
ersten Semesters eingeladen unter anderem und haben dann so ein bisschen
das Feedback bekommen von den Studierenden von euch.
Und SA1 hat sehr gute Kritiken gekriegt.
Und das ist immer wieder sehr erfreulich zu hören.
Aber bitte?
Ja, beschummelt
Genau, also die einzige Kritik, die wirklich ernsthaft rüberkam,
war am Wochenende, dass ich beim TikTac-Tor geschummelt hätte.
Was jetzt eine glatte Unterstellung ist, aber ansonsten war das Feedback eben halt sehr positiv.
Und das liegt eben halt nicht nur an mir,
ich stehe hier vorne immer so, ich bin derjenige,
die alle sehen und alle denken, Mensch,
der Spolizki, der macht das gut,
aber das ist natürlich alles überhaupt nicht möglich,
ohne das, was alles drumherum passiert.
Und das sind eben halt sehr, sehr viele Personen,
die da beteiligt sind. Inzwischen sind das über 1000 Teilnehmer
an dieser Veranstaltung gewesen in den letzten, ich glaube,
das ist das siebte Jahr jetzt oder das sechste Jahr
Das heißt also, da ist schon ganz viel Feedback
auch von den Teilnehmern in diese Veranstaltung rangeflossen.
Ohne das geht es auch nicht. Wir machen keine Veranstaltungen,
die über die Köpfe der Teilnehmer hinweg geht.
Wir haben aber auch eine ganze Menge Betreuer. Ihr habt das schon mitbekommen,
stilenische Betreuer, aber auch wissenschaftliche Mitarbeiter von anderen Arbeitsbereichen oder auch von unserem Arbeitsbereich.
Das dürfte inzwischen auch schon in die dreistelligen Dimensionen gehen,
also denke ich mal so über 100 Personen waren da bisher schon beteiligt.
Und natürlich dann Kolleginnen und Kollegen, auch ehemalige im Arbeitsbereich bei uns,
SWT, allen voran Christian Spät,
den nehmt ihr wahrscheinlich alle so kaum wahr, aber der sorgt sehr dafür,
dass im Hintergrund und alles richtig und gut läuft.
Leider ist er gerade krank. Gute Besserung von dieser Stelle. Ja,
dann gibt es natürlich auch noch Heinz Zülichhof,
den ihr bisher noch nicht gesehen habt,
aber nehmen wir auch ein bisschen verdanken,
dass diese Veranstaltung so sein kann, wie sie ist,
weil eben halt auch diese Grundidee der Veranstaltung sehr stark unterstützt und auch dafür gekämpft hat,
dass SE1 und SE2 so im Curriculum verankert sind,
wie sie es momentan sind.
Das ist also alles nicht so ganz ohne und das ist
dann so ein Moment, wo man dann merkt,
nee, jetzt nicht austauschen, oder?
Jetzt nicht austauschen, oder?
Jetzt nicht. In der Pause. Okay, jetzt bitte nicht
. Ich möchte jetzt nicht nochmal irgendwie neu anfangen hier.
Gut. Also, man sieht hier, das funktioniert auch beidseitig.
Man muss also von allen Seiten, muss da irgendwie was beigetragen werden.
Das heißt, das ist mal wieder ein Musterbeispiel dafür,
dass so etwas nicht wie in der Informatik ist mit Klient
und Dienstleister und ich nehme Dienstleistungen in Anspruch.
Also hier, mach mich glücklich, sondern da müssen halt
immer beide dran arbeiten, beide Seiten. Von daher,
das einfach mal an dieser Stelle auch meine Anmerkung,
dass ich da nicht alleine stehe.
Okay, heute geht es um strukturierte Programmierung. Wir werden
in der ersten Hälfte heute uns intensiv mit bedingten Anweisungen beschäftigen,
also mit, eigentlich mit Auswahlanweisungen, If on Switch in Dava.
Und so ein bisschen noch Grundlagen zur strukturierten Programmierung machen.
Und in der zweiten Hälfte werden wir uns schleifen ansehen,
Schleifmechanismen, Schleifenkonzepte und ein bisschen noch auf die Begriffe Laufzeit und Übersetzungszeit eingehen.
Und da schauen wir mal, wie die Zeit heute reicht.
Sonst machen wir das notfalls beim nächsten Mal. Okay,
was ihr bisher schon mehrfach von mir gehört habt,
ist, dass man immer, wenn man iperativ programmiert,
eine Idee haben muss von einem Kontrollfluss.
Das heißt also, irgendwo ist gerade die Ausführung.
Irgendwo gibt es immer einen Punkt, in dem gerade das
Programm ausgeführt wird. Es gibt wie so einen roten Faden,
der sich durch den Quelltext zieht, der festlegt, was gerade ausgeführt wird.
Das kann immer anders sein, je nach dynamischer Ausführung,
je nach Eingaben, die verarbeitet werden.
Und das ist eben halt auf verschiedenen Ebenen auch tatsächlich wichtig,
das zu verstehen. Zwischen den Anweisungen kennt ihr das,
das heißt, in einer Methode,
die Anweisungen im Rumpf werden von oben nach unten ausgeführt,
also sequenziell in der Reihenfolge, wie sie auch im Quelltext stehen.
Das ist das, was allgemein bekannt ist. Zwischen den Methoden haben wir es auch schon kennengelernt,
so was wie Methodenaufrufe, die dafür sorgen,
dass der kontrollflos woanders hinspricht und eine andere Methode,
da den Rumpf ausführt, dann wieder zurückspringt an die Stelle,
wo die Methode aufgerufen wurde und so weiter.
Aber auch innerhalb einer Anweisung, das haben wir vor zwei Wochen gesehen,
dass es innerhalb eines Ausdrucks tatsächlich ja auch eine Reihenfolge gibt,
in der die Teilausdrücke ausgewertet werden.
Und das heißt also, man kann sich wirklich das so vorstellen,
dass da so dieser Kontrollfluss durch diese einzelnen Anweisungen durchfließt.
Okay, und dann nochmal die Erinnerung,
wir betrachten halt hier keine nebenläufigen Programme,
also keine Parallelprogramme
Prozesse, sondern immer ein Prozess ist aktiv und führt ein Programm aus.
Das ist unser Verständnis. Das eines der bekanntesten Darstellungsmittel für Kontrollfluss
sind Flussdiagramme. Die gibt es schon ziemlich lange und die müsst
ihr auch nicht jetzt lernen. Das ist sozusagen nur,
dass ihr das mal gesehen habt,
dass es dieses Konzept schon sehr lange gibt,
nämlich für die Imperative Programmierung, sowas wie eine Anweisung,
sowas wie Drucke X aus, hier oben angedeutet,
ist so ein eckiger Kasten.
Einfach so eine Anweisung,
eineckiger Kasten in so einem Plusdiagramm und es gibt immer so
einen Pfeil rein und einen Pfeil raus
Das heißt also, hier kommt der Kontrollfluss rein und dann
geht der Kontrollfluss da auch wieder raus.
Und diese Dinge haben immer nur einen Eingang und einen Ausgang.
Also wenn man dann sowas hat wie die Sequenz hier,
aufeinanderfolgende Anweisungen, Anweisungen, A und Anweisungen, B mit einem Silikoland getrennt,
dann ist das eben halt hier tatsächlich der Kontrollfluss fließt durch diese Anweisung durch.
Soweit so anschaulich, sehr einfach. Das habt ihr auch
schon gesehen, sowas wie bedingte Anweisungen,
sehen wir uns heute noch ein bisschen genauer an.
Hier einfach ohne einen ALs, hier mit einem ALs,
was wir uns heute auch ansehen werden, sind Schleifen.
Also sowas wie Wild X DuA,
also solange X gilt,
führe A aus
Und auch da ist es wieder so,
wir haben wieder so eine Idee von einem Kontrollfluss,
also es fließt hier oben rein,
dann wird so eine Raute hier angelaufen.
Wenn die, die enthält üblicherweise eine Bedingung,
wenn die Bedingung true ist, dann wird hier in den unteren Zweig gelaufen.
Das muss auch immer dran geschrieben werden,
ob das der Jahre, der Nein-Fall ist.
Dann wird hier ausgeführt, dann geht das hier wieder hoch.
Da sieht man jetzt sehr schön, dass das eine Schleife ist.
Deswegen auch dieser umgangssprachliche Begriff Schleifen für Wiederholung. Das kann jetzt
hier mehrfach geschleift werden und irgendwann ist die Bedingung dann doch
nicht mehr zutreffend und dann geht es hier raus und so weiter.
Das ist erstmal so einfach um diese Begriffe Kontrollfluss und
dann auch diese Flussdiagramme so ein bisschen zusammenzubringen
Weil diese Kästchen und Pfeile und so weiter,
die Computer-Terminals der 60er Jahre deutlich überfordert haben.
Also es hat ziemlich lange gedauert, bis wir so grandiose Displays hatten,
mit denen wir so beliebig viel zeichnen können.
Lange Zeit waren die Terminals ja reine Text-Terminals und dann hat man eben halt sich einfachere Diagrammarten überlegt,
die das Gleiche leisten, nämlich Strukturgramme,
die aber ein bisschen leichter zu zeichnen sind mit den Mitteln der damaligen Computertechnik,
wo man dann so mit Aski-Kunst irgendwie so Dinge zeichnen konnte.
Und hier dann bieten wir das Gleiche,
also eine einzelne Anweisung, dann die Sequenz,
da werden diese Kästen einfach einander geploppt.
Auch da wieder, hier geht es rein,
da geht es raus
Dann die sichere Nein, Verzweigung. Da gibt es dann
irgendwie entweder einen AMB oder einfach nur das A.
Und das so lange ist hier so angedeutet,
hier irgendwie so eine Schleifensteuerung und hier dann der Rumpf, der ausgeführt werden soll.
Und an diesem Diagramm werden wir uns auch gleich orientieren,
wenn wir uns ein bisschen die Schleifen veranschaulichen.
Okay. Aber erstmal nochmal so ein bisschen Hintergrund. Diese Kontrollstrukturen,
also diese Strukturen in Programmiersprachen, um den Kontrollfluss irgendwie zu steuern,
die gibt es schon ziemlich lange in Programmiersprachen.
Wie gesagt, seit den 50er Jahren gibt es ja schon schicke Programmiersprachen. Und dann haben zwei Forscher es geschafft,
1966 nachzuweisen, dass man tatsächlich alle Algorithmen,
die man in Flussdiagrammen ausdrücken kann, ihr habt ja gesehen,
Flusstdiagramme so mit If und Wirel und so,
kann man alles Mögliche darstellen,
dass das D-Diagramme sind und dass man also tatsächlich jeden Algorithmus,
der so darstellbar ist, auch durch die,
die Renne abbilden könnte.
Und das ist hier die Definition von D-Diagramm,
das ist von einem Herrn Dixtra, zu dem sage ich gleich noch was.
Das ist wieder das gleiche Prinzip. Eine einfache Aktion ist eine D-Diagramm,
sind A und B-Diagramm sind auch A, Semikolon B,
also die Sequenz und dann IfLs und so weiter.
Weil D-Diagramme und nichts sonst
ist ein D-Diagramm
So, und die haben damit gezeigt, dass man,
dass zumindest diese D-Diagramme genauso mächtig sind wie Flussdiagramme.
Es ist die Frage, kann man mit Flussdiagrammen
denn alles programmieren, was man so programmieren will?
Und da waren viele lange Zeit nicht der Meinung.
Da hat man gesagt, wir brauchen ja immer noch das Go-To,
weil in den frühen Programmiersprachen und auch in heutigen Programmiersprachen steckt stellenweise noch eine Go-To-Anweisung drin.
Die werdet ihr hier bei uns nicht kennenlernen, weil es
in Java kein Go-To gibt. Es gibt zwar ein reserviertes Wort,
Go-To, und wenn ihr eine lokale Variable Go-To nennen wollt,
dann wird der Compiler meckern und sagen,
das Wort ist reserviert, aber Die Anweisung bewirkt nichts.
Also wenn das Go-To irgendwie benutzen will,
es gibt einfach keine Go-To-Anweisung in Java. Das ist interessant,
weil einige vielleicht schon mal mit einem Taschenrechner programmiert haben,
mit Basic und dann sagen, Mensch,
da gab es ein Go-To, das war klasse.
Tatsächlich ist es so, dass man das Go-To einfach schlicht
nicht braucht für mehr oder weniger alle Programmieraufgaben, die es so gibt.
Der gute Herr Deixtra, der hat in den 60er Jahren,
1968 einen Brief geschrieben, einen Leserbrief war das, Go-To-Statement,
Constellant Hample, das ist so einer der klassischen Artikel in der Informatik.
Also jeder Informatiker sollte den mal gehört, gelesen haben,
das sind nur zwei Seiten,
das lohnt sich wirklich,
die die mal anzuziehen
Zu gucken. Da hat er einfach gesagt,
The Go-To-Statement, as it stance is just to primitive.
It's too much in invitation to make it mass or once program.
Man kann sich also damit beliebig ins Knie schießen.
Und er hat halt gesagt, schmeißt das Go-To raus.
Und dann ging es heiß los. Dann haben wir so
zehn Jahre lang, glaube ich, zehn Jahre lang ungelogen,
gab es immer wieder Leserbriefe als Reaktionen auf seinen Leserbrief.
Das kann wie sein, dafür braucht man das Go-To
und dafür braucht man das Go-To und dafür.
Und das war sehr erhitzt. Hat sich aber inzwischen gelegt
, ist ja auch schon lange her.
Und inzwischen weiß man einfach, man braucht das Go-To nicht.
Java hat es nicht drin. Andere sprachen schon.
Und der gute Diaxtra hat das eben halt auch nochmal so
ein bisschen hier klarer ausgedrückt, NRB Came Convince at the Go-to-Statement,
should be abologed from all higher level programming languages.
Das war damals Visionär und heutzutage ist es eigentlich,
sagen wir, anerkanntes Verständnis. Das heißt,
der gute Herr Deikstra hat die Informatik sehr stark geprägt.
Er ist einer der wenigen großen Informatiker,
die nicht mehr leben, weil die meisten leben noch.
Die meisten, die die Informatik geprägt haben, leben noch.
Das ist ja eine Gegenwartsdisziplin. Aber der gute Diikstra ist
schon 20002 gestorben und er hat viele wichtige Dinge gesagt,
viele wichtige Dinge auch getan.
Allerdings ist er auch kein ganz unnötiger, problematischer Mensch gewesen.
Also er war auch sehr, sagen wir sehr unerbittlich mit Denkfehlern von anderen.
Er war sehr unerbittlich, was den Umgang mit Mathematik anging.
Er fand also die Mathematik extrem wichtig. Er meinte eigentlich,
dass die Informatik nichts weiter ist als eine Verlängerung der Informatik.
Und ein ganz berühmter Satz von ihm ist Program Pesting,
Can at best show the presence of errors, but never they app since.
Das heißt also, man kann, wir testen zwar Fehler nachweisen,
aber man kann nie nachweisen, dass keine Fehler drin sind.
Das geht mit Testen nicht. Und deswegen hat er eben halt sehr dafür gekämpft,
dass man Programmbeweise führt, also seine Programme versucht zu verifizieren.
Sehr mathematisch, wie gesagt. Und ich denke,
da sind wir heute, sagen wir mal, einen Ticken weiter,
dass wir akzeptieren, dass wir nicht alles beweisen können.
Also es ist schon relativ schwierig, es ist
so interaktive Anwendungen mit beliebigen Einflussfaktoren nicht gut beweisen können.
Aber er, wie gesagt, hat eine Menge gemacht,
auch Betriebssysteme geschrieben und ähnliches. Also ein ganz großer. Gut,
also was wir jetzt von ihm geerbt haben, juhu,
worum geht es uns jetzt hier überhaupt, um strukturierte Programmierung?
Also, was ist strukturierte Programmierung? Besteht aus genau diesen
drei elementaren Einheiten, Sequenz, Auswahl, Wiederholung?
Sequenz habt ihr gesehen, Auswahl,
habt ihr auch gesehen mit dem IF,
Wiederholung sehen wir uns noch an
Das kann man tatsächlich so sehen, wie hier auf dem Bild angedeutet.
Das ist so quasi die Doppel-Helix der imperativen Programmierung.
Also als Grundlage für alles, was wir in imperativen Anweisungen tun
, in unseren objektorientierten Systemen. Ist das wirklich so,
wir haben diese drei Elemente und mit denen können wir mehr oder weniger alles bauen.
Das ist also ganz gut zu wissen. Natürlich gibt es noch
ein paar Sachen mehr, nämlich Prozeduren in der imperativen Programmierung,
deswegen habe ich hier das Männchen nochmal rangemacht,
der ist imperative Männchen.
Also Prozeduren ist ein imperativer Begriff, wir nennen die ja Methoden in der Objektorientierung.
Hundabstrakte Datentypen, die nennen wir eigentlich Klassen.
Aber das ist sozusagen das, was man dazu sagen kann.
Zur Strukturiertenformierung. Ich muss ein bisschen aufpassen,
ich habe das Mikro an meinem Bart,
das raschelt dann immer mal
so ein bisschen
So sind das hier. Funktioniert. Gut. Bevor wir
jetzt einsteigen in IF und alles, was damit zusammenhängt,
muss ich noch zwei kleine Begriffe einführen.
Die sind relativ schnell eingeführt. Das eine ist, es gibt
so was wie zusammengesetzte Anweisungen. Das heißt einfach nur,
dass ich mehrere Anweisungen zu einer logischen Einheit zusammenfasse.
So einfach so eine Schleife drum mache und sage,
so, die betrachte ich jetzt mal als eine.
Also hier irgendwie Statement 1 für Statement N,
dann klammere ich das mit einem Beginn End und schon
kann ich dieses Ding insgesamt als eine zusammengefasste Anweisung ansehen.
Also als eine einzelne Anweisung. Das ist sehr nützlich,
wenn man so gerade Schleifen baut und auch Bedingungen,
das werdet ihr dann auch noch mal sehen.
Blöcke sind das Gleiche wie zusammengesetzte Anweisungen. Nur sind Blöcke noch mal angereichert,
um die Möglichkeit, lokale Variablen zu deklarieren. Das heißt,
ich kann sowas machen,
ich habe hier zwei Variablen A und B,
die haben irgendwelche Belegungen, dann kann ich die beiden vergleichen,
dann wird hier ein Block geöffnet,
in Java wird ja durch diese geschweiften Klammern ein neuer Block aufgemacht.
In diesem Block ist eine neue Variable deklariert, Tamp vom Typ
In und die ist nur innerhalb dieses Blocks definiert und kann
auch hier nur benutzt werden.
Wir werden heute noch mal über Sichtbarkeit und Lebensdauer
reden und das sind Beginne für die dann genau damit reinspielen
in solche Block strukturierten Sprachen
Gut, also auch Java ist blogstrukturiert, wobei man ein bisschen aufpassen muss,
man kann jetzt in Java zum Beispiel keine Prozedur, keine Methoden ineinander schachteln,
was man zum Beispiel in Pascal kann, das geht in Java nicht. Okay,
dann sind wir schon bei nochmal ein bisschen Syntax,
hier unten, Level 1 Syntax, also Blog, geschweifte Klammern,
dann hier die roten Meta-Symbole heißen, ja, beliebig oft,
also beliebig viele Blogstatements und ein Blogstatement kann ein Java Level 1 sein,
ein Local Variable Declaration Statement, also eine lokale Variable,
die ich deklariere oder ein Statement,
da sieht man auch wieder an der syntaktischen Struktur,
spiegelt sich wieder,
was die Dinger so auskönnen,
was die Dinger so ausmacht und können
Gut. Jetzt die IF-Anweisung. Jetzt war ja schon wiederholt,
habt ihr ja in den Übungen mit IFs arbeiten müssen.
Und ich hoffe, das hat euch nicht zu sehr gestresst,
dass ihr das machen musstet.
Wir haben im Sinne immer davon aussehen,
dass man so ungefähr weiß, was das mal bedeutet,
wenn die Bedingungen zutrifft, dann führt das aus.
Jetzt wird es ein bisschen ausführlicher endlich in der Vorlesung erklärt,
aber auch nicht zu ausführlich.
Wir wollen ja nicht zu lange darauf rumreiten. Ich bin
nur so ein paar Dinge dazu anmerken. Also zum einen
die Syntax. Hier sieht man es einfach mal IF,
dann die runden Klammer, die müssen immer dastehen.
Also wundert euch nicht, wenn der Kompalla meckert,
wenn ihr die mal vergesst.
Wenn die Bedingungen zutrifft, diese Bedingungen,
diese Expression hier muss
den Tybulien haben
Ich kann also nicht steuern, E5. Ja, das geht nicht.
Ich muss schreiben, ihr fünf größeren Null oder ähnliches.
Also es muss ein Bulshar-Ausdruck sein. Das kann man
auch zur Übersetzungszeit prüfen. Der Compiler kann das prüfen.
Dann wird das Statement ausgeführt und ansonsten ein anderes Statement.
Man sieht hier ein einzelnes Statement und ihr wisst,
ein Statement kann auch ein Blog sein,
wo dann wieder mehrere Statements drin sind.
Deswegen diese Idee, mit dem Zusammensetzten eine Anweisung.
Okay, jetzt sieht man hier mal so ein kleines Beispiel.
If A, Klana B, dann min gleich A,
Elsman, gleich B. Das ist,
möglicherweise stößt das einige von euch schon so ein bisschen auf,
weil das so ein bisschen komisch aussieht,
weil hier die geschweiften Klammern fehlen
Das ist auch tatsächlich etwas, was ich euch mal an
einem BlueJ-Beispiel zeigen will. Ich habe da mal was vorbereitet.
Und zwar haben wir hier eine sehr einfache, klasse Textanalyse.
Das ist auch mehr oder weniger so die Klasse,
die ja auch in den Übungen wahrscheinlich mal etwas näher sehen werdet.
Ganz viel Text, ganz einfach nur eine Methode,
also diese Klasse, Textanalyse, hat erstmal keinen Zustand bisher.
Keine Exemplarvariablen. Das heißt, ein Exemplar dieser Klasse ist
zustandslos. Hat eine Methode, die heißt Ist Frage,
bekommt einen formalen Parameter vom Tipp String und liefert,
ob dieser String eine Frage ist.
Relativ einfach implementiert. Wenn das letzte Zeichen in der Zeichenkette,
in dem String meint, Fragezeichen ist, dann ist es eine Frage.
Ansonsten eben nicht. Das ist ja auch ganz einfache Implemente.
Wir haben es hier sehr ausführlich gemacht. In den Übungen seht ihr dann nochmal,
wie man das auch sehr viel kürzer schreiben kann,
aber es ist einfach nochmal gut, sich nochmal explizit klarzumachen,
was da alles passiert.
Also man kann anscheinend von so einem String die Länge abfragen.
Wie viele Zeichen enthält er? Das kann ich in einer
länger variablen, speichernden Länge. Dann kann ich sagen,
die letzte Position in einer Zeichenkette ist Länge minus eins.
Das ist ein Zusammenhang, den wir uns
auch nächste Woche ausführlich ansehen werden
Dann ist das letzte Zeichen, Text, Char-Ed,
anscheinend kann ich mit Char-Ed auf das Zeichen an einer bestimmten Position zugreifen,
also letzte Position, ist das letzte Zeichen.
So, dann vergleiche ich das letzte Zeichen mit einem Fragezeichen.
Und wenn die gleich sind, dann endet das auf dem Fragezeichen
sonst eben nicht. Eine bulsche Variable und am Ende schreibt,
schmeiße ich dann diese bulsche Variable als Ergebnis raus.
Sehr schön, sehr schön, sehr schön.
Das funktioniert auch, ich kann es also mal zeigen,
wir machen mal hier ein Exemplar.
Und dann ist Frage, hier sowas wie Hallo
Hallo, dann sagte er hoffentlich, False, ja,
das ist wunderbar, jetzt sage ich hier nochmal,
ist Frage, jetzt sage ich hier mal, hallo.
Und jetzt kommt ein Schuh raus, welche Überraschung?
Also ist das, das wird bei diesem Programm schiefgehen.
Ja, weil wir dann auf einen Index zugreifen,
der dann minus eins ist, die Länge der Zeichenkette ist null,
wenn der leeres Trink übergeben wird.
Und wenn man dann auf minus eins zugreift,
gibt es einen Indexfehler beim Stream.
Wird also nicht funktionieren, das heißt,
dieses Programm ist sehr einfach,
nicht sehr gut für Sonderfälle gebaut
Okay, jetzt nehmen wir mal an,
wir würden jetzt gerne hier in unserem Analysierer.
Der soll jetzt so Analyse-Daten sammeln. Der momentan bietet ja nur diese Dienstleistung an,
du kannst diese Methode aufrufen und eine Zeichenkette übergeben.
Jetzt sage ich mal, ich möchte gerne hier eine Exemplarvariable
deklarieren vom Typ Int und die soll einfach nur die Frage, die Fragen zählen.
Private Int-Fragezähler. Das heißt, wir haben jetzt eine Exemplarvariable,
wenn wir ein Exemplar dieser Klasse erzeugen, hat die ein Feld,
ein Int um dann dieses Ding halten zu können.
Normalerweise müsste ich jetzt einen Konstruktur schreiben,
um das Ding zu initialisieren, das wisst ihr,
das machen wir jetzt gerade mal nicht wegen der Kürze der Zeit.
Das heißt, wenn wir ein Exemplar erzeugen,
dann ist dieser Fragezähler zu Anfang null.
So, und jetzt möchte ich an dieser Stelle hier,
wenn das auf dem Fragezeichen endet, dann mache ich hier mal Folgendes.
Moment. Jetzt mache ich hier mal Folgendes,
jetzt kopiere ich mal das Zeug hier rüber
Ja, das war jetzt vielleicht nicht ganz so schlau,
aber egal, so, dann, es ist alles nicht so geschickt,
was ich hier gerade mache, stelle ich gerade fest,
egal, ich mache es mal so, so,
so, endet, nee,
endet auf Fragezeichen,
gleich True
So, und hier sagen wir, endet oft Lagerzeigen des gleichen Fals.
Also ich nehme einfach mal an, meine lokale Variable initialisiere ich mit Fals.
Wir gehen davon aus, das ist keine Frage.
Nur wenn das letzte Zeichen hier ein Fragezeichen ist, dann machen wir das so.
Okay, und dann machen wir hier das Return und wunderbar.
Und was ich jetzt noch machen will,
ich möchte jetzt außerdem, wenn wir eine Frage gezählt haben,
dann möchte ich zusätzlich, dass mein Fragezähler erhöht wird.
Ich möchte einfach mitzählen, dass es ja eine Frage aufgetreuen ist.
Also sage ich hier irgendwie Fragezähler plus plus
Plus plus Fragezähler. Also hier, so. Also wenn das
eine Frage ist, dann soll der Fragezähler erhöht werden.
Das übersetze ich jetzt mal. Und das lässt sich
nicht übersetzen, weil das kein Fragezähler ist.
So, jetzt ist es der Fragezähler.
Danke für den Hinweis. Ja, Moment, Moment,
Moment, ich will doch gerade was zeigen hier.
Könnt ihr mich mal in Ruhe lassen? So,
jetzt zeige ich euch hier, jetzt habe ich ja hier
meinen Buschen, der das irgendwie zählt.
Und wenn ich jetzt das Ding aufrufe,
dann teste ich das mal eben
ganz kurz mit einer Frage.
Und schwuppdiwupp, siehe da, der Fragezähler ist um eins erhöht worden.
Das sieht hier richtig gut aus. Toll, macht
genau das, was ich will. Wir testen es nochmal
mit dem anderen Fall, wenn es keine Frage ist.
Hier, zack, erhöhen und er liefert Fords.
Toll. Hups. Ah, okay. Aber er hat
auch diesen Täler erhöht. Das heißt,
das hier ist nicht das, was wir wollen.
Und es ist natürlich schon fast zu offensichtlich, unter anderem deshalb auch,
weil Bluejay ja inzwischen die Blöcke so gut markiert.
Man sieht hier dieses blaue Ding, das zeigt,
das ist die Anweisung, die ausgeführt wird, wenn das If zutrifft.
Und das ist genau eine Anweisung. Und was ich hier gemacht habe,
ist, ich habe einfach durch Einrückung geglaubt,
dass das dann auch bei dem If passiert.
Ein gern gemachter Fehler. Das ist jetzt nichts,
was ich mir ausgedacht habe, sondern das haben wir immer wieder erlebt.
Und deswegen ist es eigentlich, mir eben schon fast ungeduldig zugerufen worden,
Mensch, mach doch da Klammern hin, dann passt das auch. So,
das heißt also, was wir hier in der Situation haben,
ist, ich habe eine Anweisung,
und obwohl ich am Anfang dann nur eine Anweisung stehen hatte,
hätte ich trotzdem schon die Klammern hinschreiben sollen,
weil wenn ich dann eine weitere Anweisung hinter zuschreiben will,
dann kann ich den einfach dazuschreiben.
Ich muss nicht erst irgendwie jetzt anfangen, mit Klammern einzurücken,
was weiß ich weiß, die stehen ja immer schon da.
Das ist also egal, ob da eine Anweisung steht oder viele,
Macht es bitte immer so, das ist sehr viel robuster.
Das ist auch ein weiteres Beispiel hier auf dieser Folie.
Das ist auch nochmal ganz interessant. Wenn ihr euch mal diesen Quelltext anseht,
ja, If-Summen gleich, gleich, null,
If-Count like, gleich, nur Result, gleich,
eins, ESP seid gleich, null.
Jetzt frage ich euch mal, wir nehmen an,
die Belegung sieht so aus, vorher.
Summen ist null, Count ist eins, Result ist zwei.
Was kommt dann da raus? Wer hat mal
einen Vorschlag? Ja. Du sagst zwei. Okay.
Wer sagt was anderes
Wer sagt was anderes? Ihr sagt alle,
das kommt durch Result gleich zwei raus.
Anderer Vorschlag ist null. Es ist ja schon interessant,
dass jetzt hier eine ganze Menge schlaue Informatikstudierende sitzen und nicht
so richtig wissen, was da jetzt die richtige Antwort ist.
Das liegt natürlich daran, dass das Ding hier ein bisschen
komisch eingerückt ist. Wenn man das jetzt so einrückt,
dann wird das vielleicht schon klarer,
was da an Ergebnis rauskommt
Also, wenn es so mit Null ist,
wird dieser Zweig hier ausgeführt,
dann wird geprüft Opcount gleich null, das gilt nicht,
also wird das Els hier bezieht sich auf dieses If und dann wird Result auf Null gesetzt,
das heißt, kommt Result null raus und nicht Result 2.
Was man glauben könnte für den anderen Fall hier,
If Summen gleich null, dann führe Account gleich,
dann geht er hier ja rein,
Count ist nicht gleich null und dann gibt es zu diesem If kein Els,
also würde Result unverändert gelassen, dann würde Result 2 sein.
Das sind also jetzt zwei mögliche Durchläufe,
die man hier sich überlegen kann und das Problem ist,
dass dieser dann natürlich falsch geschrieben ist,
weil hier dieses Els eine Bezug suggeriert durch die Einrückung,
der nicht da ist.
Es ist tatsächlich so, dass das, was hier darstellt,
ist das sogenannte Dengling-Els-Problem in solchen Sprachen wie Java oder C oder C Plus Plus.
Und zwar ist es so, in Java,
dass sich ein Els-Zweig immer auf das letzte IF bezieht.
Eigentlich müsste man genauer sagen, auch das letzte offene IF.
Nicht auf das letzte IF, weil das könnte ja
ein letztes IF in einem anderen Blog sein.
Aber immer auf das letzte offene IF. Und hier ist sozusagen
ein IF noch offen, deswegen kann sich das Els hier,
bezieht sich immer auf das direkte IF,
was davor steht.
Das kann man verhindern
Die man es so hinschreibt. Wenn wir wieder
unsere berühmte Klammerung nehmen, dann passt das alles wieder.
Dann ist auch genau eindeutig, was passiert. Dann gibt es
überhaupt keine Diskussion. Da muss man das auch gar nicht irgendwie nachschlagen.
Dann ist einfach sehr viel eindeutiger. Das heißt also,
wir haben dazu Quertext-Konventionen und das ist auch das,
was ich eben versucht habe, in dem anderen Beispiel zu zeigen,
wen ich dann so eine weitere Anweisung zu einer einzelnen Anweisung hinzuschreibe.
Es ist sehr viel praktischer, wenn die Klammern schon da sind.
Das ist eben genau dieser Begriff der Robustheit hier an dieser Stelle.
Okay, so viel zum IF.
Jetzt gehen wir zum Switch über
Das Switch ist so ähnlich wie das IF, nur ganz anders.
Ich versuche erst mal so ein bisschen einführend ein paar Beispiele zu geben.
Das ist wieder eine Folie, die nicht im Skript ist,
also nicht blättern jetzt nervös und hektisch, ist nicht drin.
Nehmen wir mal an, abhängig von einer auf der Tastatur gedrückten Taste
soll in einem Spiel eine von mehreren Prozeduren aufgerufen werden.
Also hier mal so, Andi,
das ist ja sogar ein Skript, stimmt ja gar nicht,
das ist ja noch ein Skript.
Also hier haben wir dann diesen Beispielcode Switch, gedrückte Taste,
wir nehmen an,
das ist ein Char,
also ein einzelnes Zeichen
Dann gibt es hier anscheinend mehrere Fälle, die hier und überprüft werden.
Also KSR, KSD, KSW, KSS.
Die Idee ist wohl, dass man irgendwie mit A,
D, W und S, kennen vielleicht einige von euch,
die schon mal mit Tastaturen irgendwelche Spiele gespielt haben.
Damit kann man so irgendwelche Raumschiffe steuern oder was weiß ich was.
Und mit der Lehrtaste natürlich hier immer schön unten, Rakete abfeuern.
Sehr schön. Und das ist einfach mal ein Paradebeispiel für einen Switch.
Das heißt, da geht es uns nicht um die Unterscheidung
Ja oder Nein, sondern es geht uns um die Unterscheidung
zwischen fünf verschiedenen Fällen.
Und die möchte man eigentlich gleichberechtigt nebeneinander schreiben können
Man könnte das doch alles mit IfLs schreiben. If,
Tastik gedrückt gleich. Ah, dann mach das, Els,
mach D und das sieht aber irgendwie ziemlich hässlich aus.
Das ist hier ein bisschen eleganter. Und was man hier verwendet,
das ist so eine sogenannte Case-Label, das sind eigentlich,
wenn man, also hier steht für uns Danten,
eigentlich sind es Literale.
Also in diesem Fall Zeichenliterale. Es gibt durchaus auch die
Möglichkeit, in Literale hinzuschreiben, aber wirklich nur Literale.
Also was dann nicht möglich ist, ist sowas wie einen Bereich anzugeben,
Case, E irgendwie dann eins bis fünf oder so.
Das geht nicht, geht einfach nicht.
Es müssen einfach einzelne Label sein,
einzelne Konstanten
Und ich werde gleich noch mal was dazu sagen,
dass es auch noch andere Typen gibt, über die man switchen kann.
Das sind so die Klassiker hier, Zeichen on Int.
So, was man jetzt aussieht, ist dieses komische Break, diese Break-Anweisung.
Hier ist es tatsächlich so, wenn einer der Fälle zutrifft,
dann soll nur das ausgeführt werden, was da steht.
Und dann wird mit dem Break aus dieser Switch-Anweisung rausgesprungen. Das heißt,
dieses Break ist sozusagen ein Springen,
ein implizites an diese Stelle, ein implizites,
kein Go-To, wenn man es mit Go-To machen würde,
mit Go-To würde man jetzt sagen, hier unten,
so ein Label hier hinschreiben,
Ende und dann würde man irgendwie Go-To-Ende schreiben oder sowas.
Ganz hässlich
Man kann sich da, wie gesagt, Go-To brauchen wir nicht weiter diskutieren.
So, dieses Break ist also hier so ein,
was passiert jetzt immer, wenn das Break da fehlen würden?
Nehm mal an, ich würde hier das Break weglassen,
dann wäre es tatsächlich so, wenn ich die Taste A drücke,
dann würde der Spieler nach links bewegt werden,
weil hier kein Break steht, läuft die Ausführung einfach im Kontrollfluss,
im Quelltext weiter.
Dann würde noch Bewegespieler nach rechts aufgerufen, was letztendlich bedeuten würde,
einmal da links und nach rechts, was nicht viel bewirkt.
Und dann würde erst das Break da ausgeführt werden,
weil dieses Break erst dasteht. Das heißt,
dieses Break ist hier schon sehr vernünftig an dieser Stelle.
Aber man kann es auch weglassen,
man muss es
nicht hinschreiben
Dafür gibt es eine ganze Menge interessante Anwendungen,
auch mal ohne mehrere Case-Label zusammenzufassen.
Nehmen wir zum Beispiel an für eine auf der Tastatur gedrückte Taste,
soll ausgegeben werden, ob sie einen Vokal liefert oder nicht.
Das ist ein Vokal. Da hat man auch wieder
so was hier, Char-Buchstabe. Ach, ich meine,
ich habe das doch auch irgendwo, nee, genau.
Also, wir lesen ein Zeichen von der Tastatur ein und
dann haben wir unsere lokale Variable Ist Bulien, ist Pokal von Pybulien.
Die setzen wir erstmal auf Forsch und dann machen wir
einen Switch über dieses Zeichen, was wir eingelesen haben.
Und dann steht hier KSA, E und so weiter,
also die ganzen Vokale an Groß und Klein.
Und am Ende steht hier Ist Vokale gleich True
Und wie man hier sieht, wenn das jetzt ein anderer Buchstabe ist,
dann wird hier keiner von diesen Labeln angesprungen.
Und dann passiert hier auch einfach gar nichts. Das heißt,
hier wird dann am Ende aus jedem System-out Print-Buchstabe,
der da eingegeben wurde, ist.
Und dann ist hier so eine ganz lustige Keine-Konstruktion.
Wenn es kein Vokal ist, dann wird noch ein Chaos gegeben.
Und sonst hier wird einfach gesagt,
der Buchstabe ist ein Vokal oder beziehungsweise ist kein Vokal.
Das ist ein bisschen lustig. Was passiert,
wenn zwar Case Label denselben Wert haben?
Ja, das ist jetzt mal eine interessante Frage.
Also wir können uns ja erstmal das Ding mal angucken.
Ich habe es nämlich hier
Mitgebracht, Textanalyse, ist Vokal, da ist es doch.
Direkt vor meiner Nase und für eure auch. Ist Vokal,
habe ich jetzt hier ein bisschen anders gebaut,
also Char-Buchstabe wird hier als Parameter übergeben und dann wird das hier überprüft.
Können wir also auch mal eben relativ leicht ausführen.
Ich mache hier mal so ein Exemplar und dann sage ich hier,
ist Vokal, ist den A,
ein Vokal, da sagt er mir,
jo, das ist ein Vokal und wenn ich sage,
ist denn V, ein Vokal, dann ist natürlich das False.
So, also das ist auch relativ überschaubar. Also abhängig davon,
was der Huchschlag ist, wird hier irgendein Case-Level angesprungen.
Aber was ist, wir sind jetzt tatsächlich zwei Case-Level in
denselben Bett hinten? Was wir jetzt zum Beispiel,
wenn ich hier ein kleines A stehen habe da oben,
da oben und hier hätte ich jetzt aus Versehen auch ein kleines A eingeschrieben.
Was würde dann passieren? Was ist eure Vermutung?
Wir hatten einen Vorschlag. Wild Gassing. Na,
wir hatten einen Vorschlag. Ja? So,
der guckt beim ersten und wenn das wirklich klingt,
wird das schon rausmokuriert
Okay, er sagte,
er springt dann zum ersten und wenn das irgendwie nicht stimmt,
dann spielt er zum zweiten oder so, habe ich das richtig verstanden?
Ja, das heißt, beim ersten, jeder weiß,
das spielt das auch, wenn dann Break steht.
Ach so, also er springt einfach zum ersten,
das heißt, er hat, er hat eigentlich zwei Stellen,
wo er hinspringen könnte, aber er springt zur ersten, okay?
Andere Möglichkeit. Ja? Ich habe zweimal rausgesagt und sage zweimal,
das ist... Er führt das zweimal aus und sagt einfach zweimal,
dass es ein A ist. Also hier, gut,
hier wird nur der Vokal, der Vokal steht hier nur einmal,
ja, also diese Switch ist keine Schleife, ja,
ist ganz vorsichtig,
das ist wirklich eine lineare Kontrollstruktur,
also hier wird einmal geprüft und dann wird
hier reingesprungen und dann wird hier irgendwas ausgeführt
Keinerlei Schleifen, keine Wiederholung, nix. Das ist ganz einfach,
wir können es ja mal probieren, ich mache das mal hier, ich schreibe hier mal ein A hin.
Der Compiler meckert schon, ist ja auch offensichtlich, dass das ziemlicher Quatsch ist. Ich habe da zwei Case-Labels stehen,
der kann es sehen, der Compiler,
weil es müssen Literale sein, der Compiler kann sofort sehen,
das ist das Gleiche, wie da ist,
da weiß ich ja nicht, wo ich hinspringen soll,
dass es mehrdeutig, und da wäre es schon ziemlich komisch,
wenn der Compiler sagen würde, oh,
ich springe mal zum ersten oder zum zweiten oder,
also, das ist natürlich Quatsch.
Deswegen ist es tatsächlich hier die Regel in Java,
es müssen verschiedene Labels sein,
wenn man da denselben Label zweimal hinschreibt,
ist das Unfug
Okay. Noch ein Beispiel. Ja, Switch. Für einen Monat im Jahr,
den der Benutzer durch eine ganze Zahl benennen soll,
soll ausgegeben werden, wie viele Tage er hat.
Also ich gebe irgendwie die Monatsnummer an. Eins für den Januar,
zwölf für den Dezember, elf für den November und so weiter.
Und dann soll mir ermittelt werden, wie viele Tage das hat.
So, dann kann man jetzt ganz unterschiedlich bauen,
aber das ist jemand mit einem Switch geworden.
Da sieht man einfach, dass es auch sehr, sehr nützlich ist,
dass man dann eben halt so verschiedene Fälle zusammenfassen kann.
Also diese Monate hier, 1, 3, 5,
7, 8, 10 und 12,
das sind die mit 31 Tagen.
Und dann steht hier
das Break
Und man kann tatsächlich jetzt hier wieder genau sehen,
Kontrollfluss, ja, hier irgendwie kommt der Kontrollfluss rein,
da steht das Switch, da wird der Ausdruck rausgewertet.
Als Ergebnis des Ausdrucks wird ein Case-Label angesprungen,
also in diesem Fall hier die Sieben,
wenn wir die Sieben eingegeben haben, dann wird hier das ausgeführt.
Bis dahin, bis zum nächsten Break und von da aus schwupps
springt er hier runter und führt dann hier noch was aus.
Auch das ist hier mal angedeutet in diesem Ding,
ich kann es mal übersetzen, hier ist dieses Switch gebaut.
Also passt tatsächlich auch noch im Bildschirm, ganz toll,
ermittle Tage für Monat, ich kann also hier einen Monat
eingeben und dann kann ich hier mit diesem Switch die richtige Anzahl ermitteln,
dass das funktioniert, können wir uns auch nochmal angucken.
So, jetzt sage ich immer, ermittle Tage für einen Monat,
jetzt sage ich mal, den Monat 11, also November,
boah, der hat, glaube ich, 30,
genau, und ermittle Tage für einen Monat, der Mai,
der hat, glaube ich, 31, ja, passt.
Okay. So, was ist jetzt,
jetzt kommen ja diejenigen unter euch, die sagen, was ist denn,
wenn da jetzt eine größere Zahl eingegeben wird, gut,
das ist natürlich jetzt hier wieder eine Frage des Bereiches,
der definiert ist, also in dem Kommentar für den Benutzer steht drin,
bitte gib eine Zahl 1 bis 12 ein.
Und jetzt kommt noch die Frage, nach dem Schaltjahr und ihr
wisst das, dass man das alles noch weiterführen kann.
Es geht jetzt hier darum,
das Switch zu demonstrieren und nicht darum zu zeigen,
wie man für Schaltjahre und so weiter.
Also das ist ein Beispiel, um zu zeigen,
dass es durchaus sinnvoll sein kann, mehrere Case-Label zu einem Fall zusammenzufassen.
Was passiert denn, wenn keiner der Fälle zutrifft und die Default-Anweisung fehlt?
Das haben wir eigentlich eben schon gesehen bei dem anderen Beispiel.
Da war tatsächlich hier Sign Default. Das ist tatsächlich sogar so,
wenn da hier jemand mal hier in Default eingibt,
also ich kann jetzt hier das Ding einfach nicht ausführen
und sage jetzt mal 33,
dann kommt da minus eins raus
Ein wohl definiertes Ergebnis, also keine Fehlermeldung,
kann man da halt drum streiten, ist halt eine Frage,
wie denn diese Dienstleistung definiert ist. Wenn der Dienstleister sagt,
bitte gib mir nur Zahlen von 1 bis 12,
dann könnte er auch eine Fehlermeldung schmeißen an der Stelle.
Gut, wenn es diese Default-Anweisung fehlt und es trifft keiner der Fälle zu,
das haben wir eben schon gesehen, dann wird einfach nichts ausgeführt.
Das ist so wie beim IF,
wenn beim IF die Bedingungen nicht zutrifft,
wird ja auch einfach nichts gemacht von dem IF,
von der Anweisung,
die da steht
Hier ist noch ein weiteres Beispiel. Das ist auch nochmal
ganz hübsch. Der Benutzer soll eine ganze Zahl eingeben,
die eine Zehnerpotenz ist, für eine korrekt eingegebene Zehnerpotenz soll
eine passende Exponent ausgegeben werden, für alle anderen Zahlen eine Meldung.
Das ist keine Zehnerpotenz ist. Das heißt,
wenn ich zum Beispiel die Zehn eingebe,
das ist eine gültige Zehnerpotenz, dann ist der Exponent,
der wird hier auf Null gesetzt, dann wird er hier,
der Switch läuft genau hier runter und dann wird hier einmal der Exponent erhöht.
Also ist das 10 hoch 1. Stimmt, genau.
10 hoch 1 ist 10. Und was man aber auch hier sieht,
wenn man jetzt hier eine größere Zahl nimmt, sagen wir mal,
ich nehme hier sowas wie eine Million oder so,
hier der Exponent halt mehrfach erhöht.
Das wird tatsächlich, es werden alle Anweisungen durchgeführt, bis zum nächsten Break.
Es ist kein Breakdar, beziehungsweise hier ist nur ein kleines Break.
Und das wird einfach alles ausgeführt. Wenn denn hier der
entsprechende Label angesprungen wird, wenn keine Zehnerpotenz eingegeben wird,
default, dann wird hier irgendwas anderes rausgeben.
Ist keine Zehnerpotenz. Also ihr seht,
das ist durchaus möglich und sinnvoll, sowas auch zu benutzen.
Kann mir jemand sagen, warum dieses hier diese Zahl,
die sinnvollste Zahl ist, die als man mal größte Zahl hinschreiben kann.
Das ist eine Milliarde hier. Die nächste Zehnerpotenz wären
10 Milliarden, genau. Ich glaube, da springen schon
die Arme hoch. Es ist der Wertebereich von innen,
geht ja nur bis plus 2 Milliarden,
also kann man 10 Milliarden gar nicht mehr vernünftig als Int darstellen.
Wenn man das hinschreibt, dann kommt wieder irgendwas anderes aus.
Durch irgendwelche Überläufe. Gut. Nee,
das kann man, glaube ich, gar nicht hinschreiben.
Kann man gar nicht entscheiden. So, sehr schön.
Dann habt ihr mal so ein paar Switches gesehen.
Da ist eine Frage zum Switch. Würde der Intro
nicht sein. Bei einer Folie davor war dieser hier.
Noch einen davor oder bei dieser?
Bei dieser
Nee, es ist ja so, wenn wir zum Beispiel
hier, sagen wir mal, umgebende 1000 ein.
1000 ist 10 hoch 3, richtig? Das heißt,
dann springt dann hier zur 1000,
dann wird der Exponent von 0 auf 1 erhöht,
dann wird er von 1 auf 2 hört,
dann wird er von zwar auf 3 erhöht.
Und dann kommt hier raus 10 noch 3. Das heißt,
für die höheren Zahlen muss der Exponent natürlich häufiger erhöht werden.
Okay. Sonst noch Fragen jetzt erstmal zu den Beispielen.
Dann können wir nämlich jetzt das hier mal kurz zusammenfassen.
Also diese Switch sieht halt so aus, allgemein switcht dann
eine Expression. Dann diese Cases mit diesen Werten,
die hier stehen, das müssen halt
Konstanten sein
Dann können da mehrere Statements stehen und dann kann man so
einen Break dahin schreiben und dann gibt es auch so einen Default.
Man kann tatsächlich auch über die Elemente eines Aufzählungstyps switchen,
die habt ihr noch nicht kennengelernt, aber die Welt ihr
sicherlich das eine oder andere nochmal zu sehen bekommen.
Man kann so Aufzählungstypen wie Farbe definieren,
da gibt es dann irgendwie die Elemente rot-grün-blau zum Beispiel.
Oder tatsächlich auch über Strings. Man kann tatsächlich auch über Strings switchen.
Das geht aber erst seit Java 1,7 und wir gehen momentan
bei uns im Übungsbetrieb noch nicht von Java 1,7 aus.
Also wenn ihr dann mal mit ganz modernen Rechnern arbeitet,
ganz modernen Systemen arbeitet. Wir gehen, glaube ich,
bei uns momentan von Java 1,6 aus,
Mindestens 1,5 auf jeden Fall. Okay, die Auswahlanweisung ist
eine Mehrzwick, eine Mehrwegverzweigung. Das heißt, ich kann
mehrere Riffe unterscheiden. Wenn man das jetzt mit dem IF vergleicht,
das Case mit dem IF-Vergleicht, dann ist es eben halt,
erstmal ist es so, dass ich verschiedene Ausdruckstypen habe.
Bei einem IF ist es nur ein Bulien,
der den Ausdruck reguliert, das IF.
Während es beim Switch, können es eben halt Cha sein,
in, aber auch Strings oder Aufzählungstypen.
Es können eine oder mehrere Fälle ausgewählt werden, das ist auch anders.
Bei dem IF ist entweder das eine oder das andere,
ich kann nicht irgendwie erreichen,
dass beides gemacht wird
Wünschen geht das. Ich kann tatsächlich irgendwie sagen, naja,
der eine Fall, da soll der andere gleich mit ausgeführt werden.
Anstatt eines eindeutigen Elsfalls gibt es aber auch einen Standardfall für alle nicht explizit benannten Fälle.
Es ist so ähnlich wie beim, wie beim IF. So,
dann hier einfach nochmal die Syntax, ist,
glaube ich, nicht so spannend und zusammengefasst einfach nochmal,
man kann hier also alles, alles wird durchlaufen,
ab dem passenden Label, bis zum nächsten Break.
Man kann das Break als Möglichkeit nehmen, um eine Auswahlanweisung zu verlassen.
Man kann alternativ auch mit einem Return das machen,
man kann also auch statt an einem Break einen Return dahin schreiben.
Damit verlässt man dann vorzeitig die Prozedur, geht natürlich auch,
wenn da nichts mehr passiert nach der Switch-Anweisung in der Prozedur,
in der Methode und mit Throw habt ihr vielleicht auch schon gesehen,
kann man auch ein Programm einfach abbrechen,
man schmeißt eine Acception und sagt, so nach dem Motto,
hier ist ein Fehler.
Ja, Case Label darf nur einmal vorkommen, wenn kein Default Label vorhanden ist,
dann wird das ganze Switch übersprungen, wenn kein Case Label zutrifft.
Das ist nochmal so ein Negativbeispiel,
hier hat wahrscheinlich jemand wieder mal so gedacht, ah ja,
Switch E, Case 1, schreibe 1 raus,
Case 2, schreibe 2 raus und Default schreibe viele raus.
Wenn jetzt tatsächlich Case 1 zutrifft, dann kommt da raus,
1, 2 viele und das ist vermutlich nicht das,
was gewollt war
Es sei denn, der Mensch wollte da wirklich so was komisches tun.
Ja, dann sind wir auch schon relativ gut in der Zeit.
Ich habe jetzt tatsächlich ziemlich genau die Zeit gebraucht, die ich haben wollte.
Machen wir jetzt fünf Minuten Pause, wenn nicht noch Fragen sind.
Das war erstmal alles zum Impf, unserem Switch.
Und jetzt müssen wir halt sehen,
dass wir so ein bisschen mit der Zeit hinkommen.
Ich will euch nicht zu sehr strapazieren. Wir schauen mal
, dass wir das so in 35 Minuten durchkriegen.
Gucken wir uns mal für Schleifen, also für Wiederholungen in der Programmierung.
Ein paar einführende Beispiele an. Das ist die Folie,
die ich vorhin meinte
Die ist nämlich nicht im Skript. Zum Beispiel,
wir wollen wiederholt ein Passwort einlesen, solange die Eingabe noch
nicht korrekt ist. Also, ließ ein Passwort ein,
prüfe, ob das das richtige Passwort ist.
Wenn nicht, ließ nochmal das Passwort ein.
Das kann man relativ leicht in Java so hinschreiben.
String-Passwort wird hier deklariert, dann wird hier ein Do-Wile gemacht.
System-Out-Print-Passwort und dann ließ Zeile vom Benutzer. Das ist jetzt
hier einfach mal angenommen, dass das irgendwo implementiert ist.
Und dann solange irgendwie das Passwort ungleich das Passwort ist.
Das können wir uns
mal angucken
Äh, die Vitteration hier, das zweite Projekt.
Das ist so ähnlich wie das Projekt,
was ihr auch in den Übungen bearbeiten werdet.
Eine Klasse Schleifendreher. Und da kann ich mir Exemplare erzeugen.
Und ich kann dann hier sagen, verlange Passwort.
Ja, und dann sage ich hier jetzt irgendwie,
hallo, naja, das ist es anscheinend nicht.
Die FDF auch nicht. Aber Zimtstern funktioniert dann.
Du darfst eintreten. Ist ja Weihnachten bald,
dachte ich mir
Sieht also tatsächlich mehr oder weniger genauso aus,
wie das hier auch beschrieben ist.
Hier ist das verlange Passwort. String. Passwort,
do, system, outprint, liest Zeile vom Benutzer.
Wile not password equals, das Passwort und das Passwort
steht hier irgendwo als Exemplarvariable versteckt im Quelltext.
Ja, soweit. Dann haben wir hier ein anderes Beispiel.
Wir möchten alle druckbaren Zeichen des Aski-Zeichens setzen,
das jeweils mit ihren Originalzahlen auf der Konsole ausgeben.
Da gehe ich einfach mal durch alle Zeichen von 32 bis
107, 126 durch. Ich weise dann hier irgendwie noch
den Charakter einem in zu
Und dann mache ich hier eine Ausgabe, dann gebe ich
nämlich die Originalzahl aus, das I und das Aski-Zeichen.
Auch das ist hier implementiert, das heißt,
ich kann das jetzt hier einfach mal aufrufen, drucke alle,
drucke, druckbare Aski-Zeichen, dann sieht das irgendwie so aus.
Also Aski-Zeichen, 32 ist ein Leerzeichen, dann kommen hier verschiedene Zeichen,
die ihr auch schon kennt und dann kommen hier die Großbuchstaben
und dann kommen die kleinen Buchstaben und man sieht ja auch immer so die Originalzahl dabei.
Also es ist total spannend. Man sieht hier,
wie das gebaut ist, genau wie auf der Folie, also druckbare Aski-Zeichen.
Cha, 32 bis 127 und dann wird hier entsprechend was gemacht.
Das ist, das sind zwei Beispiele, bei denen irgendetwas wiederholt wird.
In dem einen Fall weiß man nicht, wie lange das dauert,
da muss man das so lange machen,
bis halt irgendwas Richtiges vorhanden ist, bis die richtige Bedingung zutrifft.
In einem anderen Fall ist es so, man weiß schon ziemlich genau,
dass man da etwas wiederholt tun will und zwar sogar genau wie oft.
Also hier tatsächlich, ich habe ja hier meinen Anfang,
mein Ende genau festgelegt. Das sind so zwei verschiedene Ausprägungen von Schleifen,
die man so üblicherweise schreien kann. Ihr müsst mir verzeihen,
wenn ich Zwischendurch immer so ein bisschen lutsche hier an diesem Husten-Bonbon,
aber ich brauche das,
was ich sonst wahrscheinlich gleich hier nicht mehr gut sprechen könnte.
Da wird ja nicht aufgezeichnet. Der Ton aber schon,
oder? Ah, ist ja beruhigend. Okay. Ganz
allgemein ist es einfach auch nochmal ganz interessant zu sehen,
dass gerade wenn es um Schleifen geht, dann werden ja Computer erst interessant.
Man kann jetzt sagen, was wir bisher gemacht haben,
war ganz hübsch, aber so richtig spannend kann man ja erst spannende Dinge,
kann man erst tun,
wie man auch Schleifen programmieren kann
Weil man dann einfach diese Rechenpower von den heutigen Maschinen voll ausnutzen kann.
Wenn ihr einfach mal so eine Schleife baut in Java,
die einfach nur irgendwie einen Zähler hochzählt.
Und dann irgendwie das Ding mal startet und dann stoppt mit dem Debugger oder so.
Oder irgendwie anhaltet, weiß nicht, dann werdet ihr erstaunt sein,
wie weit dieser Zähler dann schon gelaufen ist.
Also das ist irre, wie schnell die Dinge heutzutage sind.
Der gute Gunther Duck hat das vor ein paar Jahren mal gesagt,
der normale Mensch hat heute mehr Rechenpower zu Hause als ganz Houston,
als es ein Apollo-Problem hat.
Ich weiß nicht, ob ihr das kennt,
diesen Film, Apollo, 13 war es glaube ich,
die dann irgendwie ein Problem hatten
Die haben da auch Computer gehabt,
aber die waren bei weitem nicht so ein Satz,
so rechnen, so fähig wie die Dinger,
die ihr heute in eurem Handy stecken habt.
Das ist schon faszinierend. Okay. Also, Computer,
Wiederholung, möglichst schnell, möglichst viel. Aber wenn man jetzt solche Schleifen programmiert,
dann muss man sich eben halt so ein paar Fragen stellen,
nämlich wie ist eigentlich so eine Wiederholungsanweisung aufgebaut?
Wo wird die Wiederholung kontrolliert und wo steht der Kontrollmechanismus?
Und das werden wir uns nochmal ein bisschen jetzt ansehen.
Wenn wir eine bestimmte Anweisung mehrfach ausführen wollen, dann können wir
das ja erreichen, indem wir sie einfach mehrfach hinschreiben.
Das ist jetzt für diejenigen, die schon programmieren können,
relativ, sagen wir offensichtlich, Für Programmieranfänger haben wir wieder festgestellt,
ist das irgendwie auch nochmal gut, sich das klarzumachen.
Ich kann natürlich auch dieselbe Anweisung mehrfach hinschreiben. Ich kann zum Beispiel bei meinem Schleifendreher hier,
statt das so zu machen, wie das hier gemacht ist,
mit einer Vorschleife, könnte ich auch einfach hier hinschreiben,
Moment, ich schreibe einfach Chart C ist gleich 32,
dann schreibe ich in I,
ist gleich c und dann schreibe ich hier irgendwie diese Zeile,
Moment, an diese Zeile,
die kopiere ich mal hier runter
So, ja, dann wird das hier schon mal für
das erste Zeichen ausgegeben und dann schreibe ich jetzt hier einfach noch dahin,
plus plus I und plus plus C. Werden also beide hochgezählt.
So. Und jetzt nehme ich einfach das Ding hier und kopiere
das hier ein paar Mal hin.
Das mache ich jetzt nur ein paar Mal,
weil ich das jetzt nicht irgendwie 90 Mal machen will,
das würde ziemlich hässlich werden.
Das funktioniert aber auch, das kann ich jetzt so übersetzen
, ups
Müsste übersetzbar sein, ja, wunderbar.
Und? Ich kann das auch ausführen. Also Schleifendreher,
gib mir mal hier drucke, druckbare Aske-Zeichen und dann macht
er hier auch ein bisschen was, nämlich immerhin von 32 bis 40.
Und er macht tatsächlich die richtigen Zeichen her.
Man sieht hier, das sind genau die gleichen Zeichen,
die da oben auch rausgekommen sind bei dem ersten Durchlauf.
Also es funktioniert auch und ihr werdet lachen, aber ich kenne,
ich habe in meiner frühen Programmierkarriere auch Leute gehabt,
die so programmiert haben. Die hatten also nicht verstanden,
dass man so mit Kontrollstrukturen irgendwie einmal was hinschreibt und dann irgendwie
eine Struktur drumherum legt und dass man das dann, also dann haben tatsächlich dann so Sachen,
die sie mehrfach haben wollten, auch einfach mehrfach hingeschrieben.
Das ist nicht sehr hilfreich, wenn man die Anzahl der Durchläufe vorher nicht kennt.
Dann wird es schwierig. In diesem Fall funktioniert das tatsächlich,
würde man so hinschreiben können, aber meistens eben doch nicht.
Das heißt, was wir eigentlich wollen, ist so eine Kontrollstruktur,
das ist hier grün angedeutet und dann die Anweisung,
die ausgeführt werden soll.
Und dann kommen wir zu so ein paar Begriffen,
die wir hier ganz zentral irgendwie mit den Schleifen definieren.
Der Schleifenrumpf ist das, was wirklich wiederholt ausgeführt werden soll
Das ist üblicherweise ein Block, meistens mit irgendwie,
vielleicht auch mit lokalen Variablen oder ähnlichem.
Und dann gibt es eine schleifende Steuerung.
Das ist hier so angedeutet, so grün drumherum.
Das ist jetzt so ähnlich wie bei den Strukturgrammen,
diese Darstellung. Und man kann das jetzt jetzt unterschiedliche,
sagen wir, Steuerungen überlegen, dass man sagt,
man macht eine feste Anzahl von Wiederholung oder man macht die Anzahl
der Wiederholung von einer Variablen abhängig oder von einer Bedingung,
sehr sogenannten Schleifenbedingung.
Und das ist eben, wie gesagt, so eine Art Rahmen.
Und was uns auch, was man aufpassen muss,
im Schleifenrum können, Anweisungen stehen die Einfluss auf die Schleifensteuerung nehmen.
Also das ist üblicherweise nicht immer so,
dass man nur in dem Schleifensteuerung die Dinge steuert.
Wenn wir uns nochmal ansehen. Okay, dann haben wir
hier mal so einfach mal so angedeutet zu grafischer Form verschiedene Schleifenarten.
Also zum Beispiel führe genau viermal aus. Was man sich
ganz gut vorstellen kann, eine Anweisung, die hier Anweisung 1 heißt.
Oder führe N mal aus. Ich habe also jetzt,
ich weiß es nicht genau, ich muss es erst berechnen,
wie oft, aber dann habe ich dann irgendwie eine Variable N und dann sage ich führe das N mal aus.
Das sind klassisch so Zählschleifen, in denen man weiß,
dass da irgendwas mehrfach passieren soll und dass man da auch das mitzählen kann und üblicherweise auch weiß,
wie häufig oder eben halt das vorher berechnet.
Das hier gibt es ein weiteres Beispiel,
solange eine Bedingung B zutrifft, soll eine Anweisung ausgefüllt werden.
Das sind alles abweisende Schleifen. Das heißt,
das sind Schleifen, das ist hier so angedeutet,
dass also hier diese Steuerung sozusagen im Weg steht,
wenn man wieder diese Idee hat von Kontrollfluss,
kommt von oben rein und unten geht es raus.
Das heißt, hier ist das Grüne im Wege und es kann sein,
dass das Grüne entscheidet, der Rumpf wird gar nicht ausgeführt.
Im Gegensatz dazu haben wir hier sowas,
was eine nicht abweisende Schleife ist,
also wo tatsächlich diese Anweisungsfolge einmal ausgeführt wird und dann am
Ende geprüft wird,
ob man weitermachen muss
Das haben wir eben schon gesehen, dass wir das mit dem Passwort eingeben.
Man muss ja mindestens erst mal einmal das Passwort einlesen,
um dann überhaupt prüfen zu können und dann eventuell schleift man wieder hoch.
Immer dann, wenn man eine Bedingung abfragt,
also bis eine Bedingung zutrifft oder so lange eine Bedingung zutrifft,
das sind dann bedingte Schleifen.
Jetzt sind wir hier schon, dass das zwei verschiedene Ausprägungen sind,
solange eine Bedingung zutrifft oder bis eine Bedingung zutrifft.
Das ist ganz interessant. Also das mit dem Abweisen habe ich
schon gesagt, wenn sie gar nicht ausgeführt werden kann,
der Schleifen rumpft,
dann ist das
eine abweisende Schleife
Wir nennen die auch gerne kopfgesteuerte Schleifen. Und die anderen
sind eben nicht abweisende oder Fuß- und Endgesteuerte Schleifen.
Begriffe, Begriffe. Die Ausführung einer bedingten Schleife, was
mit einer logischen Bedingung verknüpft. Das haben wir jetzt auch schon gesehen,
solange die Bedingung zutrifft, mache was oder eben mache etwas,
bis etwas, bis eine Bedingung zutrifft.
Kann man entweder vorher oder hinterher machen, also entweder abweisend oder entgesteuert.
Und das wird auch jedes Mal neu überprüft. Also es
wird jedes Mal bei so einem Schleifendurchlauf diese Bedingung neu geprüft.
Und das heißt üblicherweise auch, dass im Rumpf irgendwelche Anweisungen
stehen, die diese Bedingungen verändern.
Meistens möchte man tatsächlich die Schleife nicht endlos durchführen,
sondern irgendwie Eine bestimmte Anzahl und dann sollte die Bedingung irgendwann nicht mehr zutreffen.
Das muss man sich jetzt auch noch mal genau überlegen.
Also unabhängig davon, ob es jetzt abweisend ist oder nicht,
also ob der Rumpf genau einmal mindestens durchgeführt wird oder vielleicht gar nicht.
Es ist auch noch die Frage, wie formuliert man denn die Bedingung?
Also wie ist die Schleifenbedingung formuliert? Ist sie positiv formuliert im Sinne von,
solange die Bedingung zutrifft, führe den Schleifenrumpf aus?
Oder ist es eigentlich, dass man sagt,
führe den Schleifenrumpf aus, bis eine Bedingung zutrifft?
Dieses Biss ist natürlich eine andere Logik. Das heißt,
da wird die Bedingung geprüft. Und wenn sie zutrifft,
abgebrochen. Es ist zu Ende. Bei den anderen Schleifen,
bei denen positiv bedingt ist es so,
wenn die Bedingung zutrifft, mit der Schleifenrumpf noch mal ausgeführt.
Diese so lange Schleifen nennen wir positiv bedingt und die anderen nennen wir zielorientiert.
Das will ich mal an einem Beispiel zeichnen. Das Beispiel
ist im Skript zwar drin, aber nicht ganz so wie jetzt hier.
Ich habe es ein bisschen geändert, weil das Beispiel hier,
habe ich ein bisschen verständlicher ist.
Nehmen wir ein einzelnes Beispiel, solange ein einzelnes Zeichen,
sorry, einzelnes Zeichen, soll so lange eingelesen werden,
bis es entweder ein J oder ein N ist.
Irgendwie, da wird irgendwie gefragt,
weitermachen und dann steht dann da mal, ja,
nein und dann, also wiederhole, Schleifenrumpf,
ein Leser eines Zeichens bis Zeichen gleich J oder Zeichen
gleich Ende ist
Ich glaube, das kann man ganz gut nachvollziehen.
Das ist die Logik, die hier eigentlich man haben möchte.
Das Problem in Java ist, es gibt nur positiv bedingte Schleifen.
Es gibt keine Möglichkeit, so eine zielorientierte Schleife zu formulieren.
Alle bedingten Schleifen in Java werden ausgeführt, solange die Schleifbedingungen zutrifft.
Das heißt, wenn ich, ich muss diese Bedingungen hier negieren,
wenn ich die wirklich in einer Du-Wal-Schleife hinschreiben will.
Also wenn ich hier hinschreiben will, du nicht an Till,
an Till würde genau die Bedingung hier sein,
bis das zutrifft, sondern wir wollen ja machen,
du Wire, solange das Negative von diesem Hirn zutrifft.
Das heißt, aus diesem Zeichen gleich Gott oder Zeichen gleich hinein,
wird dann eigentlich sowas Wiederhole solange,
das Zeichen ungleich J ist und das Zeichen ungleich en ist.
Das ist Äquivalent, beziehungsweise das eine ist die Verneinung des anderen.
Und das ist etwas, was viele Programmieranfänger auch verwirrt,
dass man mit diesen bullischen Ausdrücken ja so aufpassen muss,
dass man tatsächlich, wenn man sie verneint,
also wenn ich diesen bullischen Ausdruck hier negiere,
dann kommt das hier dabei raus.
Das ist letztendlich eine Anwendung mit den morganischen Regeln. Das heißt,
wenn ich diesen ganzen Ausdruck hier dann negiere,
dann kann ich die einzelnen Ausdrücke negieren und muss aber dann
auch die Verknüpfung umdrehen von einem oder in ein und und umgekehrt.
Das ist das, was hier steht, also Not,
P oder Q, ist dann Not P und Not Q.
Das heißt also hier tatsächlich, beide Teile werden legiert und
das Ding wird umgedreht von einem Ohr in ein End und umgekehrt genauso.
Also wenn da steht, Not P & Q,
dann ist das hier Not P, Nord Q.
Das heißt, wir haben diesen Fall hier gehabt,
dass wir sozusagen eine Oder-Verknüpfung negiert haben und dann wird da eben halt eine Unverknüpfung draußen.
Das ist etwas, was man sich klar machen muss und Gibt es eine Frage dazu?
Will man da nicht einfach eine Negation vorschreiben?
Das ist auch eine Möglichkeit. Man kann natürlich statt,
das ist eine gute Möglichkeit, er hat gesagt,
könnte man nicht das Ganze einfach eine Integration vorschreiben.
Ich kann das Ganze einfach klammern und hier ein Ausrufezeichen davor schreiben.
Das geht natürlich auch. Ist aber auch nicht so richtig
gut lesbar, finde ich. Also wiederhole,
dann würde er da stehen, wiederhole,
do wile und dann not und dann bin ich mir ziemlich sicher,
dass dann viele, die das lesen, erstmal das nicht verstehen werden.
Ich finde, wenn man das dann mit The Morgan ausrechnet,
ist es schon nachvollziehbar, dass man das so lange macht,
solange das Zeichen ungleich wird und ungleich Ende ist.
Man möchte entweder einen J euren End haben und solange es ungleich
diesen beiden Zeichen ist, macht man eben halt die Schleife weiter.
Das ist eine Frage von Lesbarkeit,
aber es ist einfach auch nur nochmal ein Beispiel,
um zu zeigen, dass man diese Demorgan-Regeln ganz gut brauchen kann.
Gerade auch bei Schleifen. Bei bedingten Schleifen. Gut,
dann haben wir noch diese Zählschleifen, da hat man üblicherweise,
oh da ist noch eine Frage.
Bitte habe ich nicht verstanden
Ob das optimierter ist, ah, nein, das ist nicht optimierter.
Also die Geschwindigkeit, mit der solche bullischen Ausdrücke ausgewertet werden, die ist vernachlässigbar.
Das spielt an dieser Stelle keine Rolle. Nee. Es ist einfach,
das primäre Kriterium für uns ist Lesbarkeit,
dass man den Quelltext lesen kann, weil Schreiben ist einmal gemacht,
aber lesen hinterher, wenn andere Leute dann den Quelltext lesen,
die andere geschrieben haben, dann ist es immer gut,
wenn der Quelltext gut lesbar ist.
Dann haben wir die Zählschleifen, da brauchen wir üblicherweise einen Schleifenzähler.
Hier ist mal so ein Beispiel in Pascal,
um einfach mal zu deuten, wie denn so einfach,
wie einfach solche Dinge aussehen können.
Also sowas gibt es in Pascal, ich deklariere rein,
Variable i vom Typ Integer,
dann sage ich irgendwie 4i gleich 1 2 10. Du,
beginne und dann wird hier das gemacht.
Das ist relativ langweilig, was hier passiert. Er wird
irgendwie hallo ausgegeben und Durchlauf, die Nummer wird ausgegeben.
Aber man kann irgendwie sehr schön, dass das so sich überlegen,
was, ah ja, was passiert da?
Vi gleich einzutennen. Also ihr sollt zuerst den Wert 1
bekommen und dann fortlaufend bis zum W10. Das ist irgendwie ganz hübsch.
In Java sieht das ein bisschen anders aus
Üblicherweise nimmt man für eine Zählschleife eine Vorschleife,
aber hier nochmal einfach die Übersicht,
welche Schleifen wir denn haben in Java.
Es gibt vier Schleifenkonstrukte und wir betrachten erstmal nur drei.
Die vierte kommt erst in zwei, drei Wochen.
Einmal hier die Wahlschleife, das ist eine abweisende Schleife,
das ist also die Bedingung zu Anfang geprüft und alle sind positiv bedingt.
Also alle positiv bedingt, positiv bedingt, positiv,
alle machen für den Schleifenraum aus,
solange die Bedingungen zutrifft,
die in der Expression
drin steht
Die Wahlsteife ist abweisend, die Dubai-Schleife ist endgesteuert, also nicht abweisend.
Und die Vorschleife ist auch abweisend. Das heißt,
es kann auch sein, dass der Rumpf gar nicht ausgeführt wird.
Und die ermöglicht unter anderem Zählschleifen. Die gucken wir uns jetzt mal
ein bisschen genauer an. Da brauchen wir dann diese Syntax.
Und deswegen holen wir uns die mal hiermit rüber.
Das ist die Vorschleife in Java. Hier ist ein Beispiel
vor Int-I gleich 0, I kleiner 10 plus plus.
Und dann hallo und Durchlauf. Ist das gleiche Beispiel,
was wir gerade an Pascal gesehen haben,
wie jetzt in Clus Plus formuliert.
Sieht ein bisschen anders aus
Muss ein bisschen genauer eingucken, um das zu verstehen.
Also zum einen gibt es hier so etwas wie eine Init-Expression.
Das ist der Teil der Schleifensteuerung,
der wird vor dem ersten Seminar wird einmalig ausgeführt.
Also sozusagen die Initialisierung für die Schleife. Das Schöne an der Vorschleife ist,
dass dann diese Variablen, die man hier benutzt,
auch nur innerhalb der Vorschleife sichtbar sind.
Das haben wir eben tatsächlich in einem Beispiel gesehen. Und zwar,
hier, hier habe ich einfach mir eine Vorschleife deklariert, C und I.
Beides sind Varianten, die innerhalb der Schleife deklariert sind.
Aber diese Variable C hier, Ist nur in diesem Bereich sichtbar gewesen.
Das heißt, ich konnte direkt danach eine zweite Variable C deklarieren,
weil die andere schon wieder nicht mehr sichtbar ist.
Auf Sichtbarkeit und Lebensdauer kommen wir gleich.
Aber das ist einfach hier auch so ein Beispiel.
Das ist ganz praktisch. An der Stelle,
dass das nur auf diese Schleife beschränkt ist, dieses I.
Dann wird hier die Schicht in die Busche einfach die Schleifenbedingungen,
die geprüft wird.
Da ist eine Frage
So, die Frage ist, was ist,
wenn ich vorher schon eine Variable mit diesem Namen benannt habe?
Auf die Fragen komme ich gleich noch.
Das hoffe ich, das kriegen wir heute noch runter,
sonst, wie gesagt, beim nächsten Mal.
In Java ist es üblicherweise nicht möglich, die zu verdecken.
Also man kann nicht eine Variable da wählen, wenn die schon vorher existiert.
Ja, werden wir gleich nochmal sehen. Gut,
hier die Bullshit Expression, die wird überprüft und dann gibt es
diese Update Expression und die wird nach Ausführung des Schleifen noch irgendwas ausführen.
Das finde ich halt auch nochmal irgendwie ganz,
ganz gehörig kompliziert. Deswegen will ich das auch nochmal zeigen
Wir haben hier ein weiteres Beispiel. Das ist jetzt ein bisschen spannender
. Gibt die Ziffer 0 bis 9 mit dem Hinweis,
dass es sich um Ziffern handelt, auf der Konsole aus.
Also hier drucke alle Ziffern. Eine Vorschleife in die gleich 0,
i, kleiner 10 plus plus i,
System Outprint and E ist eine Ziffer.
Wenig spektakulär, aber so mehr oder weniger das Gleiche,
was auf der Folie ist.
Aber dieses Ding würde ich jetzt gerne einfach mal hier vorführen.
Und zwar setze ich hier mal einen Haltepunkt hin und
jetzt lassen wir mal hier Drucke alle Ziffern ausführen.
Da muss dann einmal hier
Drucke alle Ziffern. Wo sind Sie da? Da haben wir
jetzt hier den Debugger. Und jetzt sehen wir hier,
lokale Varianten gibt es noch gar nicht,
weil wir stehen an dieser Stelle des Fonds noch gar nicht ausgeführt.
Wenn wir jetzt einen Schritt übermachen, dann wird dieses Fonds ausgeführt.
Und zwar wird zuerst die Initialisierung vorgenommen. Das heißt,
I wird deklariert an dieser Stelle und auch gleich initialisiert mit null.
Und es wird die eingangs die Bedingung geprüft. Also ist
I kleiner 10, ja, null ist keiner 10,
also gehen wir in den Rumpf hinein.
Also sehen wir hier, wir stinken genau mitten im Rumpf.
Wir sehen jetzt hier auch die Variabi I deklariert. So,
jetzt kann ich hier Es wird hier ausgegeben, ist eine Ziffer,
ja, wunderbar. Das wollte ich jetzt nicht unbedingt sehen.
Kann man mal ein bisschen kleiner machen hier. So,
so, und wenn ich jetzt hier mich so durchschleife,
dann seht ihr, und das ist aber jetzt genau das,
was hier mehrfach passiert, und das ist bisher relativ unspektakulär,
jetzt ist hier schon acht ausgegeben worden.
Das heißt, wir sind jetzt gerade da oben,
I hat den Wert acht. Und eigentlich ist es so,
dass dieses Erhöhen für uns logisch passiert am Ende des Rumpfes.
Also, wir haben jetzt die acht schon ausgegeben, also hätte,
eigentlich müsste jetzt dieses Plus-Plus-I für uns logisch schon ausgeführt sein,
ist es noch nicht.
Also es ist immer tatsächlich jetzt hier, ist jetzt
der Kontrollfluss. Jetzt wird das plus plus i ausgeführt.
Und dann wird geprüft, ob es kleiner als 10 ist.
Wenn ich jetzt hier den Schritt übermache,
dann wird also plus plus i gemacht, wird das ist 9,
ja momentan ist es 8 und wir gehen nochmal rein.
Aber jetzt ist es so, jetzt ist die 9 da
oben ausgegeben worden. Und jetzt sind wir da oben.
Und jetzt ist es tatsächlich so, dass IS9,
jetzt wird das i erhöht, wird auf 10 erhöht werden.
Und dann wird die Prüfung gemacht und 10 ist
nicht kleiner als 10. Deswegen sage ich jetzt vorher,
dass wir jetzt hier runterspringen und nicht nochmal an den Rumpf hinein.
Und genau so ist es auch. Und das ist eben halt etwas,
was ich persönlich relativ schwierig finde, bei dieser Vorschleife,
da muss man halt schon sehr genau wissen, was da passiert,
dass das Ding hier eigentlich logisch am Ende passiert.
Ihr könnt also diese Schleife auch anders schreiben, man kann
das hier mal zeigen, ich kann das hier rausnehmen.
Und hier hinschreiben. Ja, ihr seht ja auch auf der Folie,
diese Update Expression, die ist optional da oben,
die muss da nicht stehen.
Also ist das hier auch legaler Code. Ich kann das
also übersetzen, lässt sich übersetzen. Das ist deutlich,
also im Sinne von des Verständnisses,
des Verständnisses ist das klarer, was hier passiert,
weil ihr tatsächlich dieses Erhöhen am Ende des Schleifenrumfes passiert
Ja, ist also in dem Sinne lesbarer. Das ist
eine Frage. Könnte man nicht auch das System Outprint-Line,
zusammen mit dem Frissi, in die Vorerscheinung oben reinschreiben?
Kommt ein ganz großartiger Vorschlag? Man könnte doch dieses System Outprint-Line
da oben mit reinschreiben. Das ist so ziemlich das,
was ich auf gar keinen Fall sehen will in irgendwelchen realistischen Code.
Man sollte schon einen Blick haben, was gehört zum Schleifenrumpf und das
kann halt durchaus auch noch mal eine Anweisung mehr sein.
Dieses möglichst knapp die Dinge zusammenzufassen in eine Zeile
ist selten erstrebenswert
Das ist so eine verhängnisvolle Tendenz von der C-Welt.
Die C-Programmierer lieben das, möglichst kompakten Code zu schreiben.
Man kann vermutlich wirklich das System outprinten,
da jetzt nach oben irgendwie mit reinquetschen.
Aber dann würde man wahrscheinlich das I hier auch gleich mit erhöhen,
ja, so irgendwie mitten im Ausdruck.
Sowas wollen wir aber. Ja, hinterher können wir es
auch noch machen, genau. Das sind die ganzen Spezialan Ideen
jetzt hier. Das ist nicht wirklich Sinn, weiterführend.
Das hier macht zumindest klar, dass diese Erhöhung wirklich
am Ende des Schleifenraums passiert.
Ja, gut. Endlosschleifen. Gut, kann man auch
programmieren in Java. Man kann schreiben, Wild True,
denn solange True gilt, soll es ausgeführt werden,
dann wird es eben halt endlos gemacht, weil True gilt immer.
Oder man kann auch hier die Vorschleife so hinschreiben mit
so zwei Simikola. Schön ist auch Apple,
die haben ja tatsächlich in ihrer Karten-App auf ihrem iPhone,
haben sie dann dieses kleine Symbol.
Und da sieht man auch seine Kartenausschnitte,
das ist ein Original-Kartenausschnitt von der Gegend da in Kalifornien.
Und die haben als Adresse,
haben die Infinite Loop One
Das fanden sie wohl besonders lustig, dass sie ihre Straßen so genannt haben.
Na gut, für Betriebssysteme macht das ja Sinn,
weil Betriebssysteme sind ja quasi Endplus-Schleifen,
die immer wieder Anweisungen entgegennehmen, verarbeiten und so weiter.
Ja, so, Endlosschleifen. Sehr schön. Da sind wir jetzt noch,
naja, wir haben ja ungefähr zehn Minuten, das ist ganz gut.
Das ist ein bisschen knapp, aber ich glaube,
wir werden nochmal, ich werde nochmal so ein paar Begriffe jetzt einführen,
die ich eben auch schon genannt habe.
Und wie gesagt, lasst mir noch ein bisschen Zeit,
sondern wir mindestens bis zehn vor,
dass ich hier nochmal eben diese Dinge kurz einführen kann.
Was ihr, wenn ihr bisher programmiert habt,
schon relativ viel gemerkt habe, ist, dass ihr Zeiten habt,
in denen ihr vorm Rechner sitzt und über das Programm nachdenkt.
Und dann gibt es Zeiten, in denen ihr das Programm
ausführt und seht, was es denn wirklich tut.
Das sind zwei Begriffe, die für uns sehr wichtig sind,
die beim Programmieren allgemein sehr wichtig sind, nämlich Laufzeit- und Übersetzungszeit.
Und die Übersetzungszeit, das ist nicht die Zeit,
die der Compiler braucht, um euer Programm zu übersetzen.
Das ist ein häufig anzutreffendes Missverständnis. Darum geht es nicht,
sondern es geht darum, wenn man auf den Quelltext drauf schaut,
also ich sehe jetzt hier Quelltext vor mir,
kann ich hier bestimmte Aussagen treffen.
Zum Beispiel kann ich hier sagen, dieses I,
das ist nur innerhalb von diesem Rot gemarkierten Block sichtbar,
überhaupt nur da zugreifbar.
Das heißt, ich kann aber auch sagen, welche Syntaxregeln gelten denn hier?
Welche Sichtbarkeitsregeln? Wie ist der Quelltext strukturiert?
Ist er lesbar? Ist das gut kommentiert? Das sind
alles so Eigenschaften, die kann ich durch draufschauen sehen.
Das sind alles Fragen, die man zur Übersetzungszeit beantworten kann.
Und demgegenüber steht die Laufzeit und das ist halt die Zeit,
in der das Programm wirklich ausgeführt wird.
Und oft können Fragen erst zur Laufzeit beantwortet werden.
Also zum Beispiel, was macht das Programm eigentlich wirklich
Lässt sich meistens erst zur Laufzeit sagen,
weil die Programme häufig auch von Eingaben abhängen.
Aber man weiß zum Beispiel auch nicht,
wie viele Objekte erzeugt werden von einer bestimmten Klasse.
Das kann ja zur Laufzeit sehr unterschiedlich sein.
Je nachdem, wie das Programm benutzt wird.
Welche Lebensdauer haben die Objekte? Ihr wisst auch ein Objekt,
das nicht mehr benutzt wird, wo man keine Referenz mehr darauf hat.
Das lebt nicht mehr. Das ist eben halt dann auch
teilweise sehr unterschiedlich. Gut, welche Methoden werden aufgerufen?
Welche Daten werden manifestiert? Man kann sich das
auch nochmal bezogen auf lokale Variable überlegen
Also, was wissen wir zu Übersetzungszeit über eine lokale Variable?
Naja, wir gucken nur auf den Quelltext und wissen,
die hat einen Namen, die hat einen Typ und die hat eine Sichtbarkeit.
Das heißt also, man sieht zum Beispiel in einer
lokalen Variable, die ist nur innerhalb ihrer Methode sichtbar.
Und zur Laufzeit wissen wir aber nur, kennen wir erst ihre Belegung.
Wir wissen also gar nicht, mit welchen Werten die Variable belegt ist,
weil das kann man ja erst bei der Laufzeit feststellen.
Wie lange sie leben wird, auch sowas wie ihre Adresse,
wo steht es dem Speicher auch, das ist erst etwas,
was man zur Laufzeit weiß, was man auch vielleicht nicht wissen will,
aber das ist eben halt garantiert dann erst ermittelbar.
Weiteres Beispiel für einen Unterschied ist das hier?
Die Return-Anweisung ist immer die letzte Anweisung in einer Methode
Das ist richtig, aber was ist dann zum Beispiel mit sowas hier?
Ich habe hier eine Methode Max, die liefert,
kriegt zwei Parameter und soll irgendwie das Maximum zurückliefern.
Dann schiebt man hier Return R und Return B,
da ist die Return-Anweisung nicht die letzte Anweisung im Quelltext.
Aber es ist natürlich gemein zur Laufzeit,
ist die Return-Anweisung immer die letzte Anweisung einer Methode.
Das heißt, wenn das ausgeführt wird, weiß man einfach,
sobald das Return ausgeführt ist, ist die Methode zu Ende.
Das geht halt hier einfach ein bisschen auseinander.
Statisch sieht man da irgendwie mehrere Return-Anweisungen, da sieht man,
das ist irgendwie Die letzte Anweisung ist hier eigentlich dieses Return.
Das ist einfach von der statischen Ordnung des Programmes.
Und man könnte jetzt zur besseren Lesbarkeit das auch wieder ein bisschen zusammenführen und sagen,
naja, man diktariert sich die lokale Variable und macht das dann hier so,
dass man sagt, hier in Max,
dann wird hier irgendwie Max ermittelt und am Ende sagt man,
ich liefere Max an, passt auch wieder genau die statische Sicht zur dynamischen Sicht.
Also das ist dann die statisch letzte Anweisung und es
ist aber auch dynamisch immer sowieso die letzte Anweisung.
Okay, dann Sichtbarkeitsbereich, das ist einfach der Bereich im
Quelltext,
an dem
einen bezahlt
Zeichner üblicherweise sichtbar ist. Das heißt, wir haben das
jetzt hier schon gesehen. Dieses I zum Beispiel ist nur
innerhalb des roten Blockes sichtbar, die ja genauso schleifen.
Ihr werdet auch in den Übungen mehrere verschiedene Schleifen sehen.
Da werdet ihr auch sehen, man kann Schleifen rauf und runter
zählen. Man kann diese Vorschleifen nicht nur in einer Schritten
erhöhen oder dekrementieren, sondern auch in größeren Schritten.
Hier mit irgendwie Dreierschritten oder ähnliches. Aber man sieht hier auch nochmal Beispiele,
zum Beispiel hier diese Variable C ist innerhalb der Vorschleife
sichtbar und danach ist sie schon wieder nicht mehr sichtbar.
Und hier ist eine neue Variable C,
die ist dann bis zum Ende dieses Blocks
hier sichtbar
Das ist also die Sichtbarkeit. Und das ist etwas,
was man statisch entscheiden kann. Ich gucke auf den Quertext
und weiß einfach, wenn ich die Regeln der Sprache kenne,
diese Variable ist von hier bis dahin sichtbar.
Das gilt zum einen für Methoden, klar, lokale Variablen,
nur Methoden rum sichtbar. Und außerdem wisst ihr auch,
dass man eine Methode innerhalb einer Klasse überall sehen kann.
Also es ist tatsächlich so, hier sind jetzt mehrere Methoden
drin und die können sich alle beliebig gegenseitig aufrufen.
Das heißt, die sind simultan sichtbar. Es gibt also keine lineare Sichtbarkeit,
es ist also nicht so, dass ich jetzt hier einfach,
weil die eine textuelle Reihenfolge diese Methoden in der Klasse stehen,
dass ich deswegen nur die Methoden in den unteren Methoden,
die oberen Methoden aufrufen kann.
Das ist nicht der Fall. Man können sich beliebig gegenseitig
aufrufen, die sehen sich alle gleichzeitig. Also die Sichtbarkeit
dieser Methoden innerhalb einer Klasse. Man sieht aber auch,
hier sind jetzt zum Beispiel einige Public-Methoden, hier sind eigentlich
alle Public, die sind dann auch für Klienten sichtbar.
Private Methoden sind nur innerhalb einer Methode einer Klasse sichtbar.
Gut, die Exemplarvariablen sind in allen Methoden sichtbar,
wenn sie denn Private sind, wenn sie Public sind,
sind sie natürlich auch für Klienten sichtbar,
dass man mit dem Allgemeinen nicht haben.
Sichtbarkeitsbereiche von Klassen und Methoden
sind ineinander geschachtelt
Hier ist nochmal ein Beispiel. Das ist ein Beispiel für die sogenannte Überdeckung,
oder das war eben schon die Frage, die da kam.
Hier haben wir eine Klasse Test, die macht nichts Sinnvolles.
Das ist jetzt wieder reine Technik, die wir uns hier angucken.
Manchmal ist es leider so, dass wir da keine guten Beispiele dann haben.
Das ist also nichts, was jetzt irgendwie sinnvoll ist,
aber wir sehen hier einfach von den Sprachregeln, hier ist eine Exemplarvariable in X.
Was fällt euch als erstes auf an dieser Exemplarvariablen?
Ich möchte Proteststürme hören. Kein Unterstrich, genau. Das
ist ja ganz schrecklich. Das ist aber hier natürlich Absicht,
weil wir zeigen wollten, dass ich dann eine Methode haben kann,
Start, die hat, die ruft zwei weitere Methoden auf,
M1 und M2, das sind hier die beiden Methoden,
die sind privat, also nur Public gehört zur Schnittstelle von Test.
Und M1 und M2 sind private Methoden. Und hier sehen wir jetzt,
hier wird eine Variable X deklariert, innerhalb der Methode M1.
Und deswegen kann ich hier diesem X 1,5 zuweisen.
Das könnte ich zum Beispiel hier unten nicht hinschreiben,
denn hier, dieses X greift auf die Exemplarvariable zu.
In dieser Methode ist ein weiteres X deklariert und dieses X
verdeckt dieses X, was hier als Exemplarvariable deklariert ist
Dieses Verdecken ist in Java nur möglich zwischen lokalen Variablen und Exemplarvariablen.
Ihr könnt nicht innerhalb einer Methode mehrere Blöcke schachteln und in
einem geschatteten Block ein weiteres X-Deklavieren.
Das geht einfach nicht. Ich habe das hier auch nochmal
ein Beispiel Sichtbarkeit an Lebensdauer. Das ist genau dieses Beispiel hier.
Also ganz genau dieses Beispiel. Wenn ich jetzt hier Einfach mal
dieses X wegnehme, das X hier nicht mehr deklariere.
Und dann sage X ist gleich 1.5, dann gibt es einen Fehler,
weil natürlich 1.5 ein Double-Literal ist, hat also einen Typ Double.
Und das kann ich der Variante und X nicht zuweisen.
Weil X vom Typ Int ist,
das ist ein possible Loss of Precision,
wenn ich das jetzt übersetze, dann kommt hier genau diese Fehlermeldung.
Das geht aber wieder, wenn ich dann hier das X deklariere,
weil dann ich ein neues X lokal hier deklariert habe und
das jetzt hier auch mit einem Double zugewiesen werden kann.
Ja, das sind also dann hier nochmal diese Geschichten,
dass das da überwiesen, überdeckt wird.
Dieses Überdecken ist selten sinnvoll. In anderen Sprachen kann man
das durchaus machen, also zum Beispiel in CPUS-Bus,
kann man auch in lokal geschachtelten Blöcken immer wieder weitere Eas definieren.
Und das ist selten sinnvoll, macht nicht wirklich viel Sinn.
Deswegen auch unsere Quelltextkonvention, wenn ihr eure Exemplarvarianten immer mit einem Unterstrich benennt,
dann kommt ihr gar nicht in diese Problematik rein.
Aber selbst wenn man das macht,
kann man trotzdem noch Fehler machen, hier noch ein letztes Beispiel,
die Nummernanzeige hier, die Uhrenanzeige,
kennt ihr vielleicht noch,
mit diesen beiden Exemplarvariablen Nummernanzeige
Im Konstruktor möchte ich jetzt eigentlich meine beiden Exemplarvariablen initialisieren.
Aber aus Versehen hat dann jemand hier noch den Typ wieder davor geschrieben.
Dann werden hier lokal die beiden Variablen unterstrichstunden,
unterstrich Minuten als lokale Variablen deklariert im Konstruktor.
Und damit werden diese Exemplarvarianten überhaupt nicht verändert,
sondern hier wird einfach nur, wenn die lokalen Variablen initialisiert.
Und richtigerweise müsste man es dann so schreiben.
Also tatsächlich hier diese Dings nicht mit davor schreiben. Okay,
Sichtbarkeit, Lebensdauer muss ich nächstes Mal noch was zu sagen.
Kommt nächste Woche noch was. Sorry für die
heute,