I know I can filter a stream to get only those elements that are not null, and then do with them whatever I need. Something like this:
myList.stream().filter(element -> element != null).doOtherThings...
Is there a way to assert that the elements are not null in a stream function, so that it goes through all elements and if it finds one being null, it throws an exception? I've been thinking of something like the following:
myList.stream().assert(Objects::nonNull).doOtherThings...
Use something like
.map(Objects::requireNonNull)
You just need to apply an operation which will throw an exception, but otherwise passes the argument through.
Although, unless there is a good reason not to iterate the list multiple times, it might be clearer to separate the checking and the processing:
if (myList.stream().anyMatch(Objects::isNull)) {
throw ...
}
// Do things with list.
There are some very good suggestions already. Allow me to supplement. If what you are after is an assertion as in an assert statement, I would like to make this explicit in the code in order to guide the reader about my purpose. To assert that your original list doesn’t contain any nulls:
assert ! myList.contains(null);
If the assertion is to be checked somewhere down the stream pipeline, the simple way is:
assert myList.stream().map(this::transform).allMatch(Objects::nonNull);
If you don’t want to create a separate stream for the assertion but prefer to assert in the middle of your existing stream pipeline, use for example:
myList.stream()
.peek(e -> { assert e != null; })
.toArray();
You may worry that the use of peek is not so nice, which is also why I mention this option last. peek is documented to exist “mainly to support debugging” (quote taken out of its context), so you may say that it’s related to the purpose of assert and thus defend its use in this case.
To the map method I prefer to use peek method. I think it is more expressive then uing map method that has to return some value.
list.stream()
.peek(Objects::requireNonNull)
However what i think is hard to understand is that stream is not executed until the collect() is called. That is why doing this kind of conditional logic is hard using streams. To be honest if you want to achieve the desired effect you have to do something like this.
list.stream()
.peek(Objects::requireNonNull)
.collect(Collectors.toList())
.stream()
.map(t -> do whatever ... )
Related
Faced to some interesting issue: for example, I have to choose some solutions, depending on whether my List<> is blank or not, but I don't want to use simple if-statement for refactoring reasons (for example, there are three ugly inner if-s). If I had a nullable object, I could use the Optional::ifPresentOrElse solution, but what if the array is not null but just empty? are there any built-in language solutions? I understand that I could write something like ListOptional, create my own ListOptional::isNotEmptyOrElse there, but perhaps there is another solution?
Understand Optional as a wrapper against a possibly null instance providing chainable null-safe methods. Suggested ListOptional doesn't make to me any sense as null and empty lists semantically represent the same - a bunch of nothing.
If you want to use Optional, you must filter the single list in it whether is empty or not and provide an alternative:
List<String> nonEmpty = Optional.of(list)
.filter(l -> !l.isEmpty()) // is the list empty?
.orElseGet(() -> Arrays.asList("Hi", "Bye")); // if so, yield a default one
How is this better than using a ternary operator is questionable. I see no advantage over using this or if-else construct or a wrapper from a 3rd party library:
if (list.isEmpty() {
list = Arrays.asList("Hi", "Bye");
}
A built-in language solution for handling potentially empty collections is Stream API as declarative calls of chained methods, that are not executed on Stream from an empty collection. You can understand Stream as a wrapper against a possibly empty collection with the goal of processing each element. The same goes to the Optional with a difference a single instance is handled (regardless of whether it is a collection or not).
List<String> list = Collections.emptyList(); // empty list
List<String> updated = list.stream()
.filter(str -> str.startsWith("A") // won't happen
.map(String::toLowerCase) // won't happen
.collect(Collectors.toList()); // yields empty list
I'm trying to get used to using lambda expressions, but I frequently get caught up against something basic like this:
public List<Location> findAllAccessByUser(User user) {
return listDao.getAccessList(user).stream()
.filter(list -> findBySubOrgId(list.getOwnerOrg().getId()).isPresent())
.map(list -> findBySubOrgId(list.getOwnerOrg().getId()).get())
.collect(Collectors.toList());
}
This method
Gets a list of AccessList objects,
reads the subOrgId property from each object
uses the findBySubOrgId() method to return an (Optional) Location object.
Collect the objects into a list of Location objects.
Since the findBySubOrgId() returns an Optional which may not be present, I figure I need to filter it so the return List doesn't contain any empty elements. But then I have the repeat call to the same method, which seems wasteful.
Ordinarily I'd assign it to a variable and reuse that, but I can't find a reference to how to do this with lambdas -- or if it's even necessary.
Alternately I could put a conditional in the map() expression instead, but again I'm not sure how to do this and be sure to remove nulls.
As written it works exactly as I expect, but I always try to optimize my code, and it never hurts to learn the right way to do things. What is the "correct" way to rewrite this? Or is it fine as is?
return listDao.getAccessList(user).stream()
.map(list -> findBySubOrgId(list.getOwnerOrg().getId()))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList())
I know that once we create the stream off of a collection we should not modify collection while consuming the stream, However not sure if following approach works where I am modifying the entry inside the map and not adding or removing anything from it. Also, is this the right way to stream the map always and consume it ?
creepyCategoryStatuses.entrySet().stream().forEach(entry -> {
String creepyBlockResponse = (String) getBlockResponse(entry.getKey());
if (creepyBlockResponse.equalsIgnoreCase("block")){
entry.setValue(true);
//OR creepyCategoryStatuses(entry.getKey(), true);
}
});
This kind of modification is no problem as setting the value of an entry is not a structural modification. However, it’s worth noting that there are more Java 8 features than the Stream API or the forEach method:
creepyCategoryStatuses.replaceAll((key,value)->
((String)getBlockResponse(key)).equalsIgnoreCase("block")||value
);
does the job much easier. Note that ||value will retain the old value if the condition evaluates to false as in your original code.
Yes, such usage of Map seems to be legit. Note that in this case you don't need the stream. You can simply use
creepyCategoryStatuses.entrySet().forEach(entry -> {...});
According to your use-case, you could use replaceAll here:
creepyCategoryStatuses.replaceAll((k, v) -> ((String) getBlockResponse(k)).equalsIgnoreCase("block") ? true : v);
I always favor functional paradigms, so I would collect the new data into a new map, but that's a matter of taste.
I am trying to change some for-each loops to lambda forEach()-methods to discover the possibilities of lambda expressions. The following seems to be possible:
ArrayList<Player> playersOfTeam = new ArrayList<Player>();
for (Player player : players) {
if (player.getTeam().equals(teamName)) {
playersOfTeam.add(player);
}
}
With lambda forEach()
players.forEach(player->{if (player.getTeam().equals(teamName)) {playersOfTeam.add(player);}});
But the next one doesn't work:
for (Player player : players) {
if (player.getName().contains(name)) {
return player;
}
}
with lambda
players.forEach(player->{if (player.getName().contains(name)) {return player;}});
Is there something wrong in the syntax of the last line or is it impossible to return from forEach() method?
The return there is returning from the lambda expression rather than from the containing method. Instead of forEach you need to filter the stream:
players.stream().filter(player -> player.getName().contains(name))
.findFirst().orElse(null);
Here filter restricts the stream to those items that match the predicate, and findFirst then returns an Optional with the first matching entry.
This looks less efficient than the for-loop approach, but in fact findFirst() can short-circuit - it doesn't generate the entire filtered stream and then extract one element from it, rather it filters only as many elements as it needs to in order to find the first matching one. You could also use findAny() instead of findFirst() if you don't necessarily care about getting the first matching player from the (ordered) stream but simply any matching item. This allows for better efficiency when there's parallelism involved.
I suggest you to first try to understand Java 8 in the whole picture, most importantly in your case it will be streams, lambdas and method references.
You should never convert existing code to Java 8 code on a line-by-line basis, you should extract features and convert those.
What I identified in your first case is the following:
You want to add elements of an input structure to an output list if they match some predicate.
Let's see how we do that, we can do it with the following:
List<Player> playersOfTeam = players.stream()
.filter(player -> player.getTeam().equals(teamName))
.collect(Collectors.toList());
What you do here is:
Turn your input structure into a stream (I am assuming here that it is of type Collection<Player>, now you have a Stream<Player>.
Filter out all unwanted elements with a Predicate<Player>, mapping every player to the boolean true if it is wished to be kept.
Collect the resulting elements in a list, via a Collector, here we can use one of the standard library collectors, which is Collectors.toList().
This also incorporates two other points:
Code against interfaces, so code against List<E> over ArrayList<E>.
Use diamond inference for the type parameter in new ArrayList<>(), you are using Java 8 after all.
Now onto your second point:
You again want to convert something of legacy Java to Java 8 without looking at the bigger picture. This part has already been answered by #IanRoberts, though I think that you need to do players.stream().filter(...)... over what he suggested.
If you want to return a boolean value, then you can use something like this (much faster than filter):
players.stream().anyMatch(player -> player.getName().contains(name));
This what helped me:
List<RepositoryFile> fileList = response.getRepositoryFileList();
RepositoryFile file1 = fileList.stream().filter(f -> f.getName().contains("my-file.txt")).findFirst().orElse(null);
Taken from Java 8 Finding Specific Element in List with Lambda
You can also throw an exception:
Note:
For the sake of readability each step of stream should be listed in new line.
players.stream()
.filter(player -> player.getName().contains(name))
.findFirst()
.orElseThrow(MyCustomRuntimeException::new);
if your logic is loosely "exception driven" such as there is one place in your code that catches all exceptions and decides what to do next. Only use exception driven development when you can avoid littering your code base with multiples try-catch and throwing these exceptions are for very special cases that you expect them and can be handled properly.)
I know the subject may be a bit in advance as the JDK8 is not yet released (and not for now anyway..) but I was reading some articles about the Lambda expressions and particularly the part related to the new collection API known as Stream.
Here is the example as given in the Java Magazine article (it is an otter population algorithm..):
Set<Otter> otters = getOtters();
System.out.println(otters.stream()
.filter(o -> !o.isWild())
.map(o -> o.getKeeper())
.filter(k -> k.isFemale())
.into(new ArrayList<>())
.size());
My question is what happen if in the middle of the Set internal iteration, one of the otter is null?
I would expect a NullPointerException to be thrown but maybe am I still stuck in the previous development paradigm (non-functional), can someone enlighten me as how this should be handled?
If this really throw a NullPointerException, I find the feature quite dangerous and will have to be used only as below:
Developer to ensure there is no null value (maybe using a previous
.filter(o -> o != null))
Developer to ensure the application is never
generating null otter or a special NullOtter object to deal with.
What is the best option, or any other option?
Although the answers are 100% correct, a small suggestion to improve null case handling of the list itself with Optional:
List<String> listOfStuffFiltered = Optional.ofNullable(listOfStuff)
.orElseGet(Collections::emptyList)
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
The part Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList) will allow you to handle nicely the case when listOfStuff is null and return an emptyList instead of failing with NullPointerException.
Stuart's answer provides a great explanation, but I'd like to provide another example.
I ran into this issue when attempting to perform a reduce on a Stream containing null values (actually it was LongStream.average(), which is a type of reduction). Since average() returns OptionalDouble, I assumed the Stream could contain nulls but instead a NullPointerException was thrown. This is due to Stuart's explanation of null v. empty.
So, as the OP suggests, I added a filter like so:
list.stream()
.filter(o -> o != null)
.reduce(..);
Or as tangens pointed out below, use the predicate provided by the Java API:
list.stream()
.filter(Objects::nonNull)
.reduce(..);
From the mailing list discussion Stuart linked:
Brian Goetz on nulls in Streams
Current thinking seems to be to "tolerate" nulls, that is, to allow them in general, although some operations are less tolerant and may end up throwing NPE. See the discussion of nulls on the Lambda Libraries expert group mailing list, specifically this message. Consensus around option #3 subsequently emerged (with a notable objection from Doug Lea). So yes, the OP's concern about pipelines blowing up with NPE is valid.
It's not for nothing that Tony Hoare referred to nulls as the "Billion Dollar Mistake." Dealing with nulls is a real pain. Even with classic collections (without considering lambdas or streams) nulls are problematic. As fge mentioned in a comment, some collections allow nulls and others do not. With collections that allow nulls, this introduces ambiguities into the API. For example, with Map.get(), a null return indicates either that the key is present and its value is null, or that the key is absent. One has to do extra work to disambiguate these cases.
The usual use for null is to denote the absence of a value. The approach for dealing with this proposed for Java SE 8 is to introduce a new java.util.Optional type, which encapsulates the presence/absence of a value, along with behaviors of supplying a default value, or throwing an exception, or calling a function, etc. if the value is absent. Optional is used only by new APIs, though, everything else in the system still has to put up with the possibility of nulls.
My advice is to avoid actual null references to the greatest extent possible. It's hard to see from the example given how there could be a "null" Otter. But if one were necessary, the OP's suggestions of filtering out null values, or mapping them to a sentinel object (the Null Object Pattern) are fine approaches.
If you just want to filter null values out of a stream, you can simply use a method reference to java.util.Objects.nonNull(Object). From its documentation:
This method exists to be used as a Predicate, filter(Objects::nonNull)
For example:
List<String> list = Arrays.asList( null, "Foo", null, "Bar", null, null);
list.stream()
.filter( Objects::nonNull ) // <-- Filter out null values
.forEach( System.out::println );
This will print:
Foo
Bar
An example how to avoid null e.g. use filter before groupingBy
Filter out the null instances before groupingBy.
Here is an example
MyObjectlist.stream()
.filter(p -> p.getSomeInstance() != null)
.collect(Collectors.groupingBy(MyObject::getSomeInstance));
If you do not want to iterate two times (filter + map or any). Try this.
private static void trimAll() {
String[] emtLne = {"", " ", " cc ", null, " xx "};
System.out.println(Arrays.stream(emtLne).map(val -> (val != null) ? val.trim() : "").collect(Collectors.joining()));
}
Output
ccxx