To nie będzie zamknięty cykl, bo wraz z czasem będę w niego wrzucać kolejne przykłady.

Na pierwszy ogień coś co przewija się w kodzie, który transformuje jedne obiekty w inne.

Listing 1. Klasyczny kod

class MyEntity{
   
   private String name;
   // gettery, settery, inne pola itp.
}

class MyOtherEntity{
   
   private String name;
   // gettery, settery, inne pola itp.

   public MyOtherEntity(){}

   public MyOtherEntity(MyEntity my){
      this.name = my.name
          //...
   }
}

class Converter{

    public MyOtherEntity convert(MyEntity my){
        if(my != null ) 
            return new MyOtherEntity(my);
        return new MyOtherEntity();
    }
}

Kod ten przedstawia problem z dokładnością do if-a, który może być przeniesiony do konstruktora MyOtherEntity(MyEntity). Kod zdaje się być prosty, ale tylko dlatego, że mamy tu tylko jedno pole. Przy większej liczbie pól zaczyna być nieciekawie. Rozwiązanie, a w zasadzie uproszczenie zapisu:

Listing 2. Kod z „podwójnym new”

class Converter{

    public MyOtherEntity convert(MyEntity my){
        return Optional.ofNullable(my)
                       .map(MyOtherEntity::new)
                       .orElseGet(MyOtherEntity::new);
    }
}

Co tu się dzieje? Najpierw tworzymy Optional, który pozwala na wykonanie map wtedy, gdy my nie jest null. Jako transformatę przekazujemy konstruktor. Który? Ponieważ kompilator oczekuje w tym miejscu czegoś co przyjmie jako parametr MyEntity i jest w stanie odnaleźć odpowiedni konstruktor. Jeżeli jednak my jest null to zostanie wywołany Supplier z orElseGet. I znowuż jako parametr jest przekazany konstruktor, ale tym razem kompilator będzie oczekiwał czegoś bezparametrowego.

Podsumowując. Zamieniliśmy „ifologię” na kod oparty o dobór odpowiednich typów, tu dokładnie wnioskowanie konstruktora, co pozwala na przerzucenie części odpowiedzialności na kompilator. Zadanie dla was – jak zmieniły się testy konwertera.