Java, allgemein


      
Java, allgemein   
13.09.2023

Annotations


Annotations sind Informationen (Metadaten), die man zu einer Methode oder Klasse notieren und später wieder auslesen kann.

Hier eine beispielhafte Klasse mit einer Annotation:

@MyAnnotation
class MyClass {
}

Nun das Auslesen der Annotation:

boolean annotationPresent = MyClass.class.isAnnotationPresent(MyAnnotation.class);


Stichworte:
Annotation, auslesen, Vorhandensein überprüfen, feststellen




      
Java, allgemein   
08.09.2023

Iterieren durch eine Enum


Beispiel einer Enum durch welche mit einer for-Schleife iteriert werden soll:

public enum Direction {
   NORTH,
   EAST,
   SOUTH,
   WEST;
}


Die for-Schleife:

for (Direction dir : Direction.values())
   System.out.println(dir);


Stichworte:
Enum, iterieren, for-Schleife




      
Java, allgemein   
24.07.2023

Multithreading - Fallstricke


Collections (z.B.: ArrayList)

Ein Problem sind die "neuen" Collections (z.B.: die beliebten ArrayList. Fast alle Collections sind von Haus aus nicht für Multithreading ausgelegt (Lesender Zugriff funktioniert problemlos!). Es gibt zwar Hilfsklassen wie die CopyOnWriteArrayList (für HashMaps die ConcurrentHashMap), aber wie der Name schon verrät wird hier die gesamte ArrayList für einen Schreibzugriff kopiert, was natürlich eine echter Performance-Killer ist. Natürlich können ArrayLists (und andere Collections) völlig problemlos verwendet werden, wenn sie in dem Thread erstellt wurden und nur in diesem verwendet werden! Nur der Zugriff aus verschiedenen(!) Threads macht Probleme.
Die "alten" Collections (z.B. Vector, Stack, Hashtable) sind threadsicher!

synchronized

Um kritische Codestellen für Multithreading sicher zu machen, können diese mit einem synchronized eingeschlossen werden. Innerhalb eines synchronized-Blocks kann immer nur ein Thread arbeiten. Andere Threads müssen warten (also Zeit verbrauchen), bis der arbeitende Thread fertig ist. Zu beachte ist hier auch, dass es nicht zu Deadlocks kommt.

Beispiel:

ArrayList zahlungsreihe = ...
synchronized (zahlungsreihe) {
     zahlungsreihe.sort(new DateAndIntervalComparator());
} 


Klassen wenn immer möglich unveränderlich (Immutable) schreiben.

Dazu müssen drei Bedingungen erfüllt sein:
  • Alle Felder als final deklarieren
  • this darf nicht an andere Klassen übergeben werden
  • Eine Modifizierung darf nur im Konstruktor stattfinden


Beispiel:
class ImmutableClass {
   private final HashMap map = new HashMap<>();
   
   public ImmutableClass() {
      map.put(0, BigInteger.ONE);
      for (int i = 1; i < 10; i++)
         map.put(i, BigInteger.valueof(i).multiply(map.get(i-1)));
   }

   public getFactor(int i) {
      if (i < 0 || i >= 10)
         throw new IllegalArgumentException();
      return map.get(i);
   }
}
// Die Klasse ImmutableClass kann bedenkenlos in Threads verwendet werden, obwohl sie eine Map enthält!
// Alle drei Bedingungen sind erfüllt

Beispiel 2:
class ImmutableClass2 {
   private final HashMap map = new HashMap<>();
   
   public ImmutableClass3() {
      map.put(0, BigInteger.ONE);
      IntStream.rangeClosed(1, 10).forEach(i -> map.put(n, BigInteger.valueOf(i).multiply(map.get(i - 1))));
  }

  public getFactor(int i) {
    if (i < 0 || i > 10)
      throw new IllegalArgumentException();
    return map.get(i);
  }
}
// Diese Klasse ImmutableClass2 kann nicht(!) bedenkenlos in Threads verwendet werden!
// Warum? this wird an eine andere Klasse übergeben. Leider ist das nicht offensichtlich.
// Wir greifen auf die HashMap mit einem Lambda zu. Lambdas verhalten sich wie innere anonyme Klassen.
// Da die Map ein Feld der Klasse ist, wird (unsichtbar) ein this übergeben um auf die map zugreifen zu können. Böse Falle!

Beispiel 3:
class ImmutableClass3 {
   private final HashMap map = new HashMap<>();
   
   public ImmutableClass3() {
      HashMap mapTemp = new HashMap<>();
      mapTemp.put(0, BigInteger.ONE);
      IntStream.rangeClosed(1, 10).forEach(i -> mapTemp.put(n, BigInteger.valueOf(i).multiply(mapTemp.get(i - 1))));
      map = mapTemp;
   }

   public getFactor(int i) {
      if (i < 0 || i >= 10)
         throw new IllegalArgumentException();
      return map.get(i);
   }
}
// Diese Klasse ImmutableClass3 kann wieder bedenkenlos in Threads verwendet werden!
// Warum? Der Stream arbeitet nun mit der temporären mapTemp. Dadurch ist kein Verweis auf this nötig und somit sind alle drei Bedingungen erfüllt.


"Beliebte" Probleme

Variablen static zu deklarieren ist im Bereich MultiThreading problematisch, da verschieden Threads dann ja auch die selbe Variable verwenden.



      
Java, allgemein   
23.06.2023

EnumMap


Eine EnumMap ist eine Map, bei welcher der Key eine Enumeration ist.
Durch die spezielle Ablage (als Array) in der Map, ist eine solche Map besonders effizient.
Dadurch bleibt auch eine Reihenfolge erhalten.



      
Java, allgemein   
13.06.2023

Zwei Arrays zusammenfügen


Folgende Möglichkeiten gibt es um in Java aus zwei Arrays ein Array zu machen:

int[] a = {1, 2, 3};                     // Erstes Array
int[] b = {4, 5};                        // Zweites Array
int[] c = new int[a.length + b.length];  // Drittes Array, welches die beiden ersten Arrays aufnehmen soll

// Möglichkeit 1:
System.arraycopy(a, 0, c, 0, a.length);         // Erstes Array "a" in Array "c" kopieren
System.arraycopy(b, 0, c, a.length, b.length);  // Zweites Array "b" in Array "c" kopieren

// Möglichkeit 2:
c = IntStream.concat(IntStream.of(a), IntStream.of(b)).toArray();

// Möglichkeit 3:
int index = 0;
for (int i : a) 
   c[index++] = i;
for (int i : b)
   c[index++] = i;


Stichworte:
Array, zusammenfügen, concat Arrays




      
Java, allgemein   
11.05.2023

synchronized


synchronized wird verwendet, damit nicht zwei Threads gleichzeitig auf das selbe Objekt zugreifen können.

private synchronized (this) {
   // kritischer Code
}

Der Übergabeparameter ist häufig this, kann aber auch ein beliebiges anderes Objekt sein, welches vorzugsweise final ist um sicher zu stellen, dass das Objekt zur Laufzeit nicht geändert wird. Grund: Dieses Objekt enthält den lock für den synchronized code.
Daher ist code wie dieser nicht erlaubt:

ArrayList myList = new ArrayList<>();
private synchronized (myList) {
   myList = new ArrayList<>();
}


Stichworte:
synchronized, Thread




      
Java, allgemein   
28.04.2023

ArrayList - thread safe


Es gibt verschiedene Möglichkeiten eine ArrayList thread safe zu machen:

List list = new CopyOnWriteArrayList(); // Einfach statt einer normalen ArrayList verwenden

oder

List list = Collections.synchronizedList(new ArrayList());


Stichworte:
ArrayList, Multithreading, thread safe, CopyOnWriteArrayList




      
Java, allgemein   
26.04.2023

Threadpool


package com.sowas.itwiki.threadpool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadpoolExample {

   /**
    * Ein Task ist die Aufgabe, die der Thread erledigen soll
    */
   private class Task implements Runnable {
      private int taskId;

      public Task(int id) {
         this.taskId = id;
      }

      @Override
      public void run() {
         System.out.println("Task Id: " + this.taskId + " performed by " + Thread.currentThread().getName());
      }
   }

   public static void main(String args[]) {
      ExecutorService executerService = Executors.newFixedThreadPool(4); // create 4 worker threads in Thread Pool
      for (int i = 0; i < 10; i++) {
         executerService.submit(new Task(i));
      }
      executerService.shutdown();
      System.out.println("All done.");
   }
}

Ausgabe (kann je nach Platform leicht varieren):
Task Id: 0 performed by pool-1-thread-1
Task Id: 3 performed by pool-1-thread-4
Task Id: 4 performed by pool-1-thread-1
Task Id: 2 performed by pool-1-thread-3
Task Id: 7 performed by pool-1-thread-3
Task Id: 8 performed by pool-1-thread-3
Task Id: 1 performed by pool-1-thread-2
Task Id: 9 performed by pool-1-thread-3
Task Id: 6 performed by pool-1-thread-1
Task Id: 5 performed by pool-1-thread-4
All done.



      
Java, allgemein   
18.08.2022

Konvertieren einer List in ein Set



ArrayList list = ...
Set set1 = new HashSet(list);
Set set2 = new TreeSet(list);  // sortiert




      
Java, allgemein   
10.08.2022

Konvertieren eines Set von Integern in ein Set von Strings


Am einfachsten geht dies mit der Stream-API:

Set setOfInteger = new HashSet<>();
Set setOfStrings = setOfInteger.stream().map(e -> String.valueOf(e)).collect(Collectors.toSet());

oder

Set setOfInteger = new HashSet<>();
Set setOfString = setOfInteger.stream().map(String::valueOf).collect(Collectors.toSet());