Using Optionals and forEach in Java 8, check for empty object - java-8

I would like to use Optionals with forEach in my example below, and am not sure about the correct approach.
Basically the functionality is as follows:
List<Long> myList;
List<Long> myResultList;
myList = getValues_A();
if (null != myList && !myList.isEmpty())
return;
for (Long singleVal : myList) {
List<Long> tempList = getValues_B(singleVal);
if (null != tempList && !tempList.isEmpty())
myResultList.addAll(tempList);
}
So I simple retrieve some data into myList, check if there is some value returned, and if so, I use the result to again retrieve data and put it in a final result list.
My idea with Optionals:
List<Long> myList;
List<Long> myResultList;
myList = getValues_A();
if (null != myList && !myList.isEmpty())
return;
myResult.forEach(itemToCheck -> Optional
.ofNullable(getValues_B(itemToCheck))
.ifPresent(myResultList::addAll));
Questions:
The first part:
myList = getValues_A();
if (null != myList && !myList.isEmpty())
return;
Is there any way to use Java 8 Optionals instead?
I.e.
myList = getValues_A();
if (!Optional.ofNullable(myList).isPresent())
return;
But this would only check for null and not if the object was empty (for which I also want to return). Can this be extended with a size check of the object within the Stream?
Also, misusing Optional's isPresent as a nullcheck only is bad coding practise I guess. Any other ideas?
The second part:
I assume that even empty objects will be attempted to be added to myResultList? Can this be somehow prevented in a similar approach, i.e. check if size = 0 within the stream?
myResult.forEach(itemToCheck -> Optional
.ofNullable(getValues_B(itemToCheck))
.ifPresent(myResultList::addAll));
Small sidenote: I can't use isEmpty(Object object) of org.apache.commons.lang3.ObjectUtils as I'm with version < 3.9.

I also think it is worth mentioning that besides whole reusing Optional is not good thing in any possible case(with which I agree). We also see in this approach that we create empty list and then altering its state by adding new elements. I thing if we can we should always avoid such solutions. Much cleaner approach is to instantiate list with its elements while declaring.

For getting rid of first part, you can make the getValues_A() function to return an Optional or an empty list instead of null.It make no sense to make any processing with Optional in this method.
Second part written with stream :
List<Long> myResultList = myList.stream().map(singleVal -> getValues_B(singleVal)).filter(Objects::nonNull).flatMap(List::stream).collect(Collectors.toList());
Each steps explained:
1. map(singleVal -> getValues_B(singleVal)) - each element of the list will be processed and you'll get a List as result for each.
2. filter(Objects::nonNull) - remove empty lists
3. flatMap(List::stream) - from stream of List<Long>,you'll obtain a stream of Long
4. collect(Collectors.toList()) - collect all resultList.

You may take advantage of the orELseGet() API of the Optional and the map/flatmap APIs of the stream to simplify your code.
List<Long> resultList = Optional.ofNullable(getValues_A())
.orElseGet(Collections::emptyList)
.stream()
.filter(Objects::nonNull)
.flatMap(l -> Optional.ofNullable(getValues_B(l))
.orElseGet(Collections::emptyList)
.stream()
.filter(Objects::nonNull))
.collect(Collectors.toList());

Related

Stream in java 8 for nested loop

I am trying to convert this piece of code into stream and filter but finding it really hard. help will be highly appreciated. Here is the code portion.
protected void processFacetData(final List<FacetData<SearchStateData>> facets){
final List<FacetValueData<SearchStateData>> facetValueEmptyDatas = new ArrayList<FacetValueData<SearchStateData>>();
for (final FacetData<SearchStateData> facetData : facets)
{
final List<FacetValueData<SearchStateData>> facetValueDatas = facetData.getValues();
for (final FacetValueData<SearchStateData> facetValueData : facetValueDatas)
{
if (facetValueData.getCount() == 0)
{
facetValueEmptyDatas.add(facetValueData);
}
}
facetValueDatas.removeAll(facetValueEmptyDatas);
}
}
There is no way that I can test the following code, based solely on the information in your question, but it looks like you need to use method flatMap.
facets.stream()
.flatMap(f -> f.getValues().stream())
.filter(f -> f.getCount() == 0)
.collect(Collectors.toList())
Method flatMap will return a single stream which you can think of as the concatenation of all the elements in all the lists of all the elements in the method parameter.
Then you filter for all the values in that stream where method getCount returns zero.
Finally you collect all the filtered elements into a single list.

