Arbeiten mit Strings

  • Code
  • Erklärung
  • Ergebnis

import java.lang.String;
import java.lang.StringBuilder;

class JavaExample
{
    public static void main (String[] args)
    {
        String first = "Einfaches Beispiel ";
        String second = "von Strings.";
        String third = first + second;
        System.out.println(third);
        String fourth = first.concat(second);
        System.out.println(fourth);

        //Contains
        String s1 = "Das ist ein Beispiel Text.";
        String s2 = "ein";
        boolean exists = s1.contains(s2);
        System.out.println("'" + s1 + "' beinhaltet '" + s2 + "': " + exists);
        String s3 = "EIN";
        System.out.println("Das funktioniert leider nur, identischer Groß- & Kleinschreibung: " + s1.contains(s3));
        System.out.println("Aber es gibt einen Trick: " + s1.toUpperCase().contains(s3.toUpperCase()));
        //Substring
        System.out.println("'" + s1 + "' ab der Position 5 lautet: " + s1.substring(5));

        //Equals
        System.out.println("'" + s1 + "' und '" + s2 + "' ist gleich: " + s1.equals(s2));
        System.out.println("'" + s2 + "' und '" + s3 + "' ist gleich: " + s2.equals(s3));
        System.out.println("'" + s2 + "' und '" + s3 + "' ist gleich (Ohne Groß- & Kleinschreibung): " + s2.equalsIgnoreCase(s3));


        //Remove
        String s = "abc----hij";
        System.out.println("\nIndex: 0123456789");
        System.out.println("1)     " + s);
        System.out.println("2)     " + s.replace("-", ""));

        //ToUpper und ToLower
        String text = "EiN kaPUTter TeXt";
        System.out.println("Groß geschrieben: " + text.toUpperCase());
        System.out.println("Klein geschrieben: " + text.toLowerCase());

        //Trim
        String withSpaces = "     Leerzeichen Enthalten   ";
        System.out.println("Getrimmt: " + withSpaces.trim());

        // Caps Lock umdrehen mit dem StringBuilder.
        String wrong = "uNABSICHLICH cAPS lOCK eINGESCHALTET.";
        StringBuilder sb = new StringBuilder(wrong);

        for (int i = 0; i < sb.length(); i++)
        {
            if (Character.isLowerCase(sb.charAt(i))) 
                sb.setCharAt(i, Character.toUpperCase(sb.charAt(i)));
            else if (Character.isUpperCase(sb.charAt(i))) 
                sb.setCharAt(i, Character.toLowerCase(sb.charAt(i)));

            //Alternativ:
            //wenn true ? dann : sonst
            //sb.setCharAt(i, Character.isLowerCase(sb.charAt(i)) ? Character.toUpperCase(sb.charAt(i)) : Character.toLowerCase(sb.charAt(i)));
        }
        String correct = sb.toString();
        System.out.println("\nOriginal: " + wrong);
        System.out.println("Korrigiert: " + correct);
    }
}



Die String-Klasse ist eine der am häufigsten genutzten Klassen mit vielen Methoden und Verwendungsmöglichkeiten, weshalb wir ihr an dieser Stelle einen eigenen Bereich widmen.
Wie bereits in den Grundlagen beschrieben werden Strings wie gewöhnliche Variablen initialisiert und deklariert. Auch das Zusammenführen von mehreren Strings ist denkbar einfach. Hierzu wird einfach der + Operator verwendet um zwei String aneinander zu hängen. Wir möchten an dieser Stelle nur die wichtigsten Eigenschaften der Stringklasse erwähnen die man als angehender Entwickler kennen sollte. Für eine komplette Dokumentation verwende bitte die Java Dokumentation

Zu den wichtigsten Methoden des Stringklasse zählen:
  • Length (liefert die Länge des Strings)
  • Contains (liefert true oder false ob ein substring in einem String enthalten ist)
  • Substring (liefert einen Teilstring ab einer definierten Position)
  • Equals (liefert true oder false ob sich zwei Strings gleichen. Groß- und Kleinschreibung wird berücksichtigt)
  • Replace (entfernt der Rest eines Strings ab einer bestimmten Position oder eine Anzahl an Zeichen ab einer bestimmten Position)
  • ToUpperCase / ToLowerCase (Liefert den String groß oder klein geschrieben)
  • Trim (Entfernt Leerzeichen zu Beginn und Ende des gegebenen Strings)
