Convert OptionalDouble to Optional <java.lang.Double> - java

I have a method that builds a list and I want it to return the average of the list as an Optional value.
However, when I calculate the average value using Java 8, I always get the return value as an OptionalDouble.
How do I convert
OptionalDouble to Optional<Double>?
Below are my code for average calculation:
private static Optional<Double> averageListValue() {
// Build list
List<Double> testList = new ArrayList<>();
testList.add(...);
...
...
return testList.stream().mapToDouble(value -> value).average();
}
Thanks.

I'd go for this approach:
private static Optional<Double> convert(OptionalDouble od) {
return od.isPresent() ?
Optional.of(od.getAsDouble()) : Optional.empty();
}

A slight variation on #Andremoniy's answer is to skip the DoubleStream and use the averagingDouble() collector:
if (testList.isEmpty()) {
return Optional.empty();
}
return Optional.of(testList.stream().collect(Collector.averagingDouble()));
Or consider whether 0 is a valid return value for an empty list, and possibly skip the Optional entirely.

BTW, I found another solution, which has most simple form.
I've started thinking about: when result of average can be empty? Only when list it self is empty, right? So if we are sure that list is not empty, than we can safely do getAsDouble():
return Optional.ofNullable(testList.isEmpty() ? null :
testList.stream().mapToDouble(v -> v).average().getAsDouble())
(from performance point of view this could be more efficient than creating additional lambda wrappers, as was suggested in similar answers.)

This is quite an old question, but in newer versions of Java you can:
// Given an OptionalDouble
var myOptionalDouble = OptionalDouble.of(3.0d);
// Convert to Optional<Double>
var myOptional = myOptionalDouble.stream().boxed().findFirst();
The reverse is similarly easy:
var myOptional = Optional.of(Double.valueOf(3.0d));
var myOptionalDouble = myOptional.stream().mapToDouble(t -> t).findFirst();

I don't know if there exists a neat solution, but ths should work:
OptionalDouble optionalDouble = testList.stream().mapToDouble(value -> value).average();
return Optional.ofNullable(optionalDouble.isPresent() ? optionalDouble.getAsDouble() : null);

Just for fun, I wanted to see if it could be written in a single statement, without any need for an OptionalDouble temp variable. Here is the best I came up with:
return testList.stream().collect(Collectors.collectingAndThen(
Collectors.summarizingDouble(Double::doubleValue),
stat -> Optional.ofNullable(stat.getCount()>0 ? stat.getAverage() : null)));

I came to this "one line" (single statement) solution:
return ((Function<OptionalDouble, Optional<Double>>) od
-> od.isPresent() ? Optional.of(od.getAsDouble()) : Optional.empty())
.apply(testList.stream().mapToDouble(v -> v).average());
BTW, just for sake of minimalism, if you will do static import:
import static java.util.Optional.*;
you can omit Optional., what makes it a little bit less messy.

Related

Problem witn putIfAbsent() when modifying a stream