How to return the count, while using nested foreach loops in the stream

I am using java8 streams to iterate two lists, In that one list contains some custom objects and another contains string.
With this, I have to call a method by passing custom object and sting as a input and then I have to get the count.
This is what I tried:
public int returnCode() {
/*int count = 0;
* list.forEach(x -> {
list2.forEach(p -> {
count+ = myDao.begin(conn, x.getCode(), p);
});
return count;
});*/
}
compiler is giving an error that count should be final.
Can anyone, give me how to do this in a better way.
What you're attempting to do is not possible as local variables accessed from a lambda must be final or effectively final i.e. any variable whose value does not change.
You're attempting to change the value of count in the lambda passed to the forEach hence the compilation error.
To replicate your exact code using the stream API, it would be:
int count = list.stream()
.limit(1)
.flatMapToInt(x -> list2.stream().mapToInt(p -> myDao.begin(conn, x.getCode(), p)))
.sum();
However, if you want to iterate over the entire sequence in list and not just the first then you can proceed with the following:
int count = list.stream()
.flatMapToInt(x -> list2.stream().mapToInt(p -> myDao.begin(conn, x.getCode(), p)))
.sum();
Lambdas mainly substitutes anonymous inner classes. Inside an anonymous inner class you can access only final local variables. Hence the same holds true with lambda expressions. Local variable is copied when JVM creates a lambda instance, hence it is counter intuitive to allow any update to them. So declaring the variable as final would solve the issue. But if you make it final you won't be able to do this, leading to another pitfall.
count+ = myDao.begin(conn, x.getCode(), p);
So your solution is not good and does not comply with lambda. So this will be a one way of doing it.
final int count = customObjects.stream()
.mapToInt(co -> strings.stream().mapToInt(s -> myDao.begin(conn, co.getCode(), s)).sum())
.sum();

Stream and Filter operations on a Map