Eine weitere Besonderheit bildet die StringBuilder Klasse die uns bei der Erstellung neuer Strings behilflich ist.
Da Die klassischen String-Methoden den ursprünglichen String unverändert lassen (Rückgabe dieser Methoden ist wieder ein neuer String) kann mit Hilfe des StringBuilders ein vorhandener String modifiziert werden.
In diesem Beispiel drehen wir die Groß-/Kleinschreibung einer Zeichenkette um. (import java.lang.StringBuilder; benötigt)

Klassen

  • Code
  • Erklärung
  • Ergebnis

//Car.java

public class Car
{
    //Instanzvariablen
    private String brand;
    private String model;
    private int power;
    private String color;

    //Konstruktor
    public Car(String s)
    {
        brand = s;
    }

    public void StartEngine()
    {
        System.out.println("Der " + brand + " faehrt los.");
    }

    //Eigenschaften
    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public int getPower() {
        return power;
    }

    public void setPower(int power) {
        this.power = power;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}


    
//Main-Datei

import java.lang.String;

class JavaExample
{
    public static void main(String[] args)
    {
        Car myCar = new Car("Mitsubishi");

        myCar.setColor("Schwarz");
        myCar.StartEngine();

        System.out.println("Die Farbe des Autos ist " + myCar.getColor());
    }
}



Bevor du dich mit dem folgenden Beispiel widmest, mache dich bitte mit dem Konzept von objektorientierter Programmierung vertraut. Ein klares Verständnis von Klassen ist für einen Programmierer unabdinglich. Einen passende Quelle bietet unser Artikel zu Objektorientierung.

Zu Beginn widmen wir uns der Instanziierung einer Klasse und die Verwendung ihrer Methoden.
In diesem Beispiel haben wir eine Klasse "Car" erstellt. Zu Beginn definieren wir einige Variablen die wir als private deklarieren. Den Zugriff auf diese Variablen ermöglichen wir über sogenannte getter und setter. Es ist empfohlen Klassenvariablen stets über deren Eigenschaftsmethoden erreichbar zu machen. Der Vorteil daran ist unter anderem, dass sich so leicht Prüfungen auf die Korrektheit der Werte implementieren lässt und der Zugriff klar gesteuert werden kann.

Jede Klasse besitzt von Haus aus einen Standardkonstruktor der uns unser Objekt instanziiert. Der Konstruktor besitzt keinen typischen Rückgabewert und muss immer den Klassennamen als Bezeichnung haben. In diesem Besipiel haben wir den Standardkonstruktor mit einem String-Parameter erweitert um zu gewährleisten, dass jedes Auto-Objekt zumindest einen Markennamen beinhaltet. Der Standardkonstruktor wird somit ersetzt und existiert nicht mehr.

Solltest du weiterhin einen Parameterlosen Konstruktor benötigen, muss dieser als public Car() {} implementiert werden. Zuletzt besitzt diese Klasse noch eine einfache Methode StartEngine() die eine Ausgabe in der Console veranlasst.

In unserer Main-Methode können wir nun mit dem Schlüsselwort new ein neues Car-Objekt erschaffen. Wir nennen es "myCar" und übergeben dem Konstruktor „Mitsubishi“ als Markennamen. Mit einem einfachen Punk können wir nun auf die Eigenschaften und Methoden unseres Objektes zugreifen.

Bitte beachte, dass du die in Java jedeKlasse in eine eigene .java Datei auslagern musst.

Vererbung

  • Code
  • Erklärung
  • Ergebnis

//Kfz.java

public abstract class Kfz
{
    //Klassenvariablen
    protected String brand;
    private String model;
    private int power;
    private String color;

    public void StartEngine()
    {
        System.out.println("Der " + brand + " faehrt los.");
    }

    //Eigenschaften
    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public int getPower() {
        return power;
    }

    public void setPower(int power) {
        this.power = power;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}



//Pkw.java

public class Pkw extends Kfz
{
    private int numDoors;

    public int getNumDoors() {
        return numDoors;
    }

    public void setNumDoors(int numDoors) {
        this.numDoors = numDoors;
    }

    public Pkw(String s)
    {
        brand = s;
    }

    public void StartEngine()
    {
        System.out.println("Der PKW " + brand + " startet.");
    }
}



//Lkw.java

public class Lkw extends Kfz
{
    private int maxWeight;

