Home » Beitrag verschlagwortet mit 'Java'

Schlagwort-Archive: Java

TLS/SSL probleme im Maven-Build lösen

mvn -Djavax.net.debug=ssl,handshake clean install

Zusammengehörende Objekte in einer Collection zusammenfassen – Mit Java Stream API

Angenommen wir haben eine Collection von Einkäufen (Joghurt, Bananen, Deodorant, Äpfel, Käse, …) und wir wollen diese zusammenfassen (z.B. Milchprodukte, Früchte, …) dann können wir das wie folgt machen:

Map<String, Purchase> condensedMap = purchases.stream()
    .collect(Collectors.groupingBy(Purchase::getCategory,
        Collectors.collectingAndThen(Collectors.reducing(
         (a,b) -> new Category(a.getCategory().name(), Math.sum(a.price(), b.price())), 
Optional::get))));

List<Category> condensedList = condensedMap.values();

Inspired by Java stream merge or reduce duplicate objects

Zyklische Dependencies Vermeiden, mit Dependeny Inversion

Problem

Wir haben ein Low Level (core) Module das von einem High Level (public Web) Module verwendet wird.
Nun gibt es einen neuen Fall, wo das High Module von vom Low Level Module aufgerufen werden muss. Dies ist eine umgekehrte Abhängigkeit!

edu.learn.highlevel.TuWasBean
interface HighLevelModuleTuWasServiceIntf{
  void tuWas(TuWasBean bean);
}

Das Problem ist, dass nun eine Zyklische Abhängigkeit (Cyclic Dependency) entsteht. Dies wird in unserem Fall zuallererst schmerzhaft, da High Level und Low Level Module im selben Build derselben Applikation gebaut werden. Dabei wird zuerst Low Level gebildet und dann High Level. Wenn man nun eine Anpassung am HighLevelModuleServiceIntf macht, dann muss man zuerst einen High Level Build laufen lassen, bevor man das Low Level auch adaptieren und bauen kann. (Sonst wäre ja das geänderte High Level Interface – auf das Low Level bereits aufbaut – noch gar nicht da.)

Lösung – Auflösung der Zyklischen Dependency

Die Lösung heisst „Dependency Inversion“. In unserem Fall heisst das, dass das Low Level Module so tut als sei der Service von ihm! Es definiert den Service selbst (und verlangt vom High Level Module, dass es selbst auf sein High Level Interface mappt).

Low Level Module formuliert also:

edu.learn.lowLevel.RepresentationOfTuWasBean
interface RepresentationOfTheHighLevelModuleTuWasServiceIntf{
   void tuWas(RepresentationOfTuWasBean bean);
}

Low Level codiert nun gegen sein eigenes Interface. Zur Runtime bezieht es vertrauensvoll eine Implementaion von RepresentationOfTheHighLevelModuleTuWasServiceIntf:

@Autowired
RepresentationOfTheHighLevelModuleTuWasServiceIntf service;

public void meinBusiness(){
   service.tuEtwas(RepresentationOfTuWasBean bean);
}

High Level muss dazu eine Implementierung des Low Level Interfaces zur Verfügung stellen. High Level Module mappt also selber das Low Level API zu seinem eigenen hin:

package edu.learn.highlevel.mapper;
import edu.learn.lowLevel.RepresentationOfTuWasBean
import edu.learn.highlevel.TuWasBean;

@Autowired
private OurBeanMapper beanMapper;

@Autowired
private HighLevelModuleTuWasServiceIntf highLevelService;

class TuWasServiceClientAdapter implements RepresentationOfTheHighLevelModuleTuWasServiceIntf {
   void tuWas(RepresentationOfTuWasBean lowLevelBean){
      TuWasBean highLevelBean = beanMapper.map(lowLevelBean);
      highLevelService.tuWas(highLevelBean);
   }
}

Durch diese Implementierung kann nun das High Level Module unabhängig vom Low Level Module Anpassungen an diesem API machen. Es ist einfach selbst verantwortlich das Low Level Interface weiterhin einzuhalten.
Das Low Level Module definiert den Zusammenarbeits-Vertrag. Das heisst: Auch hier ist nun High Level vom Low Level Abhängig.

Es ist nun auch möglich das Interface und dessen Nutzung (High und Low Level) anzupassen und gleichzeitig einem Build zuzuführen. Zuvor war das unmöglich, weil im ersten Schritt Low Level gebildet wurde, welches die angepassten Felder schon (zur Build-Zeit) im High Level Interface referenzierte. Nun kennt Low Level High level nicht mehr.

Zusätzlich Hilfreich …

… ist der Einsatz eines Bean-Mappers. Allein schon durch seinen Einsatz schlagen Feld-Anpassungen im Ziel-API nicht direkt auf Kompilierprobleme beim Consumer durch.

Java Runnable (EXE) erstellen / Runnable JAR erstellen

Wie erstelle ich ein Java-Programm, das ich mal einfach so einem Kollegen senden kann, das dieser dann auf seinen Computer kopiert und per Doppelklick ausführt.