I have an EdmPortfolio type that has id (int), name (String) and tags which is a map as its members.
EdmPortfolio say has an id 1, and name as Portfolio1 and Map could have the following values,
analyst, John
region, US
I have a List, At the end i want to have a Map which has all the map values combined from all portfolios. Another EdmPortfolio might have the id as 2, name as Portfolio2 and Map with values analyst, Smith
region , UK
I want to have a combined Map with Values
region 'US','UK'
analyst 'John','Smith'
analyst and region are the keys to the map.
It has both the maps combined. I have the following code but i am a little lost
List<Map<Tag,String>> portfolioTagsList = new ArrayList<>();
for (EdmPortfolio edmPortfolio : edmPortfolioList) {
Map<Tag,String> portfolioTags = edmPortfolio.getPortfolioTags().entrySet()
.stream()
.filter(e -> (e.getValue() != ""|| e.getValue() !=null))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));
portfolioTagsList.add(portfolioTags);
}
Map<Tag,String> finalTags = portfolioTagsList.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.joining(",",Map.Entry::getValue)));
I am getting nonstatic method cannot be referenced from static context. How do i achieve this?
Thanks for your time
I'd do something like:
Map<Tag,String> finalTags = edmPortfolioList.stream()
.flatMap(edmPortfolio -> edmPortfolio.getPortfolioTags().entrySet().stream())
.filter(e -> (e.getValue() != "" || e.getValue() !=null)) // this seems weird, but just keeping
.collect(Collectors.groupingBy(e -> e.getKey(),
Collectors.mapping(ev -> ev.getValue(),
Collectors.joining(",")));
BTW: Any reason to break that in two streams?
Unfortunately, “nonstatic method cannot be referenced from static context” is the error that javac often ends up when type inference fails, especially in the context of method references or lambda expressions. The actual cause could be a wrong generic type parameter, a forgotten import statement, the use of a lambda expression or method reference at an inappropriate place, or even a misplaced or forgotten brace somewhere.
In your case, it’s Collectors.joining(",",Map.Entry::getValue) as that collector has no parameter of a function type that could accept a method reference.
You should use Collectors.mapping(Map.Entry::getValue, Collectors.joining(",")) instead.
Besides that, follow BrunoJCM’s suggestion to use a single stream operation and pay attention to the filter condition. e.getValue() != "" || e.getValue() !=null makes no sense as a reference can never be both, a reference to "" and the null reference, hence, this condition is always fulfilled. You most likely wanted to express that the string must not be null and not an empty string. In this regard, you should not compare strings by reference but use equals. For testing for an empty string, there is the alternative to use isEmpty() instead of equals(""). So the condition should be e.getValue()!=null && !e.getValue().isEmpty(). Mind the order, as we can invoke isEmpty() only after having verified that it is not null.

Optional<T> does not handle null elements

As I experimented Optional<T> does not handle null elements, so in the following example it throws a NullPointerException in the last statement:
List<String> data = Arrays.asList("Foo", null, "Bar");
data.stream().findFirst().ifPresent(System.out::println);
data.stream().skip(1).findFirst().ifPresent(System.out::println);
So, I still have to explicitly deal with null and filter non-null elements, such as:
data.stream()
.filter(item -> item != null)
.skip(1)
.findFirst()
.ifPresent(System.out::println);
Is there any alternative that avoids dealing explicitly with null as: item != null
You can use .filter(Objects::nonNull) using the method Objects.nonNull(…) added for this purpose.
There is no way to avoid explicit filtering, unless you avoid having nulls in your source list in the first place.
Note that it would be strange if the Optional handled the null in this case as it would yield an empty optional which had the semantic of “there is no first element” which implies “the stream was empty” which is just wrong.
Dealing with nulls explicitly is the cleanest solution here as it also allows you to explicitly tell whether you want .filter(Objects::nonNull).skip(1), .skip(1).filter(Objects::nonNull)…
…or .map(s->s==null? "null-replacement": s).findFirst()
It really depends on what you want to do. If you want to treat null as a valid value, the answer is different than if you want to skip nulls.
If you want to keep "nulls" in your stream:
List<String> data = Arrays.asList("Foo", null, "Bar");
data.stream().map(Optional::ofNullable).findFirst().flatMap(Function.identity()).ifPresent(System.out::println); ;
data.stream().map(Optional::ofNullable).skip(1).findFirst().flatMap(Function.identity()).ifPresent(System.out::println);
If you want to remove nulls from your stream, use data.stream().filter(Objects::nonNull) to filter it out (or as you stated o -> o != null, whatever you prefer.

How does LINQ implement the SingleOrDefault() method?

How is the method SingleOrDefault() evaluated in LINQ? Does it use a Binary Search behind the scenes?
Better than attempting to explain in words, I thought I'd just post the exact code of implementation in the .NET Framework, retrieved using the Reflector program (and reformatted ever so slightly).
public static TSource SingleOrDefault<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
throw Error.ArgumentNull("source");
IList<TSource> list = source as IList<TSource>;
if (list != null)
{
switch (list.Count)
{
case 0:
return default(TSource);
case 1:
return list[0];
}
}
else
{
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
if (!enumerator.MoveNext())
return default(TSource);
TSource current = enumerator.Current;
if (!enumerator.MoveNext())
return current;
}
}
throw Error.MoreThanOneElement();
}
It's quite interesting to oberserve that an optimisation is made if the object is of type IList<T>, which seems quite sensible. It simply falls back to enumerating over the object otherwise if the object implements nothing more specific than IEnumerable<T>, and does so just how you'd expect.
Note that it can't use a binary search because the object doesn't necessarily represent a sorted collection. (In fact, in almost all usage cases, it won't.)
I would assume that it simply performs the query and if the result count is zero, it returns the default instance of the class. If the result count is one, it returns that instance, and if the result count is greater than one, it throws an exception.
I don't think it does any searching, it's all about getting the first element of the source [list, result set, etc].
My best guess is that it just pulls the first element. If there is no first it returns the default (null, 0, false, etc). If there is a first, it attempts to pull the second result. If there is a second result it throws an exception. Otherwise it returns the first result.

Resources