    public Lkw(String s) 
    {
        brand = s;
    }


    public int getMaxWeight() {
        return maxWeight;
    }


    public void setMaxWeight(int maxWeight) {
        this.maxWeight = maxWeight;
    }

    public void StartEngine()
    {
        System.out.println("Der LKW " + brand + " startet.");
    }
}



//Main-Datei

import java.lang.String;

class JavaExample
{
    public static void main(String[] args)
    {
        Pkw myPKW = new Pkw("Mitsubishi");
        Lkw myLKW = new Lkw("MAN");

        myPKW.setColor("Schwarz");
        myPKW.StartEngine();

        myLKW.setMaxWeight(50);
        myLKW.StartEngine();

        System.out.println("Die Farbe des PKW ist " + myPKW.getColor());
        System.out.println("Das maximale Gewicht des LKW ist " + myLKW.getMaxWeight() + " Tonnen.");
    }
}

Bevor du dich mit dem folgenden Beispiel widmest, mache dich bitte mit dem Konzept von objektorientierter Programmierung vertraut. Ein klares Verständnis von Klassen ist für einen Programmierer unabdinglich. Einen passende Quelle bietet unser Artikel zu Objektorientierung.

Für dieses Beispiel verwenden wir die Klasse von vorhin benennen sie aber in "Kfz" um.
Wir erweitern sie um das Schlüsselwort abstract um zu verhinden, dass ein Objekt vom Typ Kfz instanziiert werden kann. Wird eine Klasse als abstract markiert kann die Klasse nur von durch die Vererbung an eine andere Klasse verwendet werden.
Weiters haben wir in der Basisklasse die Methode StartEngine() als abstract markiert um zu erzwingen, dass jede erbende Klasse eine eigene Implementierung dieser Methode beinhaltet. Beachte, dass eine abstrakte Methode selbst keinen Inhalt hat sondern nur den Methodennamen und etwaige Paramter vorgibt.

Wie du siehst enthält jede erbende Klasse die Eigenschaften ihrer Basisklasse. Somit können wir die Farbe eines PKW aufrufen obwohl die PKW-Klasse selbst keine Implementierung beinhaltet. Somit lassen sich leicht gemeinsame Eigenschaften vom LKW und PKW in einer gemeinsamen Basisklasse implementieren.

Polymorphie

  • Code
  • Erklärung
  • Ergebnis

//Kfz.Java

public abstract class Kfz
{
    //Klassenvariablen
    protected String brand;
    private String model;
    private int power;
    private String color;

    public abstract void StartEngine();

    //Eigenschaften
    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public int getPower() {
        return power;
    }

    public void setPower(int power) {
        this.power = power;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}



//Pkw.java

public class Pkw extends Kfz
{
    private int numDoors;

    public int getNumDoors() {
        return numDoors;
    }

    public void setNumDoors(int numDoors) {
        this.numDoors = numDoors;
    }

    public Pkw(String s)
    {
        brand = s;
    }

    public void StartEngine()
    {
        System.out.println("Der PKW " + brand + " startet.");
    }
}



//Lkw.java

public class Lkw extends Kfz
{
    private int maxWeight;

    public Lkw(String s) 
    {
        brand = s;
    }


    public int getMaxWeight() {
        return maxWeight;
    }


    public void setMaxWeight(int maxWeight) {
        this.maxWeight = maxWeight;
    }

    public void StartEngine()
    {
        System.out.println("Der LKW " + brand + " startet.");
    }
}



//Motorrad.java

public class Motorrad extends Kfz
{
    private int maxGeschwindigkeit;

    public Motorrad(String s) {
        brand = s;
    }

    public int getMaxGeschwindigkeit() {
        return maxGeschwindigkeit;
    }

    public void setMaxGeschwindigkeit(int maxGeschwindigkeit) {
        this.maxGeschwindigkeit = maxGeschwindigkeit;
    }

