Home » 2017 » November

Archiv für den Monat: November 2017

Exceptions versus Status Code propagation

Java Exception Handling

Was ist gutes Error-Handling?

Gute Fehlerbehandlung bietet Übersicht, welche Fehlersituationen zu welcher Reaktion führen.

Mögliche Reaktionen bei Fehlern:

  • SW gibt Exception weiter an caller
  • SW erstellt Teilresultate, mit Fehler-Informationen

In allen meinen vergangenen Projekten hat man mit Error-Codes  (Strings) gearbeitet. Es ist dann immer recht schwierig von diesen Error-Code auf deren Verarbeitung zu schliessen.

Wäre es nicht besser, mit Exceptions zu arbeiten, statt mit Fehlercodes? Wäre es nicht besser, für alle Fehlersituationen, die eine bestimmte Reaktion hervorrufen (z.B. erstellen eines Teilresultats mit Fehlerinfo) dieselbe Exception zu werfen?
Wäre es nicht sinnvoll, wenn die Prozedur, die die Fehlerreaktion hervorrufen würde Teil der Exception wäre, bzw. die Exception das Interface implementieren würde?

 


Siehe auch: Exceptions versus Status Code propagation

 

Aufgaben eines guten Error-Handlings

Mitteilen:

  • Was ist passiert
    • Welche ursache hat welchen Impact –> Triage ermöglich. Wichtiges zuerst lösen.
    • Wie kann es gelöst werden.
  • Konstistenten Zustand im System zurück lassen. ROLLBACK.

Inhalt des Exception Objekt:

Typem von Exception Objekten:

  • Environmen Exception (Unterteilbar in Service Exception (unterteilbar in ServiceUnavailableEx und ServiceResponseException) und Platform Exception)
    Eine Platform Komponente oder ein Sevice war nicht verfügbar.
  • Data Validation Exception
    Ein Feld hat keinen/falschen Wert
    Felder:

    • Feld
      • Key
      • Value
    • Breached Constraint
    • Herkunft (wer hat das feld geliefert)
  • Allgemeine Exception Informationen: (Basisklasse. Data Validationn Exc und Environment Exc leiten davon ab)
    • Was ging schief (ist bei Environment Exceptions schon inherent klar)
    • Current Process (der nicht hat erfolgreich ausgeführt werden können)
  • Info- oder Addendum-Meldungen: Mit (teilweise) demselben Mechanismus wie exceptions werden of jegliche art von Processing-Messages verarbeitet. Das hat zu folge, dass auch Infos (z.B. „77 items verarbeitet“) als „Exception“ prozessiert werden.

List mit einem einzigen Element erstellen

    public static <T> List<T> singletonList(T o) {
        return new SingletonList<>(o);
    }

Hinzufuegen zu mapped Liste (:Map.computeIfAbsent)

Eine Liste innerhalb einer Map erweitern falls sie schon vorhanden ist oder sonst neu erstellen:

    private Map<Object, List<Object>> addToMappedList1(Map<Object, List<Object>> mapOfLists, Object key, Object newValue){

        if (mapOfLists.get(key) == null){
            mapOfLists.put(key, new ArrayList<>());
        }
        mapOfLists.get(key).add(newValue);
        return mapOfLists;
    }

Eleganter:

    private Map<Object, List<Object>> addToMappedList2(Map<Object, List<Object>> mapOfLists, Object key, Object newValue){

        mapOfLists.computeIfAbsent(key, k -> new ArrayList<>()).add(newValue);
        return mapOfLists;
    }

Kategorien – Mapping

  • Multi-Threading –> Concurrency –> Parrallel Processing
  • Stream –allenfalls–> Lambda

Mittels Stream API Flache Liste von Liste von Listen erstellen

Beispiel:

List<List<Object>> list = ...
List<Object> flat = 
    list.stream()
        .flatMap(List::stream)
        .collect(Collectors.toList());

(taken from)

 

Erklärung:

// List of Lists:
List<List<String>> listOfLists = new ArrayList<>();
listOfLists.add(Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));
listOfLists.add(Arrays.asList("Bern", "Chur", "Luzern"));

List<String> result = listOfLists.stream().flatMap(list -> list.stream()).collect(Collectors.toList());

Signatur von flatMap(..):

<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

T : Das Element mit dem der Stream parametrisiert ist, auf dem flatMap(..) aufgerufen wird.

 

Von flatMap verlanges Functional interface:
Function<? super T, ? extends Stream<? extends R>> :

interface Function<T, R> {
   R apply(T t);
}

Das heisst bezüglich übergebener Funktion/Lambda-Expression:

Input von apply: Ist gleich dem Element-Parameter des Streams auf dem flatMap aufgerufen wird.

Output von apply: <? extends Stream<? extends R>>:
Ein Stream von irgendwas. –> Ich darf selbst bestimmen, was R dann wirklich ist. Dadurch, wie meine übergebene Funktion aktuell parametrisiert ist, wird R erst bestimmt.

Mittels Stream API Flache Liste von Map von Listen erstellen:

    private List getAllAepfel(Map<UID, List<Apfel>> uidToApfelList) {
        List xq = uidToApfelList.values().stream().flatMap(List::stream).collect(Collectors.toList());
    }

Concurrency mit Spring – Scope beachten

Spring Scopes:

Aus MyKong:

5 types of bean scopes supported :

  1. singleton – Return a single bean instance per Spring IoC container
  2. prototype – Return a new bean instance each time when requested
  3. request – Return a single bean instance per HTTP request. *
  4. session – Return a single bean instance per HTTP session. *
  5. globalSession – Return a single bean instance per global HTTP session. *

In most cases, you may only deal with the Spring’s core scope – singleton and prototype, and the default scope is singleton.

P.S * means only valid in the context of a web-aware Spring ApplicationContext

Das heisst: Wenn das Bean mit Scope=“singleton“ (default) definiert ist, muss das Bean stateless sein.

Siehe auch: https://stackoverflow.com/questions/1745790/spring-singleton-session-scopes-and-concurrency

 

Referenzieren, statt kopieren

Oft meint man man arbeite auf einem Objekt, das nur einem selbst gehört. In Wirklichkeit wird aber andernorts genau dasselbe Objekt gehalten und verändert.