Null coalescing

Null coalescing
MY
  • Rejestracja:około 5 lat
  • Ostatnio:6 miesięcy
  • Postów:24
0

Cześć,

powiedzmy, że mam funkcję:

Kopiuj
public static String getCode(Foo first, Supplier<Foo> second)

interface Foo {

    String getCode();

}

chciałbym, żeby przechodziła test:

Kopiuj
expect:
            getCode(new FooImpl(first), { new FooImpl(second) }) == result
where:
            first | second || result
            'A'   | 'B'    || 'A'
            null  | 'B'    || 'B'
            null  | null   || 'default'

Jak byście napisali to w Javie 8? Próbowałem z ifami, ale robi się to mało czytelne i nie podoba mi się.

Optional.or doszedł niestety w Java 9, ale chciałbym uzyskać coś podobnego:

Kopiuj
    public static String getCode(Foo first, Supplier<Foo> second) {
        return ofNullable(first.getCode())
                .or(() -> ofNullable(second.get().getCode()))
                .orElse(DEFAULT);
    }

Może znacie jakieś Utilsy (apache, guava), które mają już coś takiego?

edytowany 1x, ostatnio: mythflame
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Silesia/Marki
  • Postów:5505
3

Zobacz jak wyglada implementacja or() i skopiuj do siebie


Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie
Wibowit
Jak skopiujesz z OpenJDK to naruszysz licencję: https://openjdk.java.net/legal/gplv2+ce.html :]
TS
  • Rejestracja:prawie 5 lat
  • Ostatnio:ponad 4 lata
  • Postów:394
1

Wpisałem w kaczkę "java first non null" i takie coś mi wyszło:

http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/ObjectUtils.html#firstNonNull%28T...%29

A potrzebowałem tego ostatnio...

Edit: dobra, w sumie to nie zadziała, bo tutaj jest Supplier. Jednak w nowszej wersji jest już metoda, która to ogarnia:

http://commons.apache.org/proper/commons-lang/javadocs/api-3.10/org/apache/commons/lang3/ObjectUtils.html#getFirstNonNull-java.util.function.Supplier...-

edytowany 2x, ostatnio: tsz
Zobacz pozostałe 3 komentarze
AK
Co to jest za klasa Supplier? Twoja/zamknięta, czy z czegoś publicznego, i powinienem się podciągnąć?
AK
Wybacz, z takim słowem google nie pomoże. Jaki pakiet?
TS
@AnyKtokolwiek: wyskakuje na pierwszej pozycji jak się wpisze "javadoc supplier"...
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Postów:1875
2

Ja bym tutaj użył instrukcji warunkowej if.


”Engineering is easy. People are hard.” Bill Coughran
edytowany 1x, ostatnio: Charles_Ray
MY
  • Rejestracja:około 5 lat
  • Ostatnio:6 miesięcy
  • Postów:24
0
Charles_Ray napisał(a):

Ja bym tutaj użył instrukcji warunkowej if.

Kopiuj
public static String getCode(Foo first, Supplier<Foo> second) {
        String firstCode = first.getCode();
        if(firstCode != null) {
            return firstCode;
        } else {
            String secondCode = second.get().getCode();
            if(secondCode != null) {
                return secondCode;
            } else {
                return DEFAULT;
            }
        }
    }

Powstaje coś takiego - wydzielenie zawartości else do metody nie pomaga w czytelności. Wolałbym coś bardziej zwięzłego, na co patrząc od razu wiedziałbym co się dzieje. Tutaj nie mam takiego uczucia.

edytowany 1x, ostatnio: mythflame
99xmarcin
Po co Ci else jak masz return?
Wibowit
  • Rejestracja:około 20 lat
  • Ostatnio:około 3 godziny
0
Kopiuj
    public static String getCode(Foo first, Supplier<Foo> second) {
        return ofNullable(first.getCode())
                .or(() -> ofNullable(second.get().getCode()))
                .orElse(DEFAULT);
    }

można by to zapisać jako:

Kopiuj
    public static String getCode(Foo first, Supplier<Foo> second) {
        String result1 = first.getCode();
        String result2 = result1 != null ? result1 : second.get().getCode();
        return result2 != null ? result2 : DEFAULT;
    }

Jeśli result1 != null to second.get().getCode() się nie wykona.

Ewentualnie można jeszcze podejść imperatywnie:

Kopiuj
    public static String getCode(Foo first, Supplier<Foo> second) {
        String result = first.getCode();
        if (result == null) { result = second.get().getCode(); }
        if (result == null) { result = DEFAULT; }
        return result;
    }

Albo wracając do Optionali na Javie 8:

Kopiuj
    public static String getCode(Foo first, Supplier<Foo> second) {
        return ofNullable(
            ofNullable(firstGetCode())
                .orElseGet(() -> second.get().getCode())
        ).orElse(DEFAULT);
    }

Dużo się nie nawalczy przy tak ubogim Optionalu jak w Javie 8.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
edytowany 4x, ostatnio: Wibowit
MY
Pytam głównie w kontekście Clean Code. Tutaj podobnie trzeba chwilę się zastanowić co się tak naprawdę dzieje
pedegie
dla mnie wersja 2 najbardziej czytelna : D
Shalom
Pytam głównie w kontekście Clean Code -> clean code to umarł jak ktoś zrobił API gdzie wpycha nulle ;)
Charles_Ray
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Postów:1875
0

W kontekście clean coda i wzorców, czy to nie jest temat na chain of responsibility? Trochę armata. Ile tam tych ifow będzie? 2 to jeszcze bez dramatu jak zamknięte w jakiejś klasie z boku


”Engineering is easy. People are hard.” Bill Coughran
edytowany 1x, ostatnio: Charles_Ray
damianem
  • Rejestracja:prawie 8 lat
  • Ostatnio:4 miesiące
  • Postów:205
0

Propozycja (niektóre null checks mogą się okazać niepotrzebne):

Kopiuj
    public static String getCode(Foo first, Supplier<Foo> second) {
        return Stream.of(() -> first, second)
            .filter(Objects::nonNull)
            .map(Supplier::get)
            .filter(Objects::nonNull)
            .map(Foo::getCode)
            .filter(Objects::nonNull)
            .findFirst()
            .orElse("default");
    }
Zobacz pozostały 1 komentarz
Charles_Ray
To trzeba zrobić Vavrem albo Reactorem
S9
@Charles_Ray no to popatrz w dół :D
Charles_Ray
No i co ja poradzę ;)
katelx
  • Rejestracja:około 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Hong Kong
2

najlepszym rozwiazaniem wydaje mi sie zmiana/opakowanie Foo zeby zwracalo vavr'owe Option<String>.
a jak nie to zrobilabym 2 ify.
mysle ze jak po kodzie lataja bomby w postaci nulli to robienie przeinzynierowanego coalesce jest wymyslaniem sobie problemu zamiast rozwiazywac faktyczny :)

LP
  • Rejestracja:około 7 lat
  • Ostatnio:28 dni
  • Postów:366
1
mythflame napisał(a):
Charles_Ray napisał(a):

Ja bym tutaj użył instrukcji warunkowej if.

Kopiuj
public static String getCode(Foo first, Supplier<Foo> second) {
        String firstCode = first.getCode();
        if(firstCode != null) {
            return firstCode;
        } else {
            String secondCode = second.get().getCode();
            if(secondCode != null) {
                return secondCode;
            } else {
                return DEFAULT;
            }
        }
    }

Powstaje coś takiego - wydzielenie zawartości else do metody nie pomaga w czytelności. Wolałbym coś bardziej zwięzłego, na co patrząc od razu wiedziałbym co się dzieje. Tutaj nie mam takiego uczucia.

Kopiuj
public static String getCode(Foo first, Supplier<Foo> second) {
        String firstCode = first.getCode();
        if(firstCode != null) {
            return firstCode;
        }

          String secondCode = second.get().getCode();
          return secondCode == null ? DEFAULT : secondCode;
    }
KamilAdam
  • Rejestracja:ponad 6 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Silesia/Marki
  • Postów:5505
0
Kopiuj
public static String getCode(Foo first, Supplier<Foo> second) {
        String firstCode = first.getCode();
        if(firstCode != null) {
            return firstCode;
        }

          String secondCode = second.get().getCode();
          return secondCode == null ? DEFAULT : secondCode;
    }
Kopiuj
  public static String getCode(Foo first, Supplier<Foo> second) {
    return Optional
      .ofNullable(first.getCode())
      .orElseGet(() -> Optional.ofNullable(second.get().getCode()).orElse(DEFAULT));
  }

Mama called me disappointment, Papa called me fat
Każdego eksperta można zastąpić backendowcem który ma się douczyć po godzinach. Tak zostałem ekspertem AI, Neo4j i Nest.js . Przez mianowanie

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.