I'm looking for a more convenient way of proofing equality for an Optional value.
This is what an Oracle Blog post suggests:
Optional<USB> maybeUSB = ...;
maybeUSB.filter(usb -> "3.0".equals(usb.getVersion())
.ifPresent(() -> System.out.println("ok"));
IMHO results in something like
if (maybeUSB.filter(c -> "3.0".equals(c.getVersion())).isPresent()) {
...
}
Of course that's kind of a poor example because it compares the Version and not the instance of USB itself but I think it should still proof my point.
Is this really as good as it gets?
No
boolean presentAndEquals(Object)
or
boolean deepEquals(Object)
Am I missing something here?
EDIT:
I'm not that happy with Optionals.equals either.
Do I really have to box an Object first to instantly unbox and check for equality ?
EDIT II:
Pretty damn happy with:
optional
.filter(nonOptional::equals)
.isPresent()
nowadays.
After some years of functional programming, if looses a lot of relevance.
You have many options.
Already noted:
boolean isEqual = maybeFoo.equals(Optional.of(testFoo));
Alternatively:
boolean isEqual = maybeFoo.isPresent() && maybeFoo.get().equals(testFoo);
Or:
boolean isEqual = testFoo.equals(maybeFoo.orElse(null));
These last two do have slightly different semantics: each returns a different value when maybeFoo is empty and testFoo is null. It's not clear which is the correct response (which I guess is one reason there's not a standard API method that does this).
You can probably come up with others if you read the Optional API doc and apply some thought. There's nothing magic that's absent from the docs.
More generally, if you're knocking against this often enough for it to bother you, you might be approaching Optional with the wrong philosophy.
As I see it, Optional is about acknowledging that something won't always be present, and that you need (sometimes verbose) code to handle that.
This should be the exception. Wherever possible, try and create variables that can't be null or Optional.empty().
In situations where this is unavoidable, embrace the fact that you need extra code.
Optional implements the equals method directly:
if (maybeUSB.equals(Optional.ofNullable(testUSB))) {
...
}
(you can also use Objects.equals rather than calling equals directly)
EDIT:
If you want both not present to be false, you can do this:
if (maybeUSB.equals(Optional.ofNullable(testUSB)) && maybeUSB.isPresent()) {
...
}
Would this work?
if (maybeUSB.map(c -> c.getVersion().equals("3.0")).orElse(false))
Related
Question ahead:
why does in Java the call coll.contains(null) fail for ImmutableCollections?
I know, that immutable collections cannot contain null-elements, and I do not want to discuss whether that's good or bad.
But when I write a Function, that takes a (general, not explicit immutable) Collection, it fails upon checking for nulls. Why does the implementation not return false (which is actually the 'correct' answer)?
And how can I properly check for nulls in a Collection in general?
Edit:
with some discussions (thanks to the commenters!) I realized, that I mixed up two things: ImmutableCollection from the guava library, and the List returned by java.util.List.of, being some class from ImmutableCollections. However, both classes throw an NPE on .contains(null).
My problem was with the List.of result, but technically the same would happen with guaves implementation. [edit: It does not]
I am distressed by this discussion!
Collections that do this have been a pet peeve of mine since before I wrote the first collections that eventually became Guava. If you find any Guava collection that throws NPE just because you asked it a perfectly innocent question like .contains(null), please file a bug! We hate that crap.
EDIT: I was so distressed that I had to go back to look at my 2007 changelist that first created ImmutableSet and saw literally this:
#Override public boolean contains(#Nullable Object target) {
if (target == null) {
return false;
}
ahhhhh.
why does in Java the call coll.contains(null) fail for ImmutableCollections?
Because the design team (the ones who have created guava) decided that, for their collections, null is unwanted, and therefore any interaction between their collections and a null check, even in this case, should just throw to highlight to the programmer, at the earliest possible opportunity, that there is a mismatch. Even where the established behaviour (as per the existing implementations in the core runtime itself, such as ArrayList and friends, as well as the javadoc), rather explicitly go the other way and say that a non-sequitur check (is this pear part of this list of apples?) strongly suggests that the right move is to just return false and not throw.
In other words, guava messed up. But now that they have done so, going back is potentially backwards compatibility breaking. It really isn't very - you are replacing an exception thrown with a false return value; presumably code could be out there that relies on the NPE (catching it and doing something different from what the code would do had contains(null) returned false instead of throwing) - but that's a rare case, and guava breaks backwards compatibility all the time.
And how can I properly check for nulls in a Collection in general?
By calling .contains(null), just as you are. The fact that guava doesn't do it right doesn't change the answer. You might as well ask 'how do I add elements to a list', and counter the answer of "well, you call list.add(item) to do that" with: Well, I have this implementation of the List interface that plays Rick Astley over the speaker instead of adding to the list, so, I reject your answer.
That's.. how java and interfaces work: You can have implementations of them, and the only guardianship that they do what the interface dictates they must, is that the author understands there is a contract that needs to be followed.
Now, normally a library so badly written they break contract for no good reason*, isn't popular. But guava IS popular. Very popular. That gets at a simple truth: No library is perfect. Guava's API design is generally quite good (in my opinion, vastly superior to e.g. Apache commons libraries), and the team actively spends a lot of time debating proper API design, in the sense that the code that one would write using guava is nice (as defined by: Easy to understand, has few surprises, easy to maintain, easy to test, and probably easy to mutate to deal with changing requirements - the only useful definition for nebulous terms like 'nice' or 'elegant' code - it's code that does those things, anything else is pointless aesthetic drivel). In other words, they are actively trying, and they usually get it right.
Just, not in this case. Work around it: return item != null && coll.contains(item); will get the job done.
There is one major argument in favour of guava's choice: They 'contract break' is an implicit break - one would expect that .contains(null) works, and always returns false, but it's not explicitly stated in the javadoc that one must do this. Contrast to e.g. IdentityHashMap, which uses identity equivalence (a==b) and not value equality (a.equals(b)) in its .containsKey etc implementations, which explicitly goes against the javadoc contract as stated in the j.u.Map interface. IHM has an excellent reason for it, and highlights the discrepancy, plus explains the reason, in the javadoc. Guava isn't nearly as clear about their bizarre null behaviour, but, here's a crucial thing about null in java:
Its meaning is nebulous. Sometimes it means 'empty', which is bad design: You should never write if (x == null || x.isEmpty()) - that implies some API is badly coded. If null is semantically equivalent to some value (such as "" or List.of()), then you should just return "" or List.of(), and not null. However, in such a design, list.contains(null) == false) would make sense.
But sometimes null means not found, irrelevant, not applicable, or unknown (for example, if map.get(k) returns null, that's what it means: Not found. Not 'I found an empty value for you'). This matches with what NULL means in e.g. SQL. In all those cases, .contains(null) should be returning neither true nor false. If I hand you a bag of marbles and ask you if there is a marble in there that is grue, and you have no idea what grue means, you shouldn't answer either yes or no to my query: Either answer is a meaningless guess. You should tell me that the question cannot be answered. Which is best represented in java by throwing, which is precisely what guava does. This also matches with what NULL does in SQL. In SQL, v IN (x) returns one of 3 values, not 2 values: It can resolve to true, false, or null. v IN (NULL) would resolve to NULL and not false. It is answering a question that can't be answered with the NULL value, which is to be read as: Don't know.
In other words, guava made a call on what null implies which evidently does not match with your definitions, as you expect .contains(null) to return false. I think your viewpoint is more idiomatic, but the point is, guava's viewpoint is different but also consistent, and the javadoc merely insinuates, but does not explicitly demand, that .contains(null) returns false.
That's not useful whatsoever in fixing your code, but hopefully it gives you a mental model, and answers your question of "why does it work like this?".
Item 12 in this using optionals correctly is not optional article states
Sometimes, we tend to "over-use" things. Meaning that we have a thing,
like Optional, and we see a use case for it everywhere. In the case of
Optional, a common scenario involves chaining its methods for the
single purpose of getting a value. Avoid this practice and rely on
simple and straightforward code.
Is the same true for Stream.ofNullable? Should I avoid this:
Stream.ofNullable(getHandlers(...))
.flatMap(Collections::stream)
.forEach(handler -> handler.handle(event));
In favour of this?
List<Handler> handlers = getHandlers(...)
if (handlers == null) {
return; // do nothing
}
handlers.forEach(handler -> handler.handle(event));
I think that the advice of "rely on simple and straightforward code" is good advice anywhere, not limited to either Optional or Stream.ofNullable.
In terms of the specific choice in the question: I think it is very hard to say that one is objectively simpler and more straightforward than the other. Stream.ofNullable is more concise, but requires you to know what it does; the explicit if check is more verbose, but is probably easier to understand if you are unfamiliar with Streams.
When new methods are introduced to an API, one can argue that it is in some sense "harder", because people unfamiliar with the API method will find it harder to read, because they won't know what that method does. Of course, one could counter they ought to know it, or should expect to encounter things they don't know.
So, I'm basically saying that you should use the one you/readers of your code will feel most comfortable with.
However, the thing I think is bad practice here is for getHandlers(...) to be returning null in the first place. There is an item in Effective Java (Item 54 in 3rd Ed, 43 in 2nd Ed) about always returning an empty list instead of null.
This advice works perfectly here, since you are handling a null list in the same way as you would an empty list.
Doing this would allow you to write:
List<Handler> handlers = getHandlers(...);
handlers.stream().forEach(...);
which is objectively simpler code.
I think it would be even better to use:
for (Handler h : getHandlers(...)) {
// ...
}
because you have more flexibility to do more inside the loop (e.g. breaking), without using streams(/stream-like methods) at all.
Consider the usage of this expression:
String hi = Optional.ofNullable(sayHi()).orElse("-");
which effectively corresponds to this ternary expression:
String hi = sayHi() != null ? sayHi() : "-";
Is this usage of Optional.ofNullable with a method call a good practice? Or just extra verbose coding?
I recognise that Optional.ofNullable actually creates a variable and avoids calling the sayHi() method twice. To avoid this problem you actually could create an extra variable but this adds to the verbosity of the ternary option:
String hi = sayHi();
hi = hi != null ? hi : "-";
On the other hand Optional.ofNullable creates in case of hi not being null an extra Optional object. So there is for sure more overhead to it.
So there seem to be some pros and cons to using this type of construct to replace the ternary constructor.
By the way: this is the Java 8 implementation of Optional.ofNullable:
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
In JDK 9 or later, use this:
String hi = Objects.requireNonNullElse(sayHi(), "-");
This avoids having to repeat sayHi() if a ternary operator is used, or to assign its value to a local variable that is reused within the ternary. It might be a small improvement. It also sidesteps the question of whether to use Optional. :-)
Whenever I come to think of using the Optional API for a specific purpose I always remind my self of what it was intended to do and why it was brought into the JDK and i.e.
Optional in intended to provide a limited mechanism for library method
return types where there is a clear need to represent “no result” and
where using null for this is overwhelmingly likely to cause errors - Stuart Marks
Optional is primarily focused on a return type that might or might not have a return value.
Over using this construct like in this specific example of yours just causes extra memory allocation and GC overhead.
I’d keep things simple and instead do:
String hi = sayHi();
if(hi == null) hi = “-“;
...
Is this usage of Optional.ofNullable with a method call a good practice?
Conceptually, it's a bad practice. The basic idea is to represent the absence of a return value, not to wrap everything that might be null. I am strongly against this usage.
Or just extra verbose coding?
It looks to me like a failed attempt to make your code more fashionable. ("Look, we are using brand-new Optional from Java 8!")
I prefer readability and clarity over conciseness.
This Optinal usage doesn't provide clarity but raises questions:
Why do you wrap the variable?
What are you going to do with this Optional?
Will it be used/returned below?
It doesn't give brevity either: your second line is even shorter.
To avoid this problem you actually could create an extra variable but this adds to the verbosity of the ternary option.
You aren't creating an extra variable. The one-line version could be:
String hi = (hi = sayHi()) != null ? hi : "-";
Though, your two-line suggestion is absolutely fine:
String messageContent = sayHi();
String hi = messageContent != null ? messageContent : "-";
If you're going to allow Optional into your workflow then you should consider modifying the sayHi() method so that it returns Optional<String> which will make the result more elegant:
hi = sayHi().orElse("-");
If you don't want to introduce Optional into your workflow (because it does create an additional object to contain the optional value) then you're better off sticking with simple null checks and the ternary operator.
With regard to the performance costs of Optional (such as increased garbage collection), you'd need to profile your application and decide whether or not this was a real concern.
Additionally, if you're mostly interested in String then be aware of the Objects.toString(Object, String) method which return a default value if the object is null:
hi = Objects.toString(hi, "-");
This is tidier and more elegant than writing out the code manually.
In brief: avoid the Optional type.
The main argument for Optional on return types is, "It's too easy for clients to forget to handle the possibility of a null return value. Optional is ugly and in your face, so a client is less likely to forget to handle the possibility of an empty return value. Everywhere else, programmers should continue to use normal references, which might be null."
I wrote a discussion of the pros and cons of using Java's Optional type: Nothing is better than the Optional type.
I think it's mostly a matter of personal taste.
From my point of view it would be more meaningful to just return an Optional<String> and let the caller deal with a missing value.
Optional, being a monadic type, can be leveraged for more then just getting an alt-value.
On the other end your operator seems terse enough, if used consistently it could be practical.
I don't think performance is a big issue here.
In Java 8,
I currently have a lambda that looks like this:
.createSomething((acceptableStates, someProxy) -> (userId) ->
acceptableStates.contains(someProxy.getSomeAttributeId(userId)))
However, we have changed someProxy.getSomeAttributeId to return an Optional<String> instead of a string.
What's the cleanest / most accepted way to essentially check for if acceptableStates contains the value of someProxy.getSomeAttributeId(userId) if the attribute returned isn't empty?
(Note: acceptableStates is still a list of strings, not of Optional<String>)
.... userId -> someProxy.getSomeAttributeId(userId)
.map(acceptableStates::contains)
.orElse(Boolean.FALSE);
Unfortunately, I see no very clean solution here. Refer to this question: Functional style of Java 8's Optional.ifPresent and if-not-Present?
Additionally, you even have to save the optional in a variable if the call to getSomeAttributeId does cost resources.
.createSomething((acceptableIds, someProxy) -> (userId) ->
{
Optional<String> attrId = someProxy.getSomeAttributeId(userId);
return attrId.isPresent() ? acceptableStates.contains(attrId.get()) : false;
})
I strongly recommend writing understandable and clear code like this snippet:
Optional<SomeAttributeId> optional = someProxy.getSomeAttributeId(userId);
return optional.isPresent() && acceptableStates.contains(optional.get());
If there should not be thrown an exception (1) when someProxy.getSomeAttributeId(userId) is an empty optional:
acceptableStates.contains(someProxy.getSomeAttributeId(userId).orElseThrow(() -> new Exception()))
Or unless you have the default value (2) to fill up the result with:
acceptableStates.contains(someProxy.getSomeAttributeId(userId).orElse(DEFAUT_VALUE))
My point:
Do not pursue Java 8 features which will mess everything up, especially in cases where a simple boolean expression could be used. I had experience refactoring some code toward plain Java statements because new people (1.1) came in a project could not get what the code does. With the time, even I (as a writer) barely can do so (1.2).
Also, with that "lambda chain" style, one slight change could cause rewriting a snippet/method entirely (2).
It is always fun to poke around n-nested lambdas, where n > 2 (3).
Anyway, if you don't share my point, #Eugene proposed a good way to go with.
return value.isPresent() && value.get().contains("some-text");
Is this a valid (intended) usage of Optional type in Java 8?
String process(String s) {
return Optional.ofNullable(s).orElseGet(this::getDefault);
}
I'll take another swing at this.
Is this a valid usage? Yes, in the narrow sense that it compiles and produces the results that you're expecting.
Is this intended usage? No. Now, sometimes things find usefulness beyond what they were originally for, and if this works out, great. But for Optional, we have found that usually things don't work out very well.
Brian Goetz and I discussed some of the issues with Optional in our JavaOne 2015 talk, API Design With Java 8 Lambdas and Streams:
link to video
link to slides
The primary use of Optional is as follows: (slide 36)
Optional is intended to provide a limited mechanism for library method return types where there is a clear need to represent "no result," and where using null for that is overwhelmingly likely to cause errors.
The ability to chain methods from an Optional is undoubtedly very cool, and in some cases it reduces the clutter from conditional logic. But quite often this doesn't work out. A typical code smell is, instead of the code using method chaining to handle an Optional returned from some method, it creates an Optional from something that's nullable, in order to chain methods and avoid conditionals. Here's an example of that in action (also from our presentation, slide 42):
// BAD
String process(String s) {
return Optional.ofNullable(s).orElseGet(this::getDefault);
}
// GOOD
String process(String s) {
return (s != null) ? s : getDefault();
}
The method that uses Optional is longer, and most people find it more obscure than the conventional code. Not only that, it creates extra garbage for no good reason.
Bottom line: just because you can do something doesn't mean that you should do it.
Since this is more or less an opinion-based question, I'll throw mine in. If you're trying to say
if (id == 1) {
Foo f = new Foo(id, "Bar", "US");
return "Bar".equals(f.getName()) && "US".equals(f.getCountryCode());
} else {
return false;
}
then just say that. Making things "functional" doesn't automatically make things clearer or better. By introducing a needless Optional, a couple lambdas, and some Optional methods that I had to look up, you've made the code more convoluted and difficult to understand. I don't think the designers of Java "intended" for people to use Optional to help make code more obscure.
EDIT: After reading some responses, I think it's worth adding some comments. This is not a functional programming idiom I'm familiar with, which would make it harder to understand. The idioms I am familiar with mostly involve Java streams, or (in other languages) functional idioms applied to multiple values in arrays or lists or other collections of multiple values. In those cases, once you get past the unfamiliarity, the functional syntax can be seen as an improvement because it allows some details to be hidden (loop indexes, iterators, running pointers, accumulator variables). So overall, it can simplify things. This example, by itself, doesn't do any such simplification.
However, some of the Optional features are useful in stream contexts. Suppose we had a parseInt() method that returns an Optional<Integer>, which is empty if the input string is invalid. (Java 8 really should have provided this.) This would make it easy to take an array of strings and produce an array of integers in which the strings that don't parse are simply eliminated from the result--use parseInt in a stream map(), and use a stream filter to filter out the empty Optionals. (I've seen multiple StackOverflow questions asking how to do this.) If you want to keep only the positive values, you could use an Optional.filter() to change the nonpositives to Optional.empty() before using the stream filter (although in this case, you could add another stream filter afterwards, but in a more complex case the Optional filter could be more useful). That's what I see as the main benefit of Optional from a functional standpoint. It allows you to work with a collection of values all at once, by giving you a way to represent "non-values" and write a function that will still work with them. So I guess the main use of Optional, besides a replacement for null, would be to represent empty spaces in a sequence of values while you're applying functions to the entire sequence as a whole.
Asking whether it's "valid" is rather opinion-based, but as to whether it's the intended use case: no, it's not.
Brian Goetz, Oracle's language architect for Java, has stated that the use case for Optional is for when you need a "no value" marker, and when using null for this is likely to cause errors. Specifically, if a reasonable user of your method is not likely to consider the possibility that its result is null, then you should use Optional. It was explicitly not intended to be a general "Maybe"-type object, as you're using it here.
In your case, the method that returns the Optional is private. That means it can only be used by the implementers of the class, and you can assume that they have good knowledge of the class' methods — including which of them may return null. Since there's no reasonable risk of confusion, Brian Goetz would (probably) say that he would not consider this a valid use case.
Its a little contrived, but 'valid' (as in 'syntactically') , but as #yshavit pointed to, it was intended for use in library development.
Previous answer was due to FP code being difficult to read. Below is commented(a little verbose, b/c that is the javadoc comments) but still. Much easier to read IMHO. (2nd is no-comments, and at least alignment to help readability)
private boolean isFooValid(final Integer id) {
return getFoo(id)
// filter if 'f' matches the predicate, return Optional w/f if true, empty Optional if false
.filter(f -> "Bar".equals(f.getName()) && "US".equals(f.getCountryCode()))
// If a value is present, apply the provided mapping function to it,
// If non-null, return an Optional describing the result.
.map(f -> true)
// Return the value if present, otherwise return other.
.orElse(false);
}
Or at least line it up so its more apparent what is going on and easier to read.
private boolean isFooValid(final Integer id) {
return getFoo(id)
.filter(f -> "Bar".equals(f.getName()) && "US".equals(f.getCountryCode()))
.map(f -> true)
.orElse(false);
}