(Java Web Start wäre wohl eine gute Wahl dafür gewesen, doch diese Technologie existiert seit Java 11 nicht mehr.)

Hat das Programm ein GUI (oder präziser: Braucht es keine Kommandozeile für die User-Interaktion) kann man ein „Doppelklickbares“ JAR aus dem Code erstellen.

Ausführbare JAR Datei erstellen

Eine doppelklickbare JAR Datei kann wie folgt erstellt werden.
Dies ist nicht zielführend mit Kommandozeilenprogrammen, die (ad hoc) Parameter verlangen. Nützlich ist diese Option hingegen für GUI Programme.

Main Klasse in Manifest referenzieren

Im MANIFEST.MF soll diese Zeile stehen:

Main-Class: ch.meine.MainKlasse
Dies kann erreicht werden indem dem pom.xml diese Plugin-Definition hinzugefüt wird:
<build>
        <plugins>

            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>ch.meine.MainKlasse</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
            </plugin>
        </plugins>
    </build>

Nun muss das Projekt gebildet werden:

mvn clean package assembly:single

Das entstande JAR-File kann mittels Doppelklick gestartet werden.
Wenn das Programm kein GUI ist wird es kaum sichtbar sein, weil es wohl anläuft aber potentiell sehr schnell wieder verschwindet.

Alternativ kann das JAR gestartet werden mit:

java -jar MeinProgramm.jar <parameters>

Auf Kommandozeile ausführen

Ein (wie oben beschrieben) ausführbar gemachtes JAR kann wie folgt ausgeführt werden:

java -jar MeinProgramm.jar <parameters>

Selbstverständlich kann dieser Aufruf in Shortcuts oder in (Power)Shell/Bat Scripts eingabaut werden (und eventuell so als ZIP dem Kunden geliefert werden).

Java Design Patterns

Siehe auch: Java Design Principles 

Ein wunderbarer Kurs: Design Patterns in Java: The Big Picture by Esteban Herrera

Design Pattern Types

Unterscheidung 1: Structural | Behavioral | Creational
Unterscheidung 2: Class | Object centric

Wichtigste Design Patterns

Creational

Abstract Factory

Factory Method

Gemäss Herrera: Gleich wie ‚Abstract Factory‘ aber links und Creator und Produkt haben nur eine Hierarchie.
Gemäss Steinhauser: Eine getFactory() Methode erzeugt die Factory anhand eines Discriminators.

Builder

Singleton Pattern

Sinn: Es soll in der Laufzeitumgebung nur genau ein Objekt einer bestimmten Klasse geben.
Vorgehen: Einzigen parameterlosen Konstruktor der Klasse auf private setzen. Statisches Feld ‚instance‘, das die eine Instanz aufnimmt. Eine statische getInstance Methode wird benutzt um 1., falls ‚instance‘ noch NULL ist die Klasse zu instqanzieren und ‚instance‘ zu setzen und 2. die Instanz zu retournieren.

Behavioural

Strategy

State

Command

Observer Pattern

Template Method Pattern

Eine Basisklasse enthälte eine Methode (Bsp. processDocument()), die sowohl Verarbeitungsschritte enthält, die für alle Spezialfälle gleich sind (Bsp. backup(), validate()), aber auch solche, die je nach Fall differenziert werden sollen (Bsp. process()). Die zu differenzierenden Schritte werden in der Basisklasse als abstrakte Methoden ausgelagert und in spezifischen Subklassen konkretisiert.

Spezialfall:
Hooks: Wie Template Pattern, aber methoden sind nicht abstrakt und müssen deshalb nicht überschriben werden (default).

Visitor

Beschreibung fehlt noch!

Iterator

Beschreibung fehlt noch!

Structural

Facade Pattern

Zweck: Einen Orchestrator haben, der weiss wo was zu holen und wie zu verarbeiten ist. ==> Wie eine Main Methode.

Decorator Pattern

Um eine Pizza mit verschiedenen Zutaten zu dekorieren:

Das bedingt, dass die Decorators eine Instanz des Decoree halten und eine gemeinsame Methode (=>Interface) implementieren:

Proxy Pattern

(Object) Adapter Pattern

Zweck: Koppelung von Services ohne direkt von ihren Interfaces abhängig zu sein.

Composite

Bridge

Traps/Fallen beim Java-Programmieren – Anfängerfehler

assertThat(booleanExpression)

Achtung! Der Ausdruck assertThat(booleanExpression) prüft nichts!

Falsch:

assterThat("Hans".equals("Peter")); // wird keine JUnit-Failed Test ausweisen!

Richtig:

assertThat("Hans").isEqualTo("Peter"); // wird JUnit-Failed Test ausweisen!

Vordefinierte Java Functional Interfaces – Welches kann ich benutzen?

ParameterFunctional Interface
keineRunnable
1 inputConsumer
1 outputSupplier
1 input / 1 outputFunction
2 inputBiConsumer