RFR 8071670: java.util.Optional: please add a way to specify if-else behavior
Hi, http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8071670-Optional-ifPresentOrEls... Here is another tweak to Optional (and primitives) that has some weight: /** * If a value is present, perform the given action with the value, * otherwise perform the given empty-based action. * * @param action the action to be performed if a value is present * @param emptyAction the empty-based action to be performed if a value is * not present * @throws NullPointerException if a value is present and {@code action} is * null, or a value is not present and {@code emptyAction} is null. * @since 1.9 */ public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) { if (value != null) { action.accept(value); } else { emptyAction.run(); } } (In hindsight we should have been consistent and thrown NPEs regardless of the optional state. The exception throwing behaviour is consistent with ifPresent.) Previously it was kind of awkward if one had two lambdas or method refs handy, one had to do: o.ifPresent(v -> ...); if (!o.ifPresent()) { ... } Or just: if (o.ifPresent()) { ... } else { ... } I also updated the language of the ifPresent methods to be more consistent with Collection/Stream.forEach. Paul.
Can't say I've used isPresent() much, as map()/flatMap()/orElse() take care of most use cases. What is an issue is that the primitive optional classes do not have ofNullable(), filter(), map() or flatMap(). It seems odd to be adding an additional new method to the primitive optional classes without rounding out the missing methods to reach feature parity. I've heard people complaining about the missing methods on more than one occasion.... Stephen On 3 February 2015 at 15:38, Paul Sandoz <paul.sandoz@oracle.com> wrote:
Hi,
http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8071670-Optional-ifPresentOrEls...
Here is another tweak to Optional (and primitives) that has some weight:
/** * If a value is present, perform the given action with the value, * otherwise perform the given empty-based action. * * @param action the action to be performed if a value is present * @param emptyAction the empty-based action to be performed if a value is * not present * @throws NullPointerException if a value is present and {@code action} is * null, or a value is not present and {@code emptyAction} is null. * @since 1.9 */ public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) { if (value != null) { action.accept(value); } else { emptyAction.run(); } }
(In hindsight we should have been consistent and thrown NPEs regardless of the optional state. The exception throwing behaviour is consistent with ifPresent.)
Previously it was kind of awkward if one had two lambdas or method refs handy, one had to do:
o.ifPresent(v -> ...); if (!o.ifPresent()) { ... }
Or just:
if (o.ifPresent()) { ... } else { ... }
I also updated the language of the ifPresent methods to be more consistent with Collection/Stream.forEach.
Paul.
On Feb 3, 2015, at 4:47 PM, Stephen Colebourne <scolebourne@joda.org> wrote:
Can't say I've used isPresent() much, as map()/flatMap()/orElse() take care of most use cases.
Yes, i suspect terminal action-based processing is less used than value transformation.
What is an issue is that the primitive optional classes do not have ofNullable(), filter(), map() or flatMap().
I dunno about the first, that would seem a little odd to me. Note the concept of ifPresent is already on all Optional variants. Same applies to the difficulties encountered with flatMap.
It seems odd to be adding an additional new method to the primitive optional classes without rounding out the missing methods to reach feature parity. I've heard people complaining about the missing methods on more than one occasion....
I recall the discussions around Optional consumed quite a bit of design discussion budget :-) so we tried to keep things to a minimum set. Do you wanna log an issue for those missing methods? Paul.
Hi Paul, This looks good - I have noticed one copy/paste error in the javadoc though: OptionalInt.java: looks like the throws clause of ifPresent and ifPresentOrElse have been interverted: 138 * @throws NullPointerException if a value is present and {@code action} is 139 * null, or a value is not present and {@code emptyAction} is null. 140 */ 141 public void ifPresent(IntConsumer action) { 142 if (isPresent) { 143 action.accept(value); 144 } 145 } 146 147 /** 148 * If a value is present, perform the given action with the value, 149 * otherwise perform the given empty-based action. 150 * 151 * @param action the action to be performed if a value is present 152 * @param emptyAction the empty-based action to be performed if a value is 153 * not present 154 * @throws NullPointerException if value is present and {@code action} is 155 * null 156 * @since 1.9 157 */ 158 public void ifPresentOrElse(IntConsumer action, Runnable emptyAction) { Concerning the test, should there be a test that verifies that NPE is thrown when null is passed - as specified in the javadoc? Best regards, -- daniel On 03/02/15 16:38, Paul Sandoz wrote:
Hi,
http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8071670-Optional-ifPresentOrEls...
Here is another tweak to Optional (and primitives) that has some weight:
/** * If a value is present, perform the given action with the value, * otherwise perform the given empty-based action. * * @param action the action to be performed if a value is present * @param emptyAction the empty-based action to be performed if a value is * not present * @throws NullPointerException if a value is present and {@code action} is * null, or a value is not present and {@code emptyAction} is null. * @since 1.9 */ public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) { if (value != null) { action.accept(value); } else { emptyAction.run(); } }
(In hindsight we should have been consistent and thrown NPEs regardless of the optional state. The exception throwing behaviour is consistent with ifPresent.)
Previously it was kind of awkward if one had two lambdas or method refs handy, one had to do:
o.ifPresent(v -> ...); if (!o.ifPresent()) { ... }
Or just:
if (o.ifPresent()) { ... } else { ... }
I also updated the language of the ifPresent methods to be more consistent with Collection/Stream.forEach.
Paul.
On Feb 12, 2015, at 3:50 PM, Daniel Fuchs <daniel.fuchs@oracle.com> wrote:
Hi Paul,
This looks good - I have noticed one copy/paste error in the javadoc though:
OptionalInt.java:
looks like the throws clause of ifPresent and ifPresentOrElse have been interverted:
138 * @throws NullPointerException if a value is present and {@code action} is 139 * null, or a value is not present and {@code emptyAction} is null. 140 */ 141 public void ifPresent(IntConsumer action) { 142 if (isPresent) { 143 action.accept(value); 144 } 145 } 146 147 /** 148 * If a value is present, perform the given action with the value, 149 * otherwise perform the given empty-based action. 150 * 151 * @param action the action to be performed if a value is present 152 * @param emptyAction the empty-based action to be performed if a value is 153 * not present 154 * @throws NullPointerException if value is present and {@code action} is 155 * null 156 * @since 1.9 157 */ 158 public void ifPresentOrElse(IntConsumer action, Runnable emptyAction) {
Oops. Fixed.
Concerning the test, should there be a test that verifies that NPE is thrown when null is passed - as specified in the javadoc?
Done. http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8071670-Optional-ifPresentOrEls... Thanks, Paul.
How often does the case when you "have a lambda handy already" come up in practice? If this leads to people using this method instead of ifPresent, that seems wasteful. Guava's Optional succeeded as much for what it left out as what it had in -- I confess this makes me nervous that j.u.Optional is becoming a kitchen sink. On Thu Feb 12 2015 at 9:51:23 AM Paul Sandoz <paul.sandoz@oracle.com> wrote:
On Feb 12, 2015, at 3:50 PM, Daniel Fuchs <daniel.fuchs@oracle.com> wrote:
Hi Paul,
This looks good - I have noticed one copy/paste error in the javadoc though:
OptionalInt.java:
looks like the throws clause of ifPresent and ifPresentOrElse have been interverted:
138 * @throws NullPointerException if a value is present and {@code action} is 139 * null, or a value is not present and {@code emptyAction} is null. 140 */ 141 public void ifPresent(IntConsumer action) { 142 if (isPresent) { 143 action.accept(value); 144 } 145 } 146 147 /** 148 * If a value is present, perform the given action with the value, 149 * otherwise perform the given empty-based action. 150 * 151 * @param action the action to be performed if a value is present 152 * @param emptyAction the empty-based action to be performed if a value is 153 * not present 154 * @throws NullPointerException if value is present and {@code action} is 155 * null 156 * @since 1.9 157 */ 158 public void ifPresentOrElse(IntConsumer action, Runnable emptyAction) {
Oops. Fixed.
Concerning the test, should there be a test that verifies that NPE is thrown when null is passed - as specified in the javadoc?
Done.
http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8071670- Optional-ifPresentOrElse/webrev/
Thanks, Paul.
On Feb 12, 2015, at 7:00 PM, Louis Wasserman <lowasser@google.com> wrote:
How often does the case when you "have a lambda handy already" come up in practice? If this leads to people using this method instead of ifPresent, that seems wasteful.
A lambda bearing ifPresent is already "present" (sorry!) :-) this is just filling it out to be consistent for a terminal operation with an empty action.
Guava's Optional succeeded as much for what it left out as what it had in -- I confess this makes me nervous that j.u.Optional is becoming a kitchen sink.
Yes, i most definitely share this concern. I have already closed a few optional issues as will not fix. FWIW I don't plan on adding any more stuff. Paul.
I get that ifPresent is already available; I'm curious if you examined how often there is actually an "if absent" case in practice, relative to the "only do something if present" case. If you don't have statistics, I could fairly easily get statistics on Google's codebase for what usages of Guava's Optional look like, in terms of how often if (optional.isPresent()) { ... } else { ... } occurs, relative to if (optional.isPresent()) { ... } // no else On Thu Feb 12 2015 at 10:15:45 AM Paul Sandoz <paul.sandoz@oracle.com> wrote:
On Feb 12, 2015, at 7:00 PM, Louis Wasserman <lowasser@google.com> wrote:
How often does the case when you "have a lambda handy already" come up in practice? If this leads to people using this method instead of ifPresent, that seems wasteful.
A lambda bearing ifPresent is already "present" (sorry!) :-) this is just filling it out to be consistent for a terminal operation with an empty action.
Guava's Optional succeeded as much for what it left out as what it had in -- I confess this makes me nervous that j.u.Optional is becoming a kitchen sink.
Yes, i most definitely share this concern. I have already closed a few optional issues as will not fix. FWIW I don't plan on adding any more stuff.
Paul.
On Feb 12, 2015, at 7:27 PM, Louis Wasserman <lowasser@google.com> wrote:
I get that ifPresent is already available; I'm curious if you examined how often there is actually an "if absent" case in practice, relative to the "only do something if present" case.
If you don't have statistics,
No, since this is still somewhat new. The evaluation was more based on the principle when this is required it is currently rather awkward.
I could fairly easily get statistics on Google's codebase for what usages of Guava's Optional look like, in terms of how often
if (optional.isPresent()) { ... } else { ... }
occurs, relative to
if (optional.isPresent()) { ... } // no else
Please, that would be very helpful and interesting. Thanks, Paul.
The new version looks good Paul! -- daniel On 2/12/15 6:50 PM, Paul Sandoz wrote:
On Feb 12, 2015, at 3:50 PM, Daniel Fuchs <daniel.fuchs@oracle.com> wrote:
Hi Paul,
This looks good - I have noticed one copy/paste error in the javadoc though:
OptionalInt.java:
looks like the throws clause of ifPresent and ifPresentOrElse have been interverted:
138 * @throws NullPointerException if a value is present and {@code action} is 139 * null, or a value is not present and {@code emptyAction} is null. 140 */ 141 public void ifPresent(IntConsumer action) { 142 if (isPresent) { 143 action.accept(value); 144 } 145 } 146 147 /** 148 * If a value is present, perform the given action with the value, 149 * otherwise perform the given empty-based action. 150 * 151 * @param action the action to be performed if a value is present 152 * @param emptyAction the empty-based action to be performed if a value is 153 * not present 154 * @throws NullPointerException if value is present and {@code action} is 155 * null 156 * @since 1.9 157 */ 158 public void ifPresentOrElse(IntConsumer action, Runnable emptyAction) {
Oops. Fixed.
Concerning the test, should there be a test that verifies that NPE is thrown when null is passed - as specified in the javadoc?
Done.
http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8071670-Optional-ifPresentOrEls...
Thanks, Paul.
participants (4)
-
Daniel Fuchs
-
Louis Wasserman
-
Paul Sandoz
-
Stephen Colebourne