W Javie 8 chcę zrobić coś z Optional
obiektem, jeśli jest obecny, i zrobić coś innego, jeśli go nie ma.
if (opt.isPresent()) {
System.out.println("found");
} else {
System.out.println("Not found");
}
Nie jest to jednak „funkcjonalny styl”.
Optional
ma ifPresent()
metodę, ale nie mogę połączyć orElse()
metody.
Dlatego nie mogę napisać:
opt.ifPresent( x -> System.out.println("found " + x))
.orElse( System.out.println("NOT FOUND"));
W odpowiedzi na @assylias nie sądzę, że Optional.map()
działa w następującym przypadku:
opt.map( o -> {
System.out.println("while opt is present...");
o.setProperty(xxx);
dao.update(o);
return null;
}).orElseGet( () -> {
System.out.println("create new obj");
dao.save(new obj);
return null;
});
W takim przypadku, gdy opt
jest obecny, aktualizuję jego właściwość i zapisuję w bazie danych. Kiedy nie jest dostępny, tworzę nowy obj
i zapisuję w bazie danych.
Uwaga w dwóch lambdach muszę wrócić null
.
Ale kiedy opt
będzie obecny, oba lambdas zostaną stracone. obj
zostanie zaktualizowany, a nowy obiekt zostanie zapisany w bazie danych. Wynika to z return null
pierwszej lambda. I orElseGet()
będzie nadal działać.
java
functional-programming
java-8
optional
smallufo
źródło
źródło
return null;
zreturn o;
(oba). Mam jednak silne przeczucie, że pracujesz w niewłaściwym miejscu. Powinieneś pracować w witrynie, która go wyprodukowałaOptional
. W tym miejscu powinien istnieć sposób wykonania żądanej operacji bez pośrednikaOptional
.ifPresent
zaprzecza to. Wszystkie inne metody odnoszą się do wartości, a nie do akcji.Odpowiedzi:
Dla mnie odpowiedź @Dane White jest OK, po pierwsze nie lubiłem używać Runnable, ale nie mogłem znaleźć żadnych alternatyw, tutaj kolejna implementacja wolała więcej
Następnie :
Aktualizacja 1:
powyższe rozwiązanie dla tradycyjnego sposobu rozwoju, gdy masz wartość i chcesz ją przetworzyć, ale co jeśli chcę zdefiniować funkcjonalność i wykonanie, to sprawdź poniższe ulepszenie;
Następnie może być użyty jako:
W tym nowym kodzie masz 3 rzeczy:
tak na marginesie, teraz jego nazwa jest bardziej opisowa, tak naprawdę jest Konsumentem
źródło
Jeśli używasz Java 9+, możesz użyć
ifPresentOrElse()
metody:źródło
Java 9 wprowadza
ifPresentOrElse, jeśli wartość jest obecna, wykonuje daną akcję z wartością, w przeciwnym razie wykonuje daną akcję pustą.
Zobacz doskonały Opcjonalny w ściągawce Java 8 .
Zawiera wszystkie odpowiedzi dla większości przypadków użycia.
Krótkie podsumowanie poniżej
ifPresent () - zrób coś, gdy opcja jest ustawiona
filter () - odrzuć (odfiltruj) pewne wartości opcjonalne.
map () - transformuj wartość, jeśli jest obecna
orElse () / orElseGet () - zmieniając pusty Opcjonalnie na domyślny T.
orElseThrow () - leniwie rzuca wyjątki na puste Opcjonalne
źródło
map
, ale trochę dziwne jest prosić o funkcjonalne rozwiązanie, abyś mógł zadzwonić do DAO. Wydaje mi się, że sensowniej byłoby zwrócić zaktualizowany / nowy obiekt z tegomap.orElse
bloku, a następnie zrobić to, co trzeba zrobić ze zwróconym obiektem.map
skupiam się na samym strumieniu i nie jest on przeznaczony do „robienia rzeczy z innym obiektem w zależności od statusu tego elementu w strumieniu”. Dobrze wiedzieć, żeifPresentOrElse
został dodany w Javie 9.Alternatywą jest:
Nie sądzę jednak, żeby poprawiało to czytelność.
Lub, jak sugerował Marko, użyj operatora trójskładnikowego:
źródło
new Object();
w pierwszej lambda, ale szczerze mówiąc, staje się to bardzo brzydkie. Chciałbym trzymać się if / else dla twojego zaktualizowanego przykładu.map
po prostu powrotuOptional
do łańcucha powoduje, że kod jest trudniejszy do zrozumienia, podczas gdymap
zakłada się, że dosłownie mapuje na coś.Innym rozwiązaniem byłoby użycie funkcji wyższego rzędu w następujący sposób
źródło
value -> () -> syso
oznacza ta część.String result = opt.map(value -> "withOptional").orElse("without optional");
Nie ma świetnego sposobu na zrobienie tego po wyjęciu z pudełka. Jeśli chcesz regularnie używać czystszej składni, możesz utworzyć klasę narzędzi, która pomoże:
Następnie możesz użyć importu statycznego w innym miejscu, aby uzyskać składnię zbliżoną do tego, czego szukasz:
źródło
Optional.ifPresentOrElse()
został dodany do JDK 9.Jeśli możesz używać tylko Java 8 lub starszej wersji:
1) jeśli nie masz
spring-data
jak dotąd najlepszego sposobu to:Teraz wiem, że nie jest to dla kogoś tak czytelne, a nawet trudne do zrozumienia, ale osobiście wygląda dobrze dla mnie i nie widzę innego płynnego sposobu na tę sprawę.
2) jeśli masz szczęście i możesz użyć
spring-data
najlepszego sposobu, to Optionals # ifPresentOrElse :Jeśli możesz korzystać z Java 9, zdecydowanie powinieneś skorzystać z:
źródło
Opisane zachowanie można osiągnąć za pomocą Vavr (wcześniej znanej jako JavaSlang), obiektowo-bibliotecznej biblioteki dla Java 8+, która implementuje większość konstrukcji Scali (będąc Scalą bardziej ekspresyjnym językiem z bogatszym systemem typów zbudowanym na JVM). Jest to bardzo dobra biblioteka do dodawania do projektów Java w celu pisania czystego kodu funkcjonalnego.
Vavr zapewnia monadę,
Option
która udostępnia funkcje do pracy z typem opcji, takie jak:fold
: aby zmapować wartość opcji na oba przypadki (zdefiniowane / puste)onEmpty
: pozwala wykonać,Runnable
gdy opcja jest pustapeek
: pozwala zużyć wartość opcji (jeśli jest zdefiniowana).Serializable
przeciwnie,Optional
co oznacza, że możesz bezpiecznie używać go jako argumentu metody i elementu instancji.Opcja jest zgodna z prawami monady w odróżnieniu od Opcjonalnej „pseudo-monady” Javy i zapewnia bogatszy interfejs API. I oczywiście możesz to zrobić z Opcjonalnej Javy (i na odwrót):
Option.ofOptional(javaOptional)
–Vavr koncentruje się na interoperacyjności.Przechodząc do przykładu:
Dalsza lektura
Brak odniesienia, błąd miliarda dolarów
Uwaga: To tylko bardzo mały przykład tego, co oferuje Vavr (dopasowanie wzorca, strumienie zwane leniwie ocenionymi listami, typy monadyczne, niezmienne zbiory, ...).
źródło
Innym rozwiązaniem może być:
Oto jak go używasz:
Lub w przypadku odwrotnego przypadku użycia:
Oto składniki:
„Kosmetycznie” ulepszony interfejs funkcji.
I opcjonalna klasa otoki dla ulepszeń:
To powinno załatwić sprawę i może służyć jako podstawowy szablon radzenia sobie z takimi wymaganiami.
Podstawowa idea tutaj jest następująca. W świecie programowania niefunkcjonalnego prawdopodobnie zaimplementowałbyś metodę przyjmującą dwa parametry, przy czym pierwszy to rodzaj kodu uruchamialnego, który powinien zostać wykonany w przypadku, gdy wartość jest dostępna, a drugim parametrem jest kod uruchamialny, który należy uruchomić w przypadku wartość nie jest dostępna. Ze względu na lepszą czytelność można użyć curlingu, aby podzielić funkcję dwóch parametrów na dwie funkcje po jednym parametrze. Tak właśnie zrobiłem tutaj.
Wskazówka: Opt zapewnia także inny przypadek użycia, w którym chcesz wykonać fragment kodu na wypadek, gdyby wartość nie była dostępna. Można to zrobić również za pośrednictwem Optional.filter.stuff, ale uważam, że jest to o wiele bardziej czytelne.
Mam nadzieję, że to pomaga!
Dobre programowanie :-)
źródło
Jeśli chcesz zapisać wartość:
źródło
Załóżmy, że masz listę i unikniesz
isPresent()
problemu (związanego z opcjami), którego możesz użyć,.iterator().hasNext()
aby sprawdzić, czy nie jest obecny.źródło