Eine null-geschützte erweiterte For-Schleife

Hallo,

da ich in einem Projekt auch null-Werte für Listen zurückbekommen kann oder auch will brauche ich null-geschützte erweiterte For-Schleifen.

Hier mein Code:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Application {

	public static void main(String[] args) {
		List<String> emptyStringList = new ArrayList<String>();
		List<String> notEmptyStringList = new ArrayList<String>(Arrays.asList("a", "b", "c"));
		
		System.out.println("Trying three lists with the guarded enhanced for loop:
");
		System.out.println("First: with an not empty list:");
		guardedEnhancedForLoop(notEmptyStringList);
		System.out.println("Second: with an empty list:");
		guardedEnhancedForLoop(emptyStringList);
		System.out.println("Third: with null:");
		guardedEnhancedForLoop(null);
		
		System.out.println("
");
		System.out.println("Trying three lists with the standard enhanced for loop:");
		System.out.println("First: with an not empty list:");
		standardEnhancedforLoop(notEmptyStringList);
		System.out.println("Second: with an empty list:");
		standardEnhancedforLoop(emptyStringList);
		System.out.println("Third: with null:");
		standardEnhancedforLoop(null);
		System.out.println("End of the test.");
	}

	private static <T> void guardedEnhancedForLoop(List<String> stringList) {
		System.out.println("	The for loop will be executed.");
		
		try {
			int i = 0;
			for (String currentString : (List<String>)(guard(stringList))) {
				if (i == 0) {
					System.out.println("	Inside the for loop.");
				}
				System.out.println("		The string is: " + currentString);
			}
			System.out.println("	The for loop was finished.
");
			
			System.out.println("	The guarded enhanced for loop is really guarded!
");
		} 
		catch(NullPointerException ex) {
			System.out.println("	An unexpected NullPointerException occured! The guarded enhanced for loop is not really guarded!
");
		}
		
	}

	private static void standardEnhancedforLoop(List<String> stringList) {
		System.out.println("	The for loop will be executed.");
		
		try {
			int i = 0;
			for (String currentString : stringList) {
				if (i == 0) {
					System.out.println("	Inside the for loop.");
				}
				System.out.println("		The string is: " + currentString);
			}
			System.out.println("	The for loop was finished.
");
			
			System.out.println("	The unguarded enhanced for loop did not throw an NullPointerException for list '" + stringList + "'.
");
		}
		catch (NullPointerException ex){
			System.out.println("	The unguarded enhanced for loop throws an NullPointerException for list '" + stringList + "'.
");
		}
	}

	private static <T> List<T> guard(List<T> toGuard) {
		return (toGuard == null) ? new ArrayList<T>() : toGuard;
	}
	
}

Jetzt mein Vorschlag:

Könnte man dies nicht in der erweiterten For-Schleife mit Index verwenden?

Falk

[quote=Falk]da ich in einem Projekt auch null-Werte für Listen zurückbekommen kann[/quote]Das ist schon doof

[quote=Falk;135327]oder auch will[/quote]Das ist noch doofer!
Den Grund lieferst Du gleich mit: es werden NullChecks benötigt.

Lass Dir doch einfach leere Listen zurück liefern. Wenn das Collections.emptyList() ist bekommt man sogar ein Singelton…

und dann wäre natürlich noch die Frage, warum der Null-Check auf die Liste selbts nicht explizit gemacht werden darf…

bye
TT

Okay, man sollte auch alles ganz genau lesen xD

Hier stand gar nichts :smiley:

Hintergrund ist der, dass ich einen Webservice rufe, welcher einen Unterschied macht zwischen ‘null’ und einer leeren Liste (bzw bei dem Rufen über SoapUI und einer XML-Struktur).

Wenn ich dann diesen Webservice mit SoapUI aufrufe und den leeren Tag von der Liste in meiner XML-Struktur drin habe, gibt es einen Fehler.
Wenn ich den Tag weglasse, funktioniert es.

Mein Parameterobjekt welches zur (De)Serialisierung verwendet wird, sollte demzufolge auch ‘null’ bei Feldern die eine Liste sind zurückliefern.

Ich bin doch an die Funktionsweise des Webservices gebunden und kann diesen nicht umprogrammieren!

Natürlich kann ich den Check explizit machen, da ich aber viele solche Überprüfungen brauche, ist es doch als Methode besser und kürzer.

Falk

for (String currentString : (List<String>)(guard(stringList))) {
kann man immerhin auch etwas kürzer als
for (String currentString : guard(stringList)) {
schreiben, deine guard-Methode ist generisch passend

diese Frage (oder Vorschlag inwiefern?) ist für mich unklar, was ist die ’ erweiterten For-Schleife mit Index’, das was hier im Blog steht, wie Suchmaschine findet? :wink:
Erweiterte For-Schleife mit Index - Blogs - Byte-Welt - Die Welt des Programmierens
bzw. gleich Version III :
https://forum.byte-welt.net/members/landei/79-erweiterte-schleife-mit-index-iii.html

eine normale for-Schleife mit Index wird sicher gehen wenn die guard-Liste idealerweise zwischengespeichert statt in jedem Schleifendurchlauf neu zu holen,
alle anderen Schleifen-Varianten genauso, oder welches Problem besteht?

das Programm ist geradezu vorbildlich mit Ausgaben, aber welche davon evtl. auf die Frage hindeutet, erkenne ich zumindest nicht…

The unguarded enhanced for loop throws an NullPointerException for list ‚null‘.

sollte nun wirklich nicht überraschen, unguarded + null …

[quote=Falk]Ich bin doch an die Funktionsweise des Webservices gebunden und kann diesen nicht umprogrammieren![/quote]Wie parst Du denn das XML? Nutzt Du dafür ein Framework?

Falls ja ist es wo möglich gar nicht die Liste, die Null ist, sondern das umschießende Tag:
[XML]

first Entry
second Entry
third Entry
fourth Entry

[/XML]

Wenn darin <YourCollectionTag/> fehlt, dann fehlt nicht die (eine) Liste, weil so ein Tag ja prinzipiell noch anderen Inhalt haben könnte…

Und ja, in diesem Fall brauchst Du einen NULL-Check, weil die wenigsten XML-Frameworks Default-Objekte zurückgeben. Obwohl: bei Jaxb könnte man das entsprechend einrichten…

bye
TT

Wie wäre es mit

public static <T> void loop(Iterable<T> iterable, Consumer<T> consumer) {
     Optional.ofNullable(iterable).ifPresent(l -> l.forEach(consumer));
}

...

List<String> list = ...
loop(list, e -> {
        System.out.println(e);
        System.out.println(e.length());
    }
);

Das kann man dann einfach zu einer Variante mit Index erweitern:

public static <T> void indexed(Iterable<T> iterable, ObjIntConsumer<T> consumer) {
    PrimitiveIterator.OfInt iterator = IntStream.iterate(0, i -> i + 1).iterator();
    Optional.ofNullable(iterable).ifPresent(l -> l.forEach(e ->  consumer.accept(e,iterator.next())));
}

...

List<String> list = ...
indexed(list, (e,i) -> {
        System.out.println(i + ":" + e);
        System.out.println(e.length());
    }
);

Die Liste ist wohl meistens nicht null

    public static <T> void loop(Iterable<T> iterable, Consumer<? super T> consumer) {
        iterable.forEach(t -> Optional.ofNullable(t).ifPresent(consumer));
   }

Ansonsten nochmal ein Optional drum - siehe anderer Thread :wink:

@Marco13 ,
deine Variante ist doch null-Test der Elemente, Schleifen-Code jeweils nur ausführen wenn ein Element nicht null ist?

ist ja ziemlich was anderes,
falls geplant, ruhig erwähnen


bei iterable = null auch NPE?.. (meistens nicht null heißt manchmal null)

Ohja, da war ich gedanklich GANZ woanders… (-> Freitag :rolleyes: )