How would I apply this isPresent()
check along with this condition?
static Predicate<Student> averageMarksGreaterThan40 = student -> student.getMarks().stream()
.mapToInt(i -> i).average().getAsDouble() > 40;
I tried applying orElse(null)
also before calling getAsDouble()
but it is also not solving the problem.
CodePudding user response:
Terminal operation average()
returns an optional because if stream is empty, result might not be present.
Method getAsDouble()
will throw NoSuchElementException
when invoked on an empty optional object. But it might not obvious to the reader of your code.
If you are certain that value has to be present orElseThrow()
will be a better alternative, because it makes your intention to throw if incorrect behavior occurs explicit.
Another option is to use orElse(defaultValue)
that expects a default value, or orElseGet()
that takes a DoubleSupplier
.
How would I apply this
isPresent()
check
You can't check it inside a stream, method isPresent()
needs to be invoked on an optional object.
I tried applying
orElse(null)
also before callinggetAsDouble()
That will not compile because method orElse()
returns a value, not an optional. Therefore, call getAsDouble()
is redundant.
Providing null
as default value isn't a good idea. Optionals are designed as mean to avoid null
values, and in your case it will immediately produce a NullPointerException
.
CodePudding user response:
I think you should rephrase your question based on what your predicate is doing: your predicate is about finding all students whose average marks is greater than 40.
Which should bring the question: what is the average of a student having no marks?
In most case, it would be 0 - which amount to use orElse(0)
:
static Predicate<Student> averageMarksGreaterThan40 = student -> student.getMarks()
.stream()
.mapToInt(i -> i)
.average()
.orElse(0) > 40; // so, no isPresent()
If you were to use isPresent()
- that's possible - but that useless here because the orElse(double)
is already doing so.
static Predicate<Student> averageMarksGreaterThan40 = student -> {
OptionalDouble average = student.getMarks()
.stream()
.mapToInt(i -> i)
.average();
return average.isPresent() && average.getAsDouble() > 40;
}
Using orElseThrow(...)
here on the other hand would be good only if you are testing that student do have marks, otherwise this would fails:
var students = new ArrayList<Student>(); // the students
var studentsWithAverageMarksGreaterThan40 = students.stream()
.filter(student -> !student.getMarks().isEmpty())
.filter(averageMarksGreaterThan40)
.toList()
;
I don't think that's a good choice in the case of a predicate.
You could also use OptionalDouble::stream
and anyMatch
, but I think orElse(0)
is far easier to read/understand:
static Predicate<Student> averageMarksGreaterThan40 = student -> student.getMarks()
.stream()
.mapToInt(i -> i)
.average()
.stream()
.anyMatch(avg -> avg -> 40)
;
}