Come già discusso , i progettisti dell'API non presumono che lo sviluppatore voglia trattare nullvalori e valori assenti allo stesso modo.
Se vuoi ancora farlo, puoi farlo esplicitamente applicando la sequenza
.map(Optional::ofNullable).findFirst().flatMap(Function.identity())
al flusso. Il risultato sarà un optional vuoto in entrambi i casi, se non c'è il primo elemento o se il primo elemento lo è null. Quindi nel tuo caso, puoi usare
String firstString = strings.stream()
.map(Optional::ofNullable).findFirst().flatMap(Function.identity())
.orElse(null);
per ottenere un nullvalore se il primo elemento è assente o null.
Se vuoi distinguere tra questi casi, puoi semplicemente omettere il flatMappassaggio:
Optional<String> firstString = strings.stream()
.map(Optional::ofNullable).findFirst().orElse(null);
System.out.println(firstString==null? "no such element":
firstString.orElse("first element is null"));
Questo non è molto diverso dalla tua domanda aggiornata. Devi solo sostituire "no such element"con "StringWhenListIsEmpty"e "first element is null"con null. Ma se non ti piacciono i condizionali, puoi ottenerlo anche come:
String firstString = strings.stream().skip(0)
.map(Optional::ofNullable).findFirst()
.orElseGet(()->Optional.of("StringWhenListIsEmpty"))
.orElse(null);
Ora, firstStringsarà nullse un elemento esiste ma è nulle sarà "StringWhenListIsEmpty"quando non esiste alcun elemento.