Having to two different collection of objects say Set say A and List say B.
If set contains any object need to get the firstobject a string variable say objectA.getName() or else need to get the firstobject in List ObjectB.getPerson().getName() and if both the collection is empty null should be assigned to the string.
Below is my code:
Optional<String> name1 =a.stream().findfirst().map(P->p.getName());
String output = null;
if (name1.ispresent()) {
output = name1.get();
} else {
Optional<String> name2 =a.stream().findfirst().map(p1->p1.getPerson().getName());
if (name2.ispresent()) {
output = name2.get();
}
}
Here I am getting the correct value. Please help me to attain same using map in pair with orElse.
What about this?
Set<String> a = ...
List<String> b = ...
String output = a.stream()
.findFirst()
.map(p -> p.getName())
.orElseGet(() -> b.stream()
.findFirst()
.map(p1 -> p1.getPerson().getName())
.orElse(null));
The important part is the orElseGet method on the Optional. It is evaluated lazily.
Related
I am having the below given data structure.
In the given code block, Im trying to get Object Dc from the given HashMap dealCommits.
The piece of code will work if the map has got the object associated with the given key (cNumber) is available.
My problem is how to handle the null pointer in line (//5) when the given key is not found in the map.
It will be a great help if somebody can throw some light to amend this stream based code to handle the exception.
public class Dc {
private String cNumber;
private Optional<List<pTerms>> pTerms;
}
public class Dd {
private String cParty;
//Dc:cNumber is the Key
private Optional<Map<String,Dc>> dealCommits;
}
public class PTerms {
private String pType;
}
public String check(String tMonth,String cNumber,Dd dDetails)
{
Optional<DealPricingTerms> dealPricingTerms = dDetails
.getDealCommits().get()
.get(cNumber)
.getPTerms().get().stream() //5
.filter(dealPricingTerm ->
tMonth.equals(dealPricingTerm.getDeliveryPeriod()))
.findFirst();
return dealPricingTerms.isPresent()? "Success" : "failed";
}
You shouldn't call get() on your Optionals - and when you use Optional.map you have a nice way to wrap a null result from a Map get into another Optional:
Optional<PTerms> dealPricingTerms = dDetails
.getDealCommits().map(c -> c.get(cNumber))
.flatMap(dc -> dc.getPTerms())
.map(l -> l.stream())
.flatMap(s ->
s.filter(dealPricingTerm ->
tMonth.equals(dealPricingTerm.getDeliveryPeriod()))
.findFirst());
You have to add filter to check null before your condition filter.
.filter(Objects::nonNull)
for example,
List<String> carsFiltered = Optional.ofNullable(cars)
.orElseGet(Collections::emptyList)
.stream()
.filter(Objects::nonNull) //filtering car object that are null
.map(Car::getName) //now it's a stream of Strings
.filter(Objects::nonNull) //filtering null in Strings
.filter(name -> name.startsWith("M"))
.collect(Collectors.toList()); //back to List of Strings
So, I have an ArrayList of autogenerated strings. I want to find the first element that contains some character or else if there is no one element that matches this filter, to apply another filter. In another way, I want to return null object.
So I write this lambda expression:
str.stream()
.filter(s -> s.contains("q"))
.findFirst()
.orElseGet(() -> str.stream()
.filter(s -> s.contains("w"))
.findFirst()
.orElseGet(null))
But if there is no one element that matches this two filters I will have NullPointerException. How, can I get something like: return null?
Unless I'm missing something obvious, simply .orElse(null) instead of the last orElseGet. orElseGet accepts a Supplier and you pass a null, calling get() on a null reference, well...
An additional, simpler approach: you can filter on strings containing q or w, then sort to move those containing q first, find first, return null if the optional is empty:
str.stream()
.filter(s -> s.contains("q") || s.contains("w"))
.sorted((s1, s2) -> s1.contains("q") ? -1 : 1 )
.findFirst()
.orElse(null);
.sorted((s1, s2) -> s1.contains("q") ? -1 : 1 ) will move the strings containing "q" first. Since the stream has been filtered only on values containing either q or w, then returning null will only happen no element is retained.
The problem is Optional::orElseGet(null) which accepts a Supplier<T> and throws the NullPointerException.
Use the Optional::orElse(null) which accepts T which is String in your case.
The following code works:
List<String> str = Arrays.asList("a", "b", "c");
String output = str.stream()
.filter(s -> s.contains("q"))
.findFirst()
.orElseGet(() -> str.stream()
.filter(s -> s.contains("w"))
.findFirst()
.orElse(null)); // <-- HERE
System.out.println(output); // Prints null
Alternatively, use the Optional::orElseGet(Supplier<? extends T> other) to return null. The Supplier itself must be not null:
.orElseGet(() -> null));
orElseGet expects a Supplier, you need to pass a value, which is the case for orElse.
I wouldn't use Stream API here, one iteration is enough to solve the problem:
String wString = null;
for (String s : str) {
if (s.contains("q")) return s;
if (s.contains("w") && wString == null) wString = s;
}
return wString;
How can I filter a list using java8 streams and return the found element if it is the only element in the filtered list, otherwise(if there are more which meet the condition, or there is no result that meets the condition) return for example an Optional.empty()
I would need something like this:
Suppose I have a:
List<String> list = Arrays.asList("Apple","Banana","Peach");
then I want:
Optional<String> string = list.stream()
.filter(item -> item.startsWith("A"))
.findOne();
I know I can do it by:
boolean singleElement = list.stream()
.filter(item -> item.startsWith("A"))
.count() == 1;
String string = null;
if(singleElement){
string = list.stream().filter(item -> item.startsWith("A")).iterator().next();
}
but I was wondering if I can do it in a single stream?
Is there any single stream solution?
Not very pretty, but you could limit the stream to 2 elements, collect those in a List, and see if that list has exactly one element. This still has more than one line, and has some overhead for creating the list, but that overhead is limited (to a list of size 2) and it does not have to iterate the stream twice, either.
List<String> tmp = list.stream()
.filter(item -> item.startsWith("A"))
.limit(2)
.collect(Collectors.toList());
Optional<String> res = tmp.size() == 1 ? Optional.of(tmp.get(0)) : Optional.empty();
(My other idea was to use reduce((s1, s2) -> null) after limit(2) and reduce any two matches to null, but instead of returning an Optional.empty this will just raise an Exception, i.e. it does not work, but maybe this triggers some better (working) ideas.)
Update: It seems like while reduce raises an Exceptions, Collectors.reducing does not, and instead returns an Optional.empty as desired, so this also works, as shown in this answer to a very similar question. Still, I'd add limit(2) to make it stop early:
Optional<String> res = list.stream()
.filter(item -> item.startsWith("A"))
.limit(2)
.collect(Collectors.reducing((s1, s2) -> null));
(If you like this last part, please upvote the original answer.)
You could use google Guava library's MoreCollectors.onlyElement as below:
List<String> list = Arrays.asList("Apple", "Banana", "Peach");
String string = null;
try {
string = list.stream()
.filter(item -> item.startsWith("A"))
.collect(MoreCollectors.onlyElement());
} catch (NoSuchElementException | IllegalArgumentException iae) {
System.out.println("zero or more than one elements found.");
}
Optional<String> res = string == null ? Optional.empty() : Optional.of(string);
Notice it throws NoSuchElementException if there is no element and it throws IllegalArgumentException if there are more than one elements.
I don't know if this counts as a single operation to you, but you can do :
Arrays.asList("Apple", "Banana", "Peach")
.stream()
.collect(Collectors.collectingAndThen(
Collectors.partitioningBy(
x -> x.startsWith("A")),
map -> {
List<String> list = map.get(Boolean.TRUE);
return list.size() == 1 ? Optional.of(list.get(0)) : Optional.empty();
}));
I have a few Optional fields with String and Long values:
Optional<Long> id;
Optional<String> name;
Optional<String> lastname;
Optional<Long> number;
....
I would like to return List with contains all of the values. If e.g optional "name" is no present, should be stored empty String. Result of method should be List with values e.q: "1", "John", "", "5".
I made stream:
Stream fields = Stream.of(id, name, lastname, number);
But I have no idea what next.
Regards.
You can use:
List<String> list = Stream.of(id, name, lastname, number)
.map(op -> op.map(o -> o.toString()).orElse(""))
.collect(Collectors.toList());
On each optional in stream you will map it into it's String version using toString() from Object class and for null you will map it into empty String. Than, you will collect it into list.
You can use the map method of the stream to manipulate the content of your stream, something like the below code:
fields.map(field -> field.orElse("").toString());
The optional also has a map method that can be used when manipulating the stream:
fields.map(field -> field.map(x -> x.toString()).orElse(""));
This works :
List<String> result = fields.map(o -> o.orElse("")) // provide default value
.map(o -> o.toString()) // cast to String
.collect(Collectors.toList()); // collect into List
See it in action.
List<String> ls = Stream.of(a, b).filter(o -> o != null && !o.trim().equals("")).map(o -> o instanceof Long ? String.valueOf(o) : o).collect(Collectors.toList());
Create a stream
Add a filter which will keep the values if two condition are respected: they are not null and if it is true the string value is not empty (the trim() method permits to remove the empty chars which are on the left and the right of the value)
Use a map method in order to transform objects which are Long instances into String instances
Use a collect method in order to retrieve values
Using Java 8 stream what is the best way to map a List<Integer> when you have no output for the input Integer ?
Simply return null? But now my output list size will be smaller than my input size...
List<Integer> input = Arrays.asList(0,1,2,3);
List<Integer> output = input.stream()
.map(i -> {
Integer out = crazyFunction(i);
if(out == null || out.equals(0))
return null;
return Optional.of(out);
})
.collect(Collectors.toList());
I don’t get why you (and all answers) make it so complicated. You have a mapping operation and a filtering operation. So the easiest way is to just apply these operation one after another. And unless your method already returns an Optional, there is no need to deal with Optional.
input.stream().map(i -> crazyFunction(i))
.filter(out -> out!=null && !out.equals(0))
.collect(Collectors.toList());
It may be simplified to
input.stream().map(context::crazyFunction)
.filter(out -> out!=null && !out.equals(0))
.collect(Collectors.toList());
But you seem to have a more theoretical question about what kind of List to generate, one with placeholders for absent values or one with a different size than the input list.
The simple answer is: don’t generate a list. A List is not an end in itself so you should consider for what kind of operation you need this list (or its contents) and apply the operation right as the terminal operation of the stream. Then you have your answer as the operation dictates whether absent values should be filtered out or represented by a special value (and what value that has to be).
It might be a different answer for different operations…
Replace the map call with flatMap. The map operation produces one output value per input value, whereas the flatMap operation produces any number of output values per input value -- include zero.
The most straightforward way is probably to replace the check like so:
List<Integer> output = input.stream()
.flatMap(i -> {
Integer out = crazyFunction(i);
if (out == null || out.equals(0))
return Stream.empty();
else
return Stream.of(out);
})
.collect(Collectors.toList());
A further refactoring could change crazyFunction to have it return an Optional (probably OptionalInt). If you call it from map, the result is a Stream<OptionalInt>. Then you need to flatMap that stream to remove the empty optionals:
List<Integer> output = input.stream()
.map(this::crazyFunctionReturningOptionalInt)
.flatMap(o -> o.isPresent() ? Stream.of(o.getAsInt()) : Stream.empty())
.collect(toList());
The result of the flatMap is a Stream<Integer> which boxes up the ints, but this is OK since you're going to send them into a List. If you weren't going to box the int values into a List, you could convert the Stream<OptionalInt> to an IntStream using the following:
flatMapToInt(o -> o.isPresent() ? IntStream.of(o.getAsInt()) : IntStream.empty())
For further discussion of dealing with streams of optionals, see this question and its answers.
Simpler variants of #Martin Magakian 's answer:
List<Integer> input = Arrays.asList(0,1,2,3);
List<Optional<Integer>> output =
input.stream()
.map(i -> crazyFunction(i)) // you can also use a method reference here
.map(Optional::ofNullable) // returns empty optional
// if original value is null
.map(optional -> optional.filter(out -> !out.equals(0))) // return empty optional
// if captured value is zero
.collect(Collectors.toList())
;
List<Integer> outputClean =
output.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList())
;
You can wrap the output into an Optional which may or may not contain a non-null value.
With an output: return Optional.of(out);
Without output: return Optional.<Integer>empty();
You have to wrap into an option because an array cannot contain any null value.
List<Integer> input = Arrays.asList(0,1,2,3);
List<Option<Integer>> output = input.stream()
.map(i -> {
Integer out = crazyFunction(i);
if(out == null || out.equals(0))
return Optional.<Integer>empty();
return Optional.of(out);
})
.collect(Collectors.toList());
This will make sure input.size() == output.size().
Later on you can exclude the empty Optional using:
List<Integer> outputClean = output.stream()
.filter(Optional::isPresent)
.map(i -> {
return i.get();
})
.collect(Collectors.toList());