Please help me to figure out what is wrong with the method bellow and how can I solve it. The method takes a stream of Person object and Map with String value (a task name) as a key and an int value (a mark). The purpose of the method is to check whether a stream contains the particular tasks from allHistoryTasks variable and if does apply to this Map .putIfAbsentmethod(taskName, 0) to ensure that all the tasks are present in the Map (the purpose is to calculate an average mark later).
When I run the test the UnsupportedOperationException error apears. When I comment the lines from the if statement and to forEach (lines 1, 2, 3, 4) test runs well. I'm new to Java and already spent several days on this issue but still can't solve it. Please tell me what is wrong here.
private Set<String> allHistoryTasks = Set.of("Phalanxing", "Shieldwalling", "Tercioing", "Wedging");
private String[] historyTasks = allHistoryTasks.toArray(new String[0]);
public Map<Person, Map<String, Integer>> addHistoryIfPresent(Stream<CourseResult> stream) {
return stream.collect(Collectors.toMap(
CourseResult::getPerson,
x -> {
if (allHistoryTasks.containsAll(x.getTaskResults().keySet())) //1
IntStream.range(0, allHistoryTasks.size()) //2
.parallel() //3
.forEach(i -> x.getTaskResults().putIfAbsent(historyTasks[i], 0)); //4
return x.getTaskResults();
}
));
}
custom classes & thread report
The x -> {} block is the 'value mapper'. It is supposed to turn an element of your stream into the value for a given map.
You have a stream of CourseResult objects, and want a Map<Person, Map<String, Integer>>, so this function turns a CourseResultobject into aMap<String, Integer>`.
You do this by mutating things and that is a biiig nono. Your stream functions should not have any side-effects. Fortunately, the author of CourseResult is way ahead of you and blocked you from making this error. You are calling .getTaskResults() on your course result object and then trying to modify it. You can't do that, as the getTaskResults() method returns a map that cannot be modified.
Presumably, you want to clone that map, and fix the clone. How do you do that? Well, you tell me, the API isn't clear. You could simply make a new ImmutableMap.builder(), loop through whatever you want to loop through, and so on. From your code it's not quite clear what end map you do want.
Note also that you're using powers without knowing what you're doing - you have a parallel stream and are then forEaching through it, mutating the same variable, which you absolutely cannot do: This results in bugs where the result of an operation depends on an evil coin flip, in the sense that it can work fine today even if you rerun the tests a million times, and fail tomorrow. Separately, using parallel() for such talks is borderline crazy - assuming the underlying stream impl actually parallelizes (.parallel() is a hint, not a demand), it would just slow everything waaay down. allHistoryTasks is tiny. This isn't what parallelism would be for.
This might be the answer to your question. Set.of method won't return the mutable set. So you need to declare a mutrable set like this to avoid this problem.
private Set<String> allHistoryTasks = new HashSet<>(Arrays.asList("Phalanxing", "Shieldwalling", "Tercioing", "Wedging"));
private String[] historyTasks = allHistoryTasks.toArray(new String[0]);
public Map<Person, Map<String, Integer>> addHistoryIfPresent(Stream<CourseResult> stream) {
return stream.collect(Collectors.toMap(
CourseResult::getPerson,
x -> {
if (allHistoryTasks.containsAll(x.getTaskResults().keySet())) //1
IntStream.range(0, allHistoryTasks.size()) //2
.parallel() //3
.forEach(i -> x.getTaskResults().putIfAbsent(historyTasks[i], 0)); //4
return x.getTaskResults();
}
));
}

Set value to a string variable, from an object based on the condition using Java Streams

I am new to Java streams. I have a code snippet that i need to write using java streams. I am trying to set a value to a string based on a condition. I tried to look for solutions and experimented by using anyMatch, however could not get anywhere.
String loadAGENTID = "";
for(ReportGenerationParameter rgp : loadReportTableExt.getReportGenerationParameters()) {
if (rgp.getKey().equalsIgnoreCase(RapFilter.IDUSR)) {
loadAGENT_ID = rgp.getValue();
}
}
String loadAGENTID is to be used in the code. Any suggestion is welcome. Thank you.
I have tried using Arrays.stream and anyMatch but no luck so far
boolean todoName =
Arrays.stream(loadReportTableExt.getReportGenerationParameters())
.anyMatch(item -> item.getKey().equalsIgnoreCase(RapFilter.IDUSR));
if (todoName) {
// want to set the value of the respective object.
loadAGENT_ID = item.getValue();
}
Use the filter to find the matching object and then use findFirst which returns the first matching element
String loadAGENTID = loadReportTableExt.getReportGenerationParameters()
.stream()
.filter(rgp-> rgp.getKey().equalsIgnoreCase(RapFilter.IDUSR))
.findFirst()
.map(rgp->rgp.getValue()) // returns value from first matching element
.orElse(""); // none of them matched returns default value

What is the most efficient way of combining many Single<List<Type>>'s into a Single<List<Type>>?

I have a function loadApplesById that accepts an AppleId and returns a Single<List<Apple>>.
In another function, loadApplesByIdList I accept a List<AppleId> as a parameter. And for each element in it I have to call loadApplesById. The loadApplesByIdList will also return a Single<List<Apple>>.
Something like this:
Single<List<Apple> loadApplesById(AppleId appleId)
{
// magic to create and load the apple list.
return the Single.just(AppleList);
}
Single<List<Apple> loadApplesByIdList(List<AppleId> appleIdList)
{
// My question how to create this function (?)
// Approach (1)
return Observable.from(appleIdList).flatMap(
appleId -> this.loadApplesById(id)
.toObservable())
.reduce(new ArrayList<>(), (List<Apple> a, List<Apple> b)
-> { a.addAll(b); return a; }).toSingle();
// Approach (2)
return Observable.from(appleIdList).flatMap(appleId -> loadApplesById(id)
.toObservable())
.toSingle();
}
While both these approaches compile, neither of them works.
It would be a great learning lesson if someone would take the time to elaborate on the different ways that this could be accomplished (with fold, reduce, flatMap, concatMap) etc.
You have to unroll each single, concatenate them and then collect them up again:
Single<List<Apple>> allApples =
Observable.fromIterable(appleIdList)
.concatMap(appleId ->
loadApplesById(appleId)
.flattenAsObservable(list -> list)
)
.toList();
You'll need RxJava 2 for this though.

Java Stream > Is is possible to inline an "orElseGet" into a parent Stream?

I wasn't sure how exactly to frame this question, so bear with me...
1) Is there a better (aka more "proper") way to instantiate a Stream of optional elements, other than adding null and subsequently filtering out null's?
Stream.of( ... ,
person.likesRed() ? Color.RED : null)
.filter(Objects::nonNull)
...
2) Secondly, is there a way to "inline" the following orElseGet function into the parent Stream/map?
.map(p -> ofNullable(p.getFavouriteColours()).orElseGet(fallbackToDefaultFavouriteColours))
The full (contrived) example:
import static java.util.Optional.ofNullable;
public Response getFavouriteColours(final String personId) {
Person person = personService.findById(personId);
Supplier<List<String>> fallbackToDefaultFavouriteColours = () ->
Stream.of(
Color.BLUE,
Color.GREEN,
person.likesRed() ? Color.RED : null)
.filter(Objects::nonNull)
.map(Color::getName)
.collect(Collectors.toList());
return ofNullable(person)
.map(p -> ofNullable(p.getFavouriteColours()).orElseGet(fallbackToDefaultFavouriteColours))
.map(Response::createSuccess)
.orElse(Response::createNotFound);
}
A cleaner expression would be
Stream.concat(Stream.of(Color.BLUE, Color.GREEN),
person.likesRed()? Stream.of(Color.RED): Stream.empty())
This isn’t simpler than your original expression, but it doesn’t create the bad feeling of inserting something just to filter it out afterwards or, more abstract, of discarding an already known information that has to be reconstructed afterwards.
There is even a technical difference. The expression above creates a Stream that a has a known size that can be used to optimize certain operations. In contrast, the variant using filter only has an estimated size, which will be the number of elements before filtering, but not a known exact size.
The surrounding code can be greatly simplified by not overusing Optional:
public Response getFavouriteColours(final String personId) {
Person person = personService.findById(personId);
if(person == null) return Response.createNotFound();
List<String> favouriteColours = person.getFavouriteColours();
if(favouriteColours == null)
favouriteColours = Stream.concat(
Stream.of(Color.BLUE, Color.GREEN),
person.likesRed()? Stream.of(Color.RED): Stream.empty())
.map(Color::getName)
.collect(Collectors.toList());
return Response.createSuccess(favouriteColours);
}
Even the Stream operation itself is not simpler than a conventional imperative code here:
public Response getFavouriteColours(final String personId) {
Person person = personService.findById(personId);
if(person==null) return Response.createNotFound();
List<String> favouriteColours = person.getFavouriteColours();
if(favouriteColours==null) {
favouriteColours=new ArrayList<>();
Collections.addAll(favouriteColours, Color.BLUE.getName(), Color.GREEN.getName());
if(person.likesRed()) favouriteColours.add(Color.RED.getName());
}
return Response.createSuccess(favouriteColours);
}
though it’s likely that a more complex example would benefit from the Stream API use, whereas the use of Optional is unlikely to get better with more complex operations. A chain of Optional operations can simplify the code if all absent values or filter mismatches within the chain are supposed to be handled the same way at the end of the chain. If, however, like in your example (and most real life scenarios) every absent value should get a different treatment or be reported individually, using Optional, especially the nested use of Optionals, does not improve the code.

Check if something is equal to null or empty using lambdas

I have a class that counts the average number of words in a sentence using Lambdas in java. The problem that I'm having is that if corp is null or is empty I need to return 0. Currently I am getting NaN if corp is either null or empty. The rest of my code does what it should, but I cannot figure this part out.
public class AverageNumberOfWordsPerSentence extends TextMetric<Double> {
#Override
public Double apply(final Corpus corp) {
Sentences sentences = new Sentences();
List<String> sentenceList = sentences.apply(corp);
LongSummaryStatistics lss = corp.texts().stream()
.map(blob -> blob.text())
.flatMap(string -> stream
(string.split("\\W+")))
.filter(string -> !string.isEmpty())
.mapToLong(String::length)
.summaryStatistics();
return (double)lss.getCount() /
sentenceList.size();
}
Change the return statement to:
return sentenceList.isEmpty() ? 0.0 : (double)lss.getCount() / sentenceList.size();
And then hope that whoever told you “not to use control structures” will accept it. Strictly speaking, the ?: operator is a control structure, but it doesn’t have a keyword like if or while.
If I've got you right, then you need to use java.util.Optional:
class AverageNumberOfWordsPerSentence {
public Double apply(final Corpus corp) {
return Optional.of(corp).map(corp -> {
Sentences sentences = new Sentences();
List<String> sentenceList = sentences.apply(corp);
LongSummaryStatistics lss = corp.texts().stream()
.map(blob -> blob.text())
.flatMap(string -> stream
(string.split("\\W+")))
.filter(string -> !string.isEmpty())
.mapToLong(String::length)
.summaryStatistics();
return (double) lss.getCount() /
sentenceList.size();
}).orElse(0);
}
}
`
From the OP's comment,
Corpus corpus = new Corpus("King", text); So if the string where king is is empty or null then I have to return 0.
it appears that there needs to be some conditional logic that bypasses the stream if a member of Corpus is null or empty. The OP didn't say what the name of the property that holds "King" is, so I'll assume it is getKing() for now.
Like what #nikelin posted, Optional will help you here. Using Optional.filter() you can branch without using control structors. For example, you could do this to test to see if the "king" value is there and if it is null or an empty string, return 0, otherwise get the text metrics:
return Optional.of(corp)
.filter(c -> c.getKing() != null && !c.getKing().isEmpty()) // skip to the orElse() if it is null or empty)
.map(c -> c.texts()) // or .map(Corpus::texts)
.map(t -> t.stream()...blah blah get the word count...)
.map(count -> (double) count / sentences)
.orElse(0.0)
Any sequence of successive .map() operations can be combined into one, your choice.
If the initial Optional.filter finds that your "king" property is not null or empty, the stream operation the stream operation proceeds, getting the texts and calculating the word count as you specified already. It then maps the word count to sentenceCount/wordCount and returns that, but if your king property is null, the filter will leave the Optional empty, the map operations will be skipped, and the value in orElse(0.0) will be returned instead.

Categories