Check condition inside lambda expression using Stream API has SonarQube issues - java

So I have a code with ArrayList of Properties object.
#Getter
#Setter
class Properties {
private String type;
private String name;
private String value;
}
I have to check if list.get(index) is not null, then if list.get(index).getType() is not null, then list.get(index).getType() equals "something", then return the value.
Below is my code:
List<String> values = list.stream()
.filter(Objects::nonNull)
.filter(c -> c.getType() != null && c.getType().equals("something"))
.map(Properties::getValue)
.collect(Collectors.toList());
My problem is the second filter part has SonarQube issues. I have to implement it using static methods like it's done in map part and first filter.

I would like to know the rule of SonarQube highlighting any issue here. If there is an issue, it's definelty not related to the functionality but to the clarity.
The only improvement I see is to simplify the conditions within the second filter method:
List<String> values = list.stream()
.filter(Objects::nonNull)
.filter(c -> "something".equals(c.getType()))
.map(Properties::getValue)
.collect(Collectors.toList());
There is actual no need for null-check as long as you use a safe non-null string comparison which never yields in NullPointerException.

List<String> values = list.stream()
.filter(Objects::nonNull)
.filter(c -> Objects.equals("something", c.getType())
.map(Properties::getValue)
.collect(Collectors.toList());

Related

Is it better filter non Null objects with map operation or return Stream.empty() on flatMap operation?

I'm really curious about this simple performance/best_use/best_practice related case scenario:
If I have this simple snippet:
List<String> list = Arrays.asList("Hello1", "Hello2", "Hello3", "Jhon", "Doe", "Hello4");
list.stream()
.map(s -> {
if (s.contains("Hello")) {
return "World";
}
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
OR
list.stream()
.flatMap(s -> {
if (s.contains("Hello")) {
Stream.of("World");
}
return Stream.empty();
})
.collect(Collectors.toList());
NOTE: I know that maybe Map the String just to convert it to another String doesn't make much sense, but that is just for the example representation purposes, it could be a pojo or an integer or anything else.
Which one will perform better? or which would be the best option?
I'm trying to understand which is the better option in cases in which some conditional appears in the logic when we use streams chains.
Thank you.
I wouldn't create and wrapper like another Stream for avoiding nulls, nor return the null value for non matching strings, you can simply filter the strings having Hello word and then use map for value modification
list.stream()
.filter(s->s.contains("Hello"))
.map(s -> "world")
.collect(Collectors.toList());

Efficient way to compare two sets of different type

First of all I need some very efficient solution as I am comparing collections with >300k elements.
At the beginning we have two different classes
Class A {
String keyA;
String keyB;
String keyC;
}
Class B {
String keyA;
String keyB;
String keyC;
String name;
String code;
toA() {
return new A(keyA, keyB, keyC);
}
}
Both of them contains several fields which are composed key(in this example key of three columns = keyA keyB keyC)
This composed key makes calculation very long for primitive brute forces using nested loops.
So I figured out that the most efficient way would be to transform second class to first one using method toA
and then I can safely compare them using for example google's api using Sets efficiency
Set<A> collectionA = <300k of elements>
Set<B> collectionB = <300k of elements>
Set<A> collectionBConvertedToA = collectionB.stream().map(item -> item.toA()).collect(toSet())
Set<A> result = Sets.differences(collectionBConvertedToA, collectionA); // very fast first full scan comparison
Set<String> changedNames = result.stream()
.map(outer -> collectionB.stream()
// very slow second full scan comparison
.filter(inner -> inner.getKeyA().equals(outer.getKeyA())
&& inner.getKeyB().equals(outer.getKeyB())
&& inner.getKeyC().equals(outer.getKeyC()))
.findFirst()
.map(item -> item.getName()))
.collect(toSet());
log.info("changed names" + changedNames);
Guava Sets.differences can find differences on Sets >300k in less than 1/10 of second but later on I still have full scan anyway to collect names.
I am just guessing, but is there something like
Set<B> result = Sets.differences(setA, setB, a -> a.customHashCode(), b -> b.customHashCode(), (a, b) -> a.customEquals(b))
with custom hashCode and custom equals methods to keep Sets efficiency or there is some better pattern to make such comparison as I believe it seems like common problem ?
EDIT
I just figured out that I can just flip conversion to extended class
toB() {
return new B(keyA, keyB, keyC, null, null);
}
but then I need override hashCode and equals to use only those 3 fields and I still believe there is more elegant way
This is O(n^2) since you are streaming collectionB for each element in result. The following should work pretty fast:
Set<String> changedNames = collectionB.stream()
.filter(b -> collectionA.contains(b.toA())
.map(item -> item.getName()).collect(toSet());
We could stream the first set and for each A object, concatenate the three fields of A by a delimiter and collect it as a Set (Set<String>).
Then we go over the elements of the second set, compose a string based on the key fields of A and check if the above-computed set has it or not.
Set<String> keysOfA = collectionA.stream()
.map(a -> compose(a.getKeyA(), a.getKeyB(), a.getKeyC()))
.collect(Collectors.toSet());
Set<String> changedNames = collectionB.stream()
.filter(b -> !keysOfA.contains(compose(b.getKeyA(), b.getKeyB(), b.getKeyC())))
.map(b -> b.getName())
.collect(Collectors.toSet());
static String compose(String keyA, String keyB, String keyC) {
return keyA + "|" + keyB + "|" + keyC; //any other delimiter would work
}
With this you don't need the toA() method.
Second approach:
If class A implements equals and hashcode, then you can do like
Set<String> changedNames = collectionB.stream()
.filter(b -> !collectionA.contains(b.toA()))
.map(b -> b.getName())
.collect(Collectors.toSet());

Defaulting Optional orElse with Optional.empty in Java 8

Java 8 here. I need to search two lists of POJOs for a string and want to use the Stream/Optional APIs correctly.
If the name appears in the first list ("lunches") then I want to return an optional containing it. Else, if the name appears in the second list ("dinners") then I want to return an optional containing it. Otherwise I want to return Optional.empty() if the name doesn't existing in either list. My best attempt thus far:
public class Restaurant {
private String id;
private String name;
private List<Food> lunches;
private List<Food> dinners;
public Optional<Food> findFoodByName(String name) {
return Optional.of(lunches.stream()
.filter(food -> food.getName()
.equalsIgnoreCase(name))
.findFirst())
.orElse(dinners.stream()
.filter(food -> food.getName()
.equalsIgnoreCase(name))
.findFirst());
// .orElse(null); TODO: how to return empty optional if neither in 'lunches' nor 'dinners'?
}
}
Can anyone help me cross the finish line here?
Combine both the list using Stream.of and check for element or return Optional.empty()
Stream.of(lunches, dinners)
.flatMap(List::stream)
.filter(s -> s.getName()
.equalsIgnoreCase(name))
.findFirst();
As per the suggestion from #Holger you can also use Stream.concat to concat two streams and then check for element
Stream.concat(lunches.stream(), dinners.stream())
.filter(s -> s.getName()
.equalsIgnoreCase(name))
.findFirst();
You can do like this too:
Optional<Food> firstTry = lunches.stream()
.filter(f -> f.getName().equalsIgnoreCase(name))
.findFirst();
return firstTry.map(Optional::of)
.orElse(dinners.stream()
.filter(f -> f.getName().equalsIgnoreCase(name)).findFirst());
Or in Java9
firstTry.or(() -> dinners.stream().filter(s -> s.equalsIgnoreCase(name)).findFirst());
As #Slaw commented correctly use of orElseGet() avoid eagerly computing.
Optional<Food> firstTry = lunches.stream().filter(...)...findFirst();
Supplier<Optional<Food>> secondTry = () -> dinners.stream()...findFirst();
and at the end
return firstTry.map(Optional::of).orElseGet(secondTry);

Use same variable in filter() and map() of a Java 8 stream

To improve performance I want to use the same variable in both filter() and map() of a Java 8 stream.
Example-
list.stream()
.filter(var -> getAnotherObject(var).isPresent())
.map(var -> getAnotherObject(var).get())
.collect(Collectors.toList())
The called method getAnotherObject() looks like-
private Optional<String> getAnotherObject(String var)
In the above scenario I have to call the method getAnotherObject() twice.If I go with a regular for loop then I have to call the method getAnotherObject() only once.
List<String> resultList = new ArrayList<>();
for(String var : list) {
Optional<String> optionalAnotherObject = getAnotherObject(var);
if(optionalAnotherObject.isPresent()) {
String anotherObject = optionalAnotherObject.get();
resultList.add(anotherObject)
}
}
Even with stream I can put all my code in map()-
list.stream()
.map(var -> {
Optional<String> anotherObjectOptional = getAnotherObject(var);
if(anotherObjectOptional.isPresent()) {
return anotherObjectOptional.get();
}
return null;
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
But I believe there must be an elegant way using filter().
You can create a stream like this
list.stream()
.map(YourClass::getAnotherObject)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
YourClass refer to the name of the class where getAnotherObject method is defined
You can use flatMap. Usually this is used to flatten stuff, but here you can
map the element to that element if the optional has a value
map the element to an empty stream if the optional has no value
Like this:
stream
.map(x -> getAnotherObject(x))
.flatMap(x -> x.map(Stream::of).orElse(Stream.of())))

How to handle nullable lists using java 8?

I'm making a service call and trying to handle response.
Response might have a list of something. That list might be null.
Moreover, if list not null or not empty, then
it needs to be filtered.
In the code "entry" reference might be null if filtering gives nothing or response list is empty or null.
Currently i'm getting NPE when i try to use stream() on a null response list.
How can i handle this situation?
#Getter
public class ServiceResponse {
List<ResponseEntry> entryList;
}
#Getter
public class ResponseEntry {
String value;
}
ServiceResponse serviceResponse = service.getServiceResponse();
ResponseEntry entry = serviceResponse.getEntryList()
.stream()
.filter(e -> "expectedValue".equals(e.getValue()))
.findFirst()
.orElse(null);
if (entry == null) { ... }
if list not null or not empty, then it needs to be filtered.
No need for Optional here, as it's not intended to replace simple if checks.
ResponseEntry entry = null;
List<ResponseEntry> responseEntries = serviceResponse.getEntryList();
if(responseEntries != null && !responseEntries.isEmpty()){
entry = responseEntries.stream()
.filter(e -> "expectedValue".equals(e.getValue()))
.findFirst()
.orElse(null);
}
reads "if responseEntries is not null and responseEntries is not empty then apply the filter operation and find the first item or else null". Very readable.
On the other hand, the optional approach:
ResponseEntry entry = Optional.ofNullable(serviceResponse.getEntryList())
.orElseGet(() -> Collections.emptyList())
.stream()
.filter(e -> "expectedValue".equals(e.getValue()))
.findFirst();
if(!entry.isPresent()){ ... } // or entry.ifPresent(e -> ...) depending on the logic you're performing inside the block
unnecessarily creates objects that could be avoided and not really the intention of optional to be used as a substitute for simple "if" checks.
Stream.ofNullable (Java-9)
Returns a sequential Stream containing a single element, if non-null,
otherwise returns an empty Stream.
Current Code
ResponseEntry entry = serviceResponse.getEntryList() // List<ResponseEntry>
.stream() // NPE here // Stream<ResponseEntry>
.filter(e -> "expectedValue".equals(e.getValue())) // filter
.findFirst() // Optional<ResponseEntry>
.orElse(null); // or else null
Updated Code
ResponseEntry entry = Stream.ofNullable(serviceResponse.getEntryList()) // Stream<List<ResponseEntry>>
.flatMap(List::stream) // Stream<ResponseEntry>
.filter(e -> "expectedValue".equals(e.getValue())) // filter here
.findFirst() // Optional<ResponseEntry>
.orElse(null); // or else null
Optional.stream (Java-9)
returns a sequential Stream containing only that value, otherwise
returns an empty Stream.
ResponseEntry entry = Optional.ofNullable(serviceResponse.getEntryList())
.stream() // Stream<List<ResponseEntry>>
.flatMap(List::stream) // Stream<ResponseEntry>
.filter(e -> "expectedValue".equals(e.getValue())) // filter here
.findFirst() // Optional<ResponseEntry>
.orElse(null); // or else null
Optional.isEmpty(Java-11)
If a value is not present, returns true, otherwise false
Optional<ResponseEntry> entry = Optional.ofNullable(serviceResponse.getEntryList()) // Optional<List<ResponseEntry>>
.orElseGet(Collections::emptyList) // or else empty List
.stream() // Stream<ResponseEntry>
.filter(e -> "expectedValue".equals(e.getValue())) // filter
.findFirst(); // Optional<ResponseEntry>
if (entry.isEmpty()) { // !entry.isPresent in java-8
// Do your work here
}
In Java 9, you could use the new method Objects.requireNonNullElse(T,T):
Objects.requireNonNullElse(serviceResponse.getEntryList(),
Collections.emptyList())
Apache Commons Collections actually has a method ListUtils.emptyIfNull(List<T>) which returns an empty list if the argument list is null. That's even better, but Objects.requireNonNullElse is the closest thing to it in Java SE.
If you're restricted to just Java 8, then I agree with Aomine's answer that trying to do something like go through Optional is worse than an if statement.
You could simply use the ternary operator:
ServiceResponse serviceResponse = service.getServiceResponse();
List<ResponseEntry> list = serviceResponse.getEntryList();
ResponseEntry entry = (list == null ? Collections.emptyList() : list)
.stream()
.filter(e -> "expectedValue".equals(e.getValue()))
.findFirst()
.orElse(null);
if (entry == null) { ... }
Sometimes, traditional is better IMO.
Another option would be to use the Optional monad:
Optional<ResponseEntry> entry = Optional.ofNullable(serviceResponse.getEntryList()).flatMap(list ->
list.stream().filter(e -> "expectedValue".equals(e.getValue())).findFirst()
);
if (!entry.isPresent()) {
…
}
You might even use orElseGet instead of that if statement if your objective is to build (and return) a value, instead of executing a side effect.
I am new to Optional and I may be wrong. Logic can be written like below if you want to have logic including only optional.
ServiceResponse serviceResponse = service.getServiceResponse();
ResponseEntry entry =
Optional.of(CollectionUtils.isNotEmpty(serviceResponse.getEntryList()))
.filter(BooleanUtils::isTrue)
.stream()
.filter(e -> "expectedValue".equals(e.getValue()))
.findFirst()
.orElse(null);

Categories

Resources