    public void StartEngine() 
    {
        System.out.println("Das Motorrad " + brand + " startet.");
    }
}

//Main-Datei
class JavaExample
{
    public static void main(String[] args)
    {
        Kfz[] arr = new Kfz[3];

        arr[0] = new Pkw("Mitsubishi");
        arr[1] = new Lkw("MAN");
        arr[2] = new Motorrad("Yamaha");

        for(Kfz k : arr)
            k.StartEngine();
    }
}

Bevor du dich mit dem folgenden Beispiel widmest, mache dich bitte mit dem Konzept von objektorientierter Programmierung vertraut. Ein klares Verständnis von Klassen ist für einen Programmierer unabdinglich. Einen passende Quelle bietet unser Artikel zu Objektorientierung.

Die Polymorphie ermöglicht uns, dass Objekte gemeinsamer Basisklasse, je nach ihrer eigenen Implementierung, unterschiedlich auf den gleichen Befehl reagieren. Somit können wir, wie dem vorherigen Beispiel entsprechend, unterschiedliche Kfz-Objekte erstellen und gemeinsam ansprechen ohne dabei die konkrete Implementierung der einzelnen Klassen aufrufen zu müssen.

Wir verwenden wieder den Code des vorherigen Beispiels und erweitern ihn wie folgt:
Zuerst erstellen wir eine Motorradklasse die ebenfalls von Kfz erbt und eine eigene StartEngine() Implementierung hat.
Als nächstes befüllen wir ein kurzes Array mit Kfz-Objekten und lassen per foreach-Schleife die StartEngine() Methode aufrufen.
Wie du siehst wird die korrekte Implementierung der jeweiligen Klasse aufgerufen.

Interfaces

  • Code
  • Erklärung
  • Ergebnis

//IMoveable.java

public interface IMoveable 
{
    public void Move();
    public void Stop();
    public void Explode();
}



//Kfz.java

public class Kfz2 implements IMoveable 
{
    public void Move() 
    {
        System.out.println("Das Kfz bewegt sich.");
    }

    public void Stop() 
    {
        System.out.println("Das Kfz stoppt");
    }

    public void Explode() 
    {
        System.out.println("Das Kfz explodiert");
    }
}


Das Konzept der Schnittstellen oder Interfaces ist dem der Klassen nicht ganz unähnlich.
Eine Klasse ist eine Art Schablone in der Methoden und Eigenschaften ihrer Instanzen definiert sind. Eine Schnittstelle hingegen ist als Vorgabe für Klassen zu sehen die eine Implementierende Klasse beinhalten muss.
Während Java keine Mehrfachvererbung unterstützt (also das Erben von mehreren Basisklassen) kann dies durch das implementieren mehrerer Schnittstellen realisiert werden.
Eine Schnittstelle enthält hierbei keine ausprogrammierten Methoden sondern nur abstrakte Definitionen.

Wie du im Codebeispiel erkennen kannst, haben wir unsere Schnittstelle IMoveable genannt. Konventionsgemäß beginnen Schnittstellen immer mit einem großen i. Die Schnittstelle enthält keine Methoden oder Felder sondern nur Eigenschaften und eine nicht ausprogrammierte Methode. Diese werden erst in der Implementierenden Klasse Kfz auscodiert.

Einfach erklärt haben Schnittstellen zwei Vorteile. Zum einen ermöglichen sie die fehlende Mehrfachvererbung in Java und zum anderen kann so einer Klasse ein Typ vorgegeben werden.
Einfaches Beispiel: Unsere Klasse Kfz von oben könnte unsere Schnittstelle implementieren. Ebenso könnte es eine Klasse Fahrrad und Skateboard geben die diese Schnittstelle ebenfalls implementieren. Auch wenn diese Klassen komplett unterschiedlich sind, haben sie nun gemeinsam, dass sie unter anderem per Move() bewegbar sind.
Wie bei der Polymorphie erklärt können nun alle Instanzen von Klassen die diese Schnittstelle implementieren angesprochen werden.

IO Streams

