Stile funzionale di Java 8 Optional.ifPresent e if-not-Present?

In Java 8, voglio fare qualcosa su un object Optional se è presente, e fare un’altra cosa se non è presente.

 if (opt.isPresent()) { System.out.println("found"); } else { System.out.println("Not found"); } 

Questo non è uno “stile funzionale”, però.

Optional ha un metodo ifPresent() , ma non riesco a concatenare un metodo orElse() .

Quindi, non posso scrivere:

 opt.ifPresent( x -> System.out.println("found " + x)) .orElse( System.out.println("NOT FOUND")); 

In risposta a @assylias, non penso che Optional.map() funzioni per il seguente caso:

     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; }); 

    In questo caso, quando opt è presente, aggiorno la sua proprietà e salva nel database. Quando non è disponibile, creo un nuovo object e salvalo nel database.

    Nota nei due lambda devo restituire null .

    Ma quando opt è presente, verranno eseguiti entrambi i lambda. obj verrà aggiornato e un nuovo object verrà salvato nel database. Questo è dovuto al return null nel primo lambda. E orElseGet() continuerà a essere eseguito.

    Per me la risposta di @Dane White è OK, prima non mi piaceva usare Runnable ma non ho trovato nessuna alternativa, qui un’altra implementazione ho preferito di più

     public class OptionalConsumer { private Optional optional; private OptionalConsumer(Optional optional) { this.optional = optional; } public static  OptionalConsumer of(Optional optional) { return new OptionalConsumer<>(optional); } public OptionalConsumer ifPresent(Consumer c) { optional.ifPresent(c); return this; } public OptionalConsumer ifNotPresent(Runnable r) { if (!optional.isPresent()) r.run(); return this; } } 

    Poi :

     Optional o = Optional.of(...); OptionalConsumer.of(o).ifPresent(s ->System.out.println("isPresent "+s)) .ifNotPresent(() -> System.out.println("! isPresent")); 

    Aggiornamento 1:

    la soluzione di cui sopra per il modo tradizionale di sviluppo quando si ha il valore e si desidera elaborarlo, ma cosa succederebbe se volessi definire la funzionalità e l’esecuzione sarà allora, controlla sotto il miglioramento;

     public class OptionalConsumer implements Consumer> { private final Consumer c; private final Runnable r; public OptionalConsumer(Consumer c, Runnable r) { super(); this.c = c; this.r = r; } public static  OptionalConsumer of(Consumer c, Runnable r) { return new OptionalConsumer(c, r); } @Override public void accept(Optional t) { if (t.isPresent()) c.accept(t.get()); else r.run(); } } 

    Quindi potrebbe essere usato come:

      Consumer> c=OptionalConsumer.of(System.out::println, ()->{System.out.println("Not fit");}); IntStream.range(0, 100).boxed().map(i->Optional.of(i).filter(j->j%2==0)).forEach(c); 

    In questo nuovo codice hai 3 cose:

    1. può definire la funzionalità prima che l’object sia facile.
    2. non creando oggetti refrence per ogni Optional, solo uno, hai meno memoria quindi meno GC.
    3. sta implementando il consumatore per un utilizzo migliore con altri componenti.

    a proposito ora il suo nome è più descrittivo in realtà è Consumer>

    Se si utilizza Java 9, è ansible utilizzare il metodo ifPresentOrElse() :

     opt.ifPresentOrElse( value -> System.out.println("Found: " + value), () -> System.out.println("Not found") ); 

    Vedi eccellente Optional in Java cheat sheet .

    Fornisce tutte le risposte per la maggior parte dei casi d’uso.

    Breve riassunto qui sotto

    ifPresent () – fa qualcosa quando è impostato Opzionale

     opt.ifPresent(x -> print(x)); opt.ifPresent(this::print); 

    filter () – reject (filter out) determinati valori opzionali.

     opt.filter(x -> x.contains("ab")).ifPresent(this::print); 

    map () – trasforma il valore se presente

     opt.map(String::trim).filter(t -> t.length() > 1).ifPresent(this::print); 

    orElse () / oElseGet () – diventa vuoto Opzionale al valore predefinito T

     int len = opt.map(String::length).orElse(-1); int len = opt. map(String::length). orElseGet(() -> slowDefault()); //orElseGet(this::slowDefault) 

    orElseThrow () – rilascia pigramente eccezioni su vuoto Facoltativo

     opt. filter(s -> !s.isEmpty()). map(s -> s.charAt(0)). orElseThrow(IllegalArgumentException::new); 

    Un’alternativa è:

     System.out.println(opt.map(o -> "Found") .orElse("Not found")); 

    Comunque non penso che migliori la leggibilità.

    O come suggerito da Marko, usa un operatore ternario:

     System.out.println(opt.isPresent() ? "Found" : "Not found"); 

    Un’altra soluzione sarebbe quella di utilizzare le funzioni di ordine superiore come segue

     opt.map(value -> () -> System.out.println("Found " + value)) .orElse(() -> System.out.println("Not Found")) .run(); 

    Non c’è un ottimo modo per farlo fuori dalla scatola. Se si desidera utilizzare regolarmente la syntax del pulitore, è ansible creare una class di utilità per aiutare:

     public class OptionalEx { private boolean isPresent; private OptionalEx(boolean isPresent) { this.isPresent = isPresent; } public void orElse(Runnable runner) { if (!isPresent) { runner.run(); } } public static  OptionalEx ifPresent(Optional opt, Consumer consumer) { if (opt.isPresent()) { consumer.accept(opt.get()); return new OptionalEx(true); } return new OptionalEx(false); } } 

    Quindi puoi utilizzare un’importazione statica altrove per ottenere la syntax più vicina a ciò che stai cercando:

     import static com.example.OptionalEx.ifPresent; ifPresent(opt, x -> System.out.println("found " + x)) .orElse(() -> System.out.println("NOT FOUND")); 

    Un’altra soluzione potrebbe essere la seguente:

    Ecco come lo usi:

      final Opt opt = Opt.of("I'm a cool text"); opt.ifPresent() .apply(s -> System.out.printf("Text is: %s\n", s)) .elseApply(() -> System.out.println("no text available")); 

    O nel caso in cui nel caso dell’uso opposto il caso sia vero:

      final Opt opt = Opt.of("This is the text"); opt.ifNotPresent() .apply(() -> System.out.println("Not present")) .elseApply(t -> /*do something here*/); 

    Questi sono gli ingredienti:

    1. Piccola interfaccia di funzione modificata, solo per il metodo “elseApply”
    2. Miglioramento opzionale
    3. Un po ‘di curry 🙂

    L’interfaccia della funzione “esteticamente” migliorata.

     @FunctionalInterface public interface Fkt extends Function { default R elseApply(final T t) { return this.apply(t); } } 

    E la class wrapper facoltativa per il miglioramento:

     public class Opt { private final Optional optional; private Opt(final Optional theOptional) { this.optional = theOptional; } public static  Opt of(final T value) { return new Opt<>(Optional.of(value)); } public static  Opt of(final Optional optional) { return new Opt<>(optional); } public static  Opt ofNullable(final T value) { return new Opt<>(Optional.ofNullable(value)); } public static  Opt empty() { return new Opt<>(Optional.empty()); } private final BiFunction, Runnable, Void> ifPresent = (present, notPresent) -> { if (this.optional.isPresent()) { present.accept(this.optional.get()); } else { notPresent.run(); } return null; }; private final BiFunction, Void> ifNotPresent = (notPresent, present) -> { if (!this.optional.isPresent()) { notPresent.run(); } else { present.accept(this.optional.get()); } return null; }; public Fkt, Fkt> ifPresent() { return Opt.curry(this.ifPresent); } public Fkt, Void>> ifNotPresent() { return Opt.curry(this.ifNotPresent); } private static  Fkt> curry(final BiFunction function) { return (final X x) -> (final Y y) -> function.apply(x, y); } } 

    Questo dovrebbe fare il trucco e potrebbe servire come modello base su come gestire tali requisiti.

    L’idea di base qui è la seguente. In un mondo di programmazione di stile non funzionale probabilmente si implementerà un metodo che assume due parametri in cui il primo è un tipo di codice eseguibile che deve essere eseguito nel caso in cui il valore sia disponibile e l’altro parametro sia il codice eseguibile che deve essere eseguito nel caso il valore non è disponibile. Per una migliore leggibilità, è ansible utilizzare curring per dividere la funzione di due parametri in due funzioni di un parametro ciascuna. Questo è quello che fondamentalmente ho fatto qui.

    Suggerimento: Opt fornisce anche l’altro caso d’uso in cui si desidera eseguire una parte di codice nel caso in cui il valore non sia disponibile. Questo potrebbe essere fatto anche tramite Optional.filter.stuff ma ho trovato questo molto più leggibile.

    Spero possa aiutare!

    Buona programmazione 🙂

    Nel caso in cui desideri memorizzare il valore:

     Pair.of, List<>> output = opt.map(details -> Pair.of(details.a, details.b))).orElseGet(() -> Pair.of(Collections.emptyList(), Collections.emptyList()));