- JAVA Control-Flow-Statements | Overview
- Control-Flow-Statements | for-Schleife
- Control-Flow-Statements | Laufvariable
- Control-Flow-Statements | Initalisierungsblock
- Control-Flow-Statements | Bedingungsblock
- Control-Flow-Statements | After-Loop-Block
- Control-Flow-Statements | Initalisierungsblock
- Control-Flow-Statements | while-Schleife
- Control-Flow-Statements | do-while-Schleife
- Control-Flow-Statements | if-elseif-else
- Control-Flow-Statements | if-elseif-else (Kurznotation)
- Control-Flow-Statements | switch
- Control-Flow-Statements | switch(int)
- Control-Flow-Statements | switch(enumKey)
- Control-Flow-Statements | switch
- Control-Flow-Statements | Dispatch über Maps
- Control-Flow-Statements | Branching-Statements
- Control-Flow-Statements | break
- Control-Flow-Statements | continue
- Control-Flow-Statements | Schleifen mit Labels
- Control-Flow-Statements | for-in-Schleife
- Control-Flow-Statements | switch-Expressions (Java 14)
- Control-Flow-Statements | Branching in Streams
JAVA-A1
Intro
JAVA Technologie vs. JAVA Sprache
Objektorientierung (Prinzip)
Basics
Variables
Primitive Typen
Wrapper
Operators
Rechenoperatoren
instanceOf Operator
Operators
a=b?c:d;
Control-Flow-Statements
for
Laufvariable
Init
Conditions
Increment
After
Beispiele zu for(;;)
do-while
if-elseif-else
else if
else
Beispiele zur Fallunterscheidung
if/else if/else in Kurznotation
switch
switch(int)
switch(String)
switch(enum)
switch(obj)
Dispatch via Maps (Ausblick/Example)
Branching-Statements
break
continue
Schleifen mit Labels
Erweiterte for-Schleife für Collections
Switch Expressions (JEP 361, Java 14) mit yield und Arrow-Notation
Branching in Streams @! verschieben zu C2!
Arrays
Arrays
Array-Literale zur Initalisierung
Multi-Dimensional-Array
Bracket-Array
JaggedArray-Array
3D-Array als Matrix
3D-Jagged-Array
Arrays in String-Darstellung ausgeben
Overview
JAVA Control-Flow-Statements | Overview
Mit Hilfe von Control-Flow-Statements oder Kontrollfluss-Ausdrücken ist es möglich, den Programmverlauf einem Programm auch in JAVA steuern zu können. Neben den üblichen Typen für Schleifen und Fallunterscheidungen, wie es diese auch in anderen Sprachen gibt, gibt es für viele dieser Varianten aber für die eigentliche Praxis später Varianten über Collection-Klassen, Stream-API und Funktionale Programmierung.
Das Verständnis der verschiedenen grundlegenden Control-Flow-Mechanismen wie kopf- oder fußgesteuerte Schleife, Prüfung von Bedingungen, Fail-Fast-Pattern sind als Grundlage für Aufbauthemen deshalb unverzichtbar.
for-Schleife
Control-Flow-Statements | for-Schleife
Eine typische for-Schleife
in JAVA besteht aus im Kopf der Schleife aus drei Bestandteilen:
Einem Block mit der Initialisierung, einem zweiten Block
mit Bedingungen und einem dritten Block welcher nach jeder
Schleife durchgeführt.
In diesem Beispiel zeigen wir, wie man einen Array mit Hilfe einer for-Schleife durchläuft.
Laufvariable
Bei einer Laufvariable handelt es sich im Kontext von Schleifen in JAVA und anderen Programmiersprachen um eine Variable, welche in jedem Durchlauf der Schleife verändert wird.
Laufvariablen heißen üblicherweise i,
j oder k.
Man beginnt üblicherweise bei der innersten Schleife mit i
und nutzt bei einer Verschachtelung von Schleifen dann die forlaufenden
Buchstaben als Bezeichner.
Initialisierungsblock
Der Initialisierungsblock kann int i=0;
beinhalten, muss es aber genau genommen nicht. Alle innerhalb einer
for-Schleife verwendeten Variablen müssen zuvor deklariert worden sein,
aber das kann auch vor der for-Schleife und damit außerhalb
erfolgt sein.
Dieser Block darf auch mehrere Variablen durch Komma separiert initialisieren..
Der Block kann also auch komplett leer sein, muss aber zwingend mit einem einzigen Semikolon abgeschlossen werden.
0, 1 bis n Bedingungen
Der zweite Block im Kopf einer for-Schleife beinhaltet die Fortsetzungsbedingungen. Nur alle alle Fortsetzungenbedingungen erfüllt sind, wird die Schleife ein weiteres Mal oder zu Beginn überhaupt ein erstes Mal durchgeführt.
Dieser Block endet immer mit einem ; Semikolon
und wird oftmals mit einem Konstrukt wie im Falle von Arrays mit
i<arr.length gefüllt. Abbruchung
After-Loop-Block
Nach jedem einzelnen Durchlauf der Schleife wird ein dritter Block
ausgeführt. Dieser Block wird zumeist dafür genutzt, die Laufvariable
wie i beispielsweise um +1 über
i++ oder i=i+1
zu erhöhen.
Auch dieser Block kann mehrere Anweisungen durch Komma separiert beinhalten, muss aber mit einem Semikolon abgeschlossen werden.
Beispiele für for-Schleifen
Zahlen von 0 bis 9
for(int i=0; i < 10; i++) {
System.out.println(i);
}
Das Komma separtiert die zwei Variablen
Das Beispiel zeigt, wie man eine Variable s
als zweite Variable deklarieren und initialisieren kann, um beispielweise
die Gesamtsumme einer Zahlen von 0 bis einschließlich 9 ermitteln zu können.
Da diese Variablen allerdings innerhalb der for-Schleife deklariert wurden,
hat die Variable s außerhalb der Schleife
keine Gültigkeit mehr.
Die Variable s verliert als mit der
abschließenden Klammer ihre Gültigkeit.
for(int i=0, s=0; i < 10; i++) { // {#1}
s += i;
System.out.println(s);
} // {#2}
System.out.println(s); // {#3} FEHLER!
Fehlende oder nicht eintretende Abbruchbedingung
Ob gewollt oder ungewollt: Endlosschleifen entstehen immer dann, wenn die
Bedingung in {#1} immer erfüllt ist und
damit die Schleife über die Bedingung(en) im Kopf niemals abgebrochen
werden wird.
Ohne eine Abbruchbedingung
{#3} innerhalb der Schleife mit einer
zugehörigen break Anweisung
wird das Programm endlos ausgeführt bis es vom Anwender
über das Betriebssystem abgebrochen oder der Rechner ausgeschaltet wird.
for(i=0;i>0;i++) { // {#1}
System.out.println(i); // {#2}
if(i>=100) { break; } // {#3}
}
// {#4}
Schleifen im Multithreading
Es gibt Fälle, in denen eine for-Schleife als Dauerschleife explizit gewünscht ist.
So wird im Falle von run-Methoden von
Threads oder
Runnables
die run-Methode oft als Dauerschleife
implementiert. Das gilt auch sinngemäß für
Callables.
Die Abbruchbedingung wird hierbei außerhalb der for-Schleife und auch außerhalb der run-Methode gesetzt.
Threads sind ein eigenständiger Themenblock im Bereich Parallel Computing.
public void run() {
int zaehler=0;
for(;;) { // {#1}
synchronized(Programm.sollAbbrechen) {
if(Programm.sollAbbrechen) { break; }
}
System.out.println("Tick "+zaehler++);
Thread.sleep(1000); // {#2}
}
// {#4}
}
package com.stuelken.java.a1.basics.arrays;
// @formatter:off
/**
* A1-e01: Einfaches primitiver int[]-Array.
* - Erzeugen
* - Lesen
* - Ändern
* - Durchlaufen
<pre>
nums[1] = 20
Alle Werte: 10, 20, 30
</pre>
*/
// @formatter:on
public class Array01Int {
public static void main(String[] args) {
// Erzeugen
int[] nums = new int[3];
nums[0] = 10;
nums[1] = 20;
nums[2] = 30;
// Lesen
System.out.println("nums[1] = " + nums[1]);
// Durchlaufen
System.out.print("Alle Werte: ");
for (int i = 0; i < nums.length; i++) {
System.out.print(nums[i] + (i < nums.length - 1 ? ", " : ""));
}
System.out.println();
}
}
Deklaration von Variablen
Um einen Array in einer Variablen speichern zu können,
ist eine Variable mit einem Bezeichner wie hier
«num» erforderlich. Maßgebend
ist aber auch eine Typisierung mit int[]
mit Angabe des Typs gefolgt von zwecke eckigen Klammern.
Dimensionieren und Speicherplatz reservieren
Der für Arrays erforderliche Speicherplatz wird in JAVA sowie C# und C++ (im Gegensatz zu Sprachen wie PHP oder JS) bei der Erzeugung des Array-Objekts als Wert einmal dimensioniert und lässt sich anschließend nicht mehr ändern.
Eine Adressierung von Feldern eines Array ist also erst möglich, wenn Speicherplatz im Arbeitsspeicher angelegt und hierfür für die gewünsche Anzahl von Feldern im Array reserviert wurde.
length
Die Anzahl der Elemente, die ein Array hat,
lässt sich über .length
an der Variablen mit dem Array adressieren.
Auch dann, wir hier einen Array mit 3 Feldern für die Indizes 0 bis 2 anlegen, können die eigentlichen Werte für die jeweiligen Felder dennoch quasi leer sein, wobei bei int-Werte dann das Feld den Wert 0 hat, bei Objekten hinzegen null.
Klassische for-Schleife mit Zugriff über Index
Schleifen werden im Themenblock Kontrollfluss erläutert.
Auch dann, wir hier einen Array mit 3 Feldern für die Indizes 0 bis 2 anlegen, können die eigentlichen Werte für die jeweiligen Felder dennoch quasi leer sein, wobei bei int-Werte dann das Feld den Wert 0 hat, bei Objekten hinzegen null.
JavaDoc und Eclipse: Vermeiden der Auto-Formatierung
Zur Vermeidung, dass das Code-Sample im <pre>..</pre>
Tags bei bei Code-Format in der
Eclipse-IDE
von mehreren Zeilen in Fließtext umgewandelt wird, lässt sich mit
// @formatter:off
die Formatierung abschalten und später mit on
wieder anschalten.
while-Schleife
Control-Flow-Statements | while-Schleife
Eine while-Schleife
ist eine kopfgesteuerte Schleife welche vor der Ausführung
einer Schleife stets prüft, ob die Bedingung erfüllt ist.
Fehlt diese Bedingung so ist diese automatisch erfüllt, so dass
die while() { } zu einer
Dauerschleife mutiert.
int counter = 0;
while(counter <= 10) {
// A
System.out.println(counter);
counter++;
if(counter==5) { continue; }
}
do-while-Schleife
Control-Flow-Statements | do-while-Schleife
Eine do-while-Schleife
ist eine fußgesteuerte Schleife. Sie wird mindestens
einmal ausgeführt, weil die zugehörige Bedingungsprüfung
erst nach einem ersten Durchlauf erfolgt.
Die do-while-Schleife in vielen Ausbildungen Prüfungsstoff, weil man erwartet, dass jeder Entwickler den Unterschied zwischen kopf- und fußgesteuerten Schleifen kennt, auch wenn gefühlt 99,99995 aller Entwickler immer kopfgesteuerte Schleifen nutzen.
int i = 0;
do {
System.out.println(i);
i++;
} while (i<10);
if-elseif-else
Control-Flow-Statements | if-elseif-else
Ein if-elseif-else-Block ermöglicht
Fallunterscheidungen.
Es muss zwingend immer einen if Block
geben. Es kann 0 bis n else-if Blöcke
und 0 bis 1 abschließenden else
Block geben.
for (int i=0; i<10; i++) {
if(i%2==0 && i%3==0) {
System.out.println("Die Zahl i="+i+" ist gerade und durch 3 teilbar. ");
} elseif (i%5==0) {
System.out.println("Die Zahl i="+i+" ist durch 5 teilbar.");
} elseif (i%7==0) {
System.out.println("Die Zahl i="+i+" ist durch 7 teilbar.");
} else {
System.out.println("Die Zahl erfuellt keines der bisherigen Kriterien.");
}
}
if-Kurznotation
Wenn der Programmcode je Block nur eine Zeile hat, darf formal betrachtet die geschweiften Klammern weglassen. Während die einen finden, dass der Code so leserlicher wird, vermissen andere für die Verbesserung der Lesbarkeit die Klammern.
Das Problem hierbei: Zu welchem Block zählt hier eigentlich der else-Zweig?
In Java bindet ein else immer zur nächstgelegenen, ungeschlossenen if-Anweisung. Fehlen geschweifte Klammern, steuert ein if nur exakt die unmittelbar folgende Anweisung; und nicht den eingerückten Block, den man optisch vielleicht erwartet.
Merke: Die Einrückung ist eine Code-Kosmetik und spielt für den Compiler, anders als bei Python, keine Rolle.
// "Schlank"
if (aNumber >= 0)
if (aNumber == 0)
System.out.println("first string");
else System.out.println("second string"); // {#3] Verwirrend eingerückt!
// "Vollständig"
if (aNumber >= 0) {
if (aNumber == 0) {
System.out.println("first string");
} else {
System.out.println("second string");
}
System.out.println("third string");
}
System.out.println("forth string");
switch
Control-Flow-Statements | switch
Mit switch,
case,
break
und
default
lassen sich alternativ zu if/elseif/else-Statements
auch Fallunterscheidungen programmieren.
Maßgebend zum Verständnis ist hierbei, dass die Variable,
auf die auf Überstimmungen in den mit case
definierten Bedinungen geprüft wird, innerhalb der Klammern
des switch(..) Kopfes
geprüft werden wird.
Trifft die Bedinungen in einem
case Block
im Sinne von case==fall
zu, so wird der Programmcode ausgeführt, welcher
nach dem case Element
zu finden ist.
Mit diesem Verfahren ist es möglich, dass mehrere Fälle zur gleichen Code-Ausführung führen können, so dass bei Konsolen-Parametern beispielsweise oftmals eine Kurz- und eine Langfassung üblich ist.
Der break; Ausdruck
bewirkt, dass der nach einem case
ausgeführte Code an dieser Stelle abgebrochen
und das Programm nach dem switch
Block fortgesetzt wird. Das Vergessen von diesen
break; Zeilen ist
eine der größten Fehlerquellen bei Einsteigern.
Der default: Block
ist der letzte Block innerhalb eines switch
Blocks und optional, dh. man kann diesen auch weglassen. Dieser
letzte Block dient dazu, dass switch stets
einen Wert kontrolliert liefert oder einen Block ausführt, auch wenn
sonst kein einziger Fall als case
zutrifft.
// Gültig ab Java 7
String fall="--port";
switch(fall) {
case "-p":
case "--port":
System.out.println("Port-Parameter erkannt!");
break;
case "-h":
case "--help":
default:
System.out.println("-p, --port: Port");
}
switch(intZahl) { }
switch(..)
lässt sich mit int-Zahlen verwenden.
Das gilt auch für byte,
short,
char und deren
Wrapper-Klassen.
int zahl = 2;
switch (zahl) {
case 1:
System.out.println("Eins");
break;
case 2:
System.out.println("Zwei");
break;
default:
System.out.println("Andere Zahl");
}
Nicht unterstützt werden long, float, double und boolean.
switch(enumKey) { }
switch(..)
lässt sich mit Enumerationskonstanten ab Java 5 verwenden.
enum Tag { MONTAG, DIENSTAG }
Tag tag = Tag.MONTAG;
switch (tag) {
case MONTAG:
System.out.println("Erster Werktag");
break;
case DIENSTAG:
System.out.println("Zweiter Werktag");
break;
}
switch(obj) { }
switch(..)
ermöglicht KEINE Unterstützung von Referenztypen mit
Ausnahme von Enumerationen und Strings.
package com.stuelken.java.a1.basics.e30.switchstring;
/**
*
* @author t2m
*/
public class SwitchStringExample {
/**
* Ruft {@link SwitchStringExample#main(String[])}.
* @param run Keine Parameter
*/
public static void main(String[] run) {
String text = (new SwitchStringExample()).test();
System.out.println(text);
}
/**
* Liefert Erläuterungstest für einen Befehl wie
* "START" und "Beginne Prozess".
*
* @return Erläuterungstext.
*/
public String test() {
String befehl = "START";
String text = "";
switch (befehl) {
case "START":
text = "Beginne Prozess";
break;
case "STOP":
text = "Beende Prozess";
break;
default:
text = "Unbekannter Befehl";
}
return text;
}
}
// Beginne Prozess
Wer Objekte auf Gleichheit prüfen möchte, muss auf deren Eigenschaften oder ggf. den Hashcode prüfen.
enum Status { OPEN, CLOSED, PENDING }
class Ticket {
Status status;
// Konstruktor, Getter…
}
Ticket t = new Ticket(Status.OPEN);
switch (t.getStatus()) {
case OPEN:
System.out.println("Ticket offen");
break;
case CLOSED:
System.out.println("Ticket geschlossen");
break;
default:
System.out.println("Anderer Status");
}
Dispatch über Maps
Control-Flow-Statements | Dispatch über Maps
Im Zuge des Ausbaus der JAVA Collection API um Streams setzen viele Entwickler bei Schleifen und dem Prüfen von Bedingungen nicht mehr auf die eigentlichen Grundlagen wie auch switch sondern auf Collection Klassen in Verbindung mit .stream() und anderen Alternativen. Ein Grundverständnis der Basics ist aber weiterhin zwingend erforderlich.
Hinweis: Die Voraussetzung für das Arbeiten mit Collections ist ein tieferes Verständnis der Objektorientierung, der generischen Programmierung sowie des Prinzips von Interfaces, so dass Collections und Schleifen über Streams erst in späteren Themenblocken erklärt werden.
Klasse für Objekte
Um Objekte vergleichen zu können, benötigen wir zu Beginn eine zugehörige Klasse.
package com.stuelken.java.a1.basics.e34.switchmapcollectionstream;
/**
* Eine Klasse welche {@link Vehicle} Objekte anhand
* von {@link VehicleType} Enumerationen unterscheiden kann.
*
* Diese Klasse dient nur als Beispiel
*
* @author t2m
*/
class Vehicle {
private final VehicleType type;
private final double weight;
private final double trailerWeight; // nur für LKW relevant
public Vehicle(VehicleType type, double weight, double trailerWeight) {
this.type = type;
this.weight = weight;
this.trailerWeight = trailerWeight;
}
public VehicleType getType() {
return type;
}
public double getWeight() {
return weight;
}
public double getTrailerWeight() {
return trailerWeight;
}
}
Berechnung der Nutzlast
Daa Programm ermittelt die gesamte Nutzlast aller Fahrzeuge.
package com.stuelken.java.a1.basics.e34.switchmapcollectionstream;
import java.util.List;
public class SwitchMapCollectionStreamExample {
public static void main(String[] args) {
List<Vehicle> fleet = List.of(
new Vehicle(VehicleType.CAR, 1500, 0),
new Vehicle(VehicleType.TRUCK, 8000, 2000),
new Vehicle(VehicleType.MOTORCYCLE, 200, 0),
new Vehicle(VehicleType.TRUCK, 9000, 2500));
double totalLoad = VehicleAggregator.computeTotalLoad(fleet);
System.out.printf("Gesamte Nutzlast der Flotte: %.2f kg\n", totalLoad);
}
}
package com.stuelken.java.a1.basics.e34.switchmapcollectionstream;
import java.util.Collection;
public class VehicleAggregator {
/**
* Berechnet die gesamte Nutzlast aller Fahrzeuge. - CAR : nur Eigengewicht -
* TRUCK : Eigengewicht + Anhängergewicht - MOTORCYCLE: nur Eigengewicht
*/
public static double computeTotalLoad(Collection<Vehicle> vehicles) {
return vehicles // Collection
.stream() // Stream<Vehicle> mit Vehicle Objekten
.mapToDouble(v -> {
switch (v.getType()) {
case CAR:
return v.getWeight();
case TRUCK:
return v.getWeight() + v.getTrailerWeight();
case MOTORCYCLE:
return v.getWeight();
default:
return 0.0;
}
})
.sum(); // Aggregation eines Gesamtwerts
}
}
Branching-Statements
Control-Flow-Statements | Branching-Statements
Branching-Statements steuern den Programmfluss und unterbrechen die sequentielle Ausführung. Sie gehören zu den Control-Flow-Statements und damit NICHT zu den Scopes (Sichtbarkeitsbereich, Gültigkeitsbereich, Lebensdauer von Variablen) von Code-Blöcken.
Die wichtigsten Branching-Statements sind
sogenannte
bedingte Verzweigungen
wie if,
else if,
else,
switch,
case
mit default.
Sprung-Anweisungen sind mitunter
break,
continue,
return für Abbruch
oder Ende einer Methode sowie
sowie throw für das
Auslösen einer Exception.
JAVA unterstützt break label;
und continue label;.
Die herkömmlichen goto-Anweisungen, die man in der Frühzeit in anderen Programmiersprachen hatte, kennt man in Java nicht, da das auf Zeilennummern basierende Springen keinen Sinn mehr macht.
break
for (int i = 1; i <= 10; i++) {
if (i == 5) {
System.out.println("Abbruch bei i = " + i);
break; // verlässt die Schleife komplett
}
System.out.println(i);
}
// Ausgabe: 1 2 3 4 Abbruch bei i = 5
continue
for (int i = 1; i <= 5; i++) {
if (i % 2 == 0) {
continue; // überspringt den aktuellen Durchlauf
}
System.out.println(i);
}
// Ausgabe: 1 3 5
Schleifen mit Labels
// Äußere Schleife
outer:
for (int row = 1; row <= 3; row++) {
// Innere Schleife
inner:
for (int col = 1; col <= 3; col++) {
if (row == 2 && col == 2) {
System.out.println("Break outer bei 2,2");
break outer; // Springt aus beiden Schleifen heraus
}
System.out.printf("(%d,%d)%n", row, col);
}
}
Control-Flow-Statements | for-in-Schleife
Im Zusammenhang mit Collections gibt es weitere Schleifen. Diese lassen sich auch mit Arrays verwenden, indem Arrays in eine entsprechende Collection gewandelt wird.
HINWEIS: Collections sind ein eigener Themenblock.
Collection collection = new ArrayList();
...
for (ItemType item : collecion) {
...
}
Control-Flow-Statements | switch-Expressions (Java 14)
Switch-Expressions wurden mit Java 14 (JEP 361) endgültig in die Sprache aufgenommen.
Sie erweitern das klassische switch um zwei unabhängige Features: Die Pfeilnotation
mit dem Array-Operator -> statt dem
bisherigen : Doppelpunkt in Kombination
mit break;, so dass die Anzahl der vergessenen
break-Anweisungen in Zukunft keine Probleme
machen wird.
Arrow-Notation ohne Fall-Through: case A, B -> ...
lässt sich direkt für mehrere Konstanten abfragen, ohne dass man noch das vormalige
break; benötigt.
Switch als Expression: Damit ist jetzt switch direkt
ein Ausdruck und erzeugt direkt einen Rückgabewert, kann also innerhalb
einer anderen Anweisung verwendet werden.
yield liefert das Ergebnis eines switch-Ausdrucks
zurück, auch wenn wie bisher den Doppelpunkt nach dem case verwendet.
Beispiel
Day day = Day.WEDNESDAY;
String type = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> "Weekend";
case TUESDAY -> "Busy day";
default -> "Midweek";
};
System.out.println(type); // Midweek
Beispiel
int result = switch (day) {
case SATURDAY, SUNDAY -> {
System.out.println("Enjoy!");
yield 0;
}
default -> {
System.out.println("Work…");
yield 1;
}
};
System.out.println("result:"+result);
Control-Flow-Statements | Branching in Streams
Collections und Streams sind fortgeschrittene Themen. Ein Kurzeinblick ist aber auch im Einstieg deshalb sinnvoll, um bereits von Beginn an zu wissen, dass es die Programmsteuerung in anderer Form auch weiterhin in der Collection-Stream-API geben muss.
Hinweis: Dieses Beispiel gehört zur JAVA-C2 Ebene.
List<String> args = List.of("-p","8080","--name","Server42");
Map<String,String> params = IntStream.range(0, args.size()/2)
.mapToObj(i -> Map.entry(args.get(2*i), args.get(2*i+1)))
.collect(Collectors.toMap(
Map.Entry::getKey, Map.Entry::getValue,
(oldV,newV) -> newV, LinkedHashMap::new
));
String port = params.entrySet().stream()
.filter(e -> e.getKey().equals("-p") || e.getKey().equals("--port"))
.map(Map.Entry::getValue)
.findFirst()
.orElse("80");
FootNotes, Keywords, Tags
java/Callables, java/Eclipse-IDE, java/ParallelComputing, java/Runnables, java/Threads, java/Wrapper-Klassen
Hinweise, Rechte, Marken
UIO3 Es ist einfacher als Du denkst.
Stelle noch heute Deine Anfrage.