  • Code
  • Erklärung
  • Ergebnis

import java.util.List;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;

public class SampleStream 
{
    public static void main (String[] args)
    {
        //Erstellung einer Liste mit Strings und Zeitstempel
        String currentTime = new SimpleDateFormat("HH:mm:ss").format(Calendar.getInstance().getTime());
        List<String> texts = Arrays.asList("Das", "ist", "ein", "Beispiel", "mit Text", currentTime);

        //Pfad wo unser .txt-File erstellt und ausgelesen werden soll
        String path = "F:\\Temp\\Testfile.txt";

        //Erstellung unseres BufferedWriters
        //Durchlauf jedes Eintrags der Liste und Schreiben in das File
        try 
        {
            BufferedWriter writer = new BufferedWriter( new FileWriter(path));
            for(String s : texts)
            {
                writer.write(s);
                writer.newLine();
            }
                writer.close();
        } 
        catch (IOException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //Erstellung unseres BufferedReaders
        //Zeilenweises Auslesen und Ausgeben der Textdatei
        String currentLine;
        try 
        {   
            BufferedReader reader = new BufferedReader(new FileReader(path));
            while ((currentLine = reader.readLine()) != null)
            {
                System.out.println(currentLine); 
            }
            reader.close();
        } 
        catch (IOException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //Kopieren des Textfiles als Backup
        String copyPath = path + "_BKP";
        File source = new File(path);
        File dest = new File(copyPath);

        try 
        {
            Files.copy(source.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
        } 
        catch (IOException e) 
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }        
}

Um in Java Dateien ein- und auslesen zu können, bedient man sich sogenannter Streams. Es gibt mehrere Methoden dies zu bewerkstelligen. In diesem Beispiel wollen wir uns den Datentypen BufferedReader und BufferedWriter widmen um Texte in eine Datei zu schreiben und wieder auszulesen.
Anschließend werden wir ein einfaches Backup davon erstellen. Zusätzlich verpassen wir dem ganzen einen Zeitstempel.

Zuerst erstellen wir uns eine einfache Liste mit Strings die wir uns später in ein Textfile ablegen lassen wollen. Bei der Pfadangabe müssen wir beachten den Backslash entsprechend zu escapen, dass der Pfad erreichbar ist und wir passende Berechtigungen haben (zB. auf Netzwerkpfade).
Die Erstellung eines neuen BufferedWriter-Objektes ist denkbar einfach. Alles was wir dafür brauchen ist unser Dateipfad.
In der Nachfolgenden for-Schleife gehen wir nun jeden String der Liste durch und schreiben diesen per write() in unser Textfile. Um den Text Zeilenweise auszugeben, fügen wir ein newLine() hinten an.
Am Ende des Vorgangs bitte nicht vergessen per close() den BufferedWriter wieder zu schließen um beanspruchte Ressourcen freizugeben.
Der BufferedReader funktioniert sehr ähnlich. Bei der Initialisierung benötigen wir ebenfalls nur den Dateipfad. Um während des Auslesens nicht über den eigentlichen Textumfang hinaus zu laufen, prüfen wir in der while-Schleife ob noch weitere Zeilen im Textfile enthalten sind. Wenn ja, dann geben wir diesen per System.out.println Zeilenweise in der Konsole aus.
Auch hier schließen wir den Stream per close().

Abschließend erstellen wir eine Kopie der eben erstellten Datei. Hierfür bedienen wir uns des Datentypes File bzw Files. Übergeben wir einen Quell- und Zielpfad können wir eine entsprechende Kopie erstellen und stellen mit StandardCopyOption.REPLACE_EXISTING sicher, dass eine eventuell vorhandene Datei überschrieben wird.

Operatoren I

  • Code
  • Erklärung
  • Ergebnis

//this -Operator
class Mitarbeiter 
{ 
    private string vorname; 
    private string nachname; 
    // Konstruktor: 
    public Mitarbeiter(string vorname, string nachname) 
    { 
        // Name des Objektes Mitarbeiter wird mit den uebergebenen Parametern befuellt 
        this.vorname = vorname; 
        this.nachname = nachname; 
    } 
}

// ?: -Operator (verkuerztes if)
//Bedingung ? Erste_Aweisung(true) : Zweite_Anweisung(false); 
int a = 5; 
int b = 7; 
 
int bigger = (a > b) ? a : b; // b wird zugewiesen 
 
 
// % -Operator (Modulo) 
// Rest einer Division
int a = 5; 
a = a % 3; //(oder auch a %= 3) 
//a=2 

Der .this -Operator
Der .this Operator verweist auf die Verwendung der Variable (oder Methode) des aktuell instanzierten Objektes. Besonders hilfreich bei der Verwendung von Klassenmethoden die Variablen mit dem gleichen Namen wie Klassenvariablen enthalten.

?: -Operator
Der ?: -Operator bietet eine verkürzte Schreibweise der klassischen if-Bedingung in der Form (Bedingung) ? (Anweisung wenn True) : (Anweisung wenn false);

% -Operator (Modulo)
Das Modulo ist der Rest einer Division (5 / 3 = 1 -> 2 Rest). Einfaches Anwednungsbeispiel: prüfen ob eine Zahl gerade oder ungerade ist.