Wie findet man in Java den längsten String in einem Array von Strings?
Die Lösung unten liefert Optional.empty() wenn strings gleich null oder leer ist, oder aber alle Einträge im Array null sind:
var result = Objects.nonNull( strings )  
  ? Arrays.stream( strings ) 
    .filter( Objects::nonNull ) 
    .max( Comparator.comparingInt( String::length ) )  
  : Optional.empty(); 
oder so:
var result = Optional.ofNullable( strings ) 
  .flatMap( s -> Arrays.stream( s ) 
    .filter( Objects::nonNull ) 
    .max( Comparator.comparingInt( String::length ) )  
  ); 
Allerdings sollte man im letzten Fall den Typ von result vielleicht besser explizit spezifizieren:
Optional<String> result = Optional.ofNullable( strings ) 
  .flatMap( s -> Arrays.stream( s ) 
    .filter( Objects::nonNull ) 
    .max( Comparator.comparingInt( String::length ) )  
  ); 
Will man eine NullPointerException für den Fall strings == null oder wenn ein Eintrag im Array null ist, dann geht es auch kürzer:
var result = Arrays.stream( strings ) 
  .max( Comparator.comparingInt( String::length ) ); 
Mit einer ausführlicheren Fehlermeldung für strings == null ginge auch:
var result = Arrays.stream( Optional.ofNullable( strings ) 
    .orElseThrow( () -> new Error( "strings is null" ) ) 
  .filter( Objects::nonNull ) 
  .max( Comparator.comparingInt( String::length ) ); 
Natürlich kann man auch null liefern, wenn strings == null ist, und Optional.empty() nur für ein leeres Array:
var result = Objects.nonNull( strings )  
  ? Arrays.stream( strings ) 
    .filter( Objects::nonNull ) 
    .max( Comparator.comparingInt( String::length ) )  
  : null; 
Wenn man der zu schreibenden Klasse die Zeilen
import static java.util.Arrays.*; 
import static java.util.Comparator.*; 
import static java.util.Objects.*; 
import static java.util.Optional.*; 
voranstellt, dann sieht der jeweilige Code so aus:
var result = nonNull( strings ) ? stream( strings ).filter( Objects::nonNull ).max( comparingInt( String::length ) ) : empty(); 
var result = ofNullable( strings ).flatMap( s -> stream( s ).filter( Objects::nonNull ).max( comparingInt( String::length ) ) ); 
Optional<String> result = ofNullable( strings ).flatMap( s -> stream( s ).filter( Objects::nonNull ).max( comparingInt( String::length ) ) ); 
var result = stream( strings ).max( comparingInt( String::length ) ); 
var result = stream( ofNullable( strings ).orElseThrow( () -> new Error( "strings is null" ) ).filter( Objects::nonNull ).max( comparingInt( String::length ) ); 
var result = nonNull( strings ) ? stream( strings ).filter( Objects::nonNull ).max( comparingInt( String::length ) ) : null; 
Und ja, das ist alles Java …
Als Traditionalist würde man so vorgehen:
String longestString = null; 
if( Objects.nonNull( strings ) ) 
{ 
  ScanLoop: for( final var s : strings ) 
  { 
    if( Objects.isNull( s ) ) continue ScanLoop; 
    if( Objects.isNull( longestString ) || (s.length() > longestString.length()) ) 
    { 
      longestString = s; 
    } 
  }  //  ScanLoop: 
} 
longestString ist null, wenn entweder strings == null ist, oder das Array leer ist, oder nur null enthält. Natürlich könnte man das auch noch schön in eine Methode verpacken …
Man könnte natürlich auch auf die Idee kommen, das Array nach der Größe zu sortieren:
String longestString = null; 
if( Objects.nonNull( strings ) && (strings.length > 0) ) 
{ 
  Arrays.sort( strings, Comparator.compareInt( String::length ).reversed(); 
  longestString = strings [0]; 
} 
Das sieht im Quellcode zwar schön kurz aus, aber ist, was die Laufzeit angeht, eine Katastrophe – zumindest für Arrays mit einer relevanten Größe; bei kleinen Arrays sollten alle Lösungen etwa ähnlich schnell sein.
Der Grund dafür ist, dass für die Sortierung alle Einträge mehrfach besucht werden, bis dann der längste String am Ende auf Position 0 steht.
Zudem verändert die Sortierung auch den Eingangsparameter strings; ist das unerwünscht, müßte man vorher eine Kopie davon machen. Auf modernen Systemen sollte das nicht so schnell zu Speicherplatzproblemen führen (es werden ja nur die Referenzen kopiert, nicht die Strings selber), aber man weiß ja nie … und wenn man das sortierte Array nicht noch für etwas anderes braucht, kann man sowohl den Speicher wie auch die Zyklen locker einsparen.
Wo wir gerade bei Laufzeit sind: für kleine bis mittelgroße Arrays ist vermutlich der "traditionelle" Ansatz der schnellste, aber wenn das Array wirklich groß wird, dann laufen die Stream-basierten Implementierungen so richtig zur Höchstform auf, insbesondere, wenn man den Stream explizit parallelisiert:
var result = Objects.nonNull( strings )  
  ? Arrays.stream( strings ) 
    .parallel() 
    .filter( Objects::nonNull ) 
    .max( Comparator.comparingInt( String::length ) )  
  : null; 
Für kleine Arrays dürfte das allerdings kontraproduktiv sein …