Unikanie null'a za wszelką cenę

1

Często spotykam się z opiniami, że null to czyste zło, ale jako amator często trafiam na przypadki, w których nie mam pomysłu na inne rozwiązanie. Przykładowo jeśli szukam w bazie danych jakiegoś obiektu, którego w bazie nie ma - otrzymuje null'a a chciałbym na nim wykonać wiele operacji. Użycie Optional.ofNullable(szukanyObiekt).isPresent() chyba też mija się z celem bo metoda isPresent() tylko sprawdza czy obiekt nie jest nullem. Wiem, że mógłbym użyć optionala.or/else

Nie za bardzo też rozumiem dlaczego przykład z bloga http://www.yegor256.com/2016/03/22/try-finally-if-not-null.html jest poprawny tj:
To zle bo jest if(null)

InputStream input = null;   // nie wiem po co koles tutaj przypisywal null'a, chyba na sile, zeby pokazac jaki to null je fee
try {
  input = url.openStream();
  // reads the stream, throws IOException
} catch (IOException ex) {
  throw new RuntimeException(ex);
} finally {
  if (input != null) {
    input.close();
  }
}

A to podobno dobrze:

final InputStream input = url.openStream();     // czemu ten input nie jest w bloku try/catch ?
try {
  // reads the stream, throws IOException
} catch (IOException ex) {
  throw new RuntimeException(ex);
} finally {
  input.close();  // a co jesli, input nie mogl 'otworzyc strumienia' i jest null'em ?
}
0

Użycie Optional.ofNullable(szukanyObiekt).isPresent() chyba też mija się z celem bo metoda isPresent() tylko sprawdza czy obiekt nie jest nullem

No jak chcesz nulla opakować optionalem żeby zaraz sprawdzić czy isPresent to faktycznie nie ma to sensu...

Nie rozumiesz przykładu z bloga bo nie przeczytałeś tekstu. To był tylko przykład co można zrobić jeśli samo open nie rzuca wyjątku. Realnie to w ogóle taki kod by sie nie skompilował, stąd też autor podał kolejny kod na taką sytuacje.

Problem z nullami jest dość trywialny i łatwy do zrozumienia: nulle są niewidzialne. Nie da się łatwo stwierdzić, patrząc na kod, czy jakaś zmienna jest/nie jest/może być nullem. Czasem musiałbyś skakać wiele poziomów w kodzie w dół żeby sprawdzić czy jakaś zmienna może być nullem czy też nie. A z drugiej strony opakowywane całego kodu w if(x != null) jest równie bez sensu. Optional ma tą zaletę że go widać. Jak jakaś metoda zwróci ci optional to wiesz że musisz sprawdzić czy nie jest pusty i jakoś tą sytuacje obsłużyć. Jak metoda zwraca ci obiekt X to nie wiesz czy ten obiekt może być nullem czy też nie, bez zagłębiania się w kod danej metody.

3

Kod z przykładu to powinien wyglądać w nowej javie jakoś tak:

try (final InputStream input = url.openStream() ) {
  // reads the stream, throws IOException
} catch (IOException ex) {
  throw new RuntimeException(ex);
}

A co do Optionalla i nulla.
Generalnie nigdy nie powinieneś używać w zdrowym kodzie metod isPresent() i get()
Tylko map, flatMap i ifPresent, orElse.
Wtedy kod i optionalle nabierają sensu. Zresztą najlepiej brać Option z vavr.io zamiast zwykłego Optionala z JDK.

Miejsce nulla jest tylko w bardzo niskopoziomowym kodzie, który walczy o cykle. W normalnym biznesowym juz nie powinien się pojawiać. Eksperyment (null) się nie udał.
Stwórca NULLa pisze tak:
Null mistake

0

Dzięki bardzo! idąc za wskazówkami, pozmieniałem kod w moim hobbystycznym projekcie na m.in

   Optional.ofNullable(source.getExerciseLogs()).ifPresentOrElse(
                        x -> {
                            List<ExerciseLogResponse> exerciseLogResponses = convertIntoExerciseLogResponse(source.getExerciseLogs());
                            trainingLogResponse.setExerciseLogs(exerciseLogResponses);
                        },
                        () -> trainingLogResponse.setExerciseLogs(new LinkedList<>())
                );

kod ten działa u mnie w intelij idea, ale niestety na heroku dostaje:

-----> Gradle app detected
-----> Spring Boot detected
-----> Installing JDK 1.8... done
-----> Building Gradle app...
-----> executing ./gradlew build -x test
       :compileJava/tmp/build_04568c6641ab5c13ee1aa6fb86ac54bf/TrainingLogToTrainingLogResponseConverter.java:26: error: cannot find symbol
               Optional.ofNullable(source.getExerciseLogs()).ifPresentOrElse(
                                                            ^
         symbol:   method ifPresentOrElse((x)->{ Lis[...]s); },()->traini[...]<>()))
         location: class Optional<List<ExerciseLog>>

Nie za bardzo rozumiem co jest nie tak w podanym fragmencie kodu, bylbym wdzieczny za pomoc

0

rozwiązaniem tego problemu jest chyba, jakaś zmiana jaka zaszła z jdk8->jdk9 bo na jdk9 śmiga bez problemu

3

A tak byłoby fajniej:

   trainingLogResponse.setExerciseLogs( 
           Optional.ofNullable(source.getExerciseLogs()).map(x -> convertIntoExerciseLogResponse(x)).orElse( new LinkedList<>())
 ); 

albo

   trainingLogResponse.setExerciseLogs( 
           Optional.ofNullable(source.getExerciseLogs()).map(this::convertIntoExerciseLogResponse).orElse( Collections.emptyList())
 ); 
0

Piękne, ogromne dzięki :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1