java.util.Optional fields
Sam Pullara
sam at sampullara.com
Sat Sep 22 09:16:16 PDT 2012
One interesting thing to note is that it is usually rare to call isPresent on an Option in Scala is usually a code smell. I would think that the code would look more like:
optional.forEach( o -> { if (o == null) throw; ... })
I like Doug's proposal of having two forms, one that returns Optional and another that has a default value. Also, I prefer Guava's optional that doesn't have a public constructor so that:
Optional.of(null) == Optional.empty()
How impossible would it be to get better null behavior into the JVM? Is that on any future roadmap? If it was easy to ignore nulls like in Kotlin's Safe calls, this wouldn't really come up and would probably perform better:
http://confluence.jetbrains.net/display/Kotlin/Null-safety
Sam
On Sep 22, 2012, at 6:51 AM, William Clark <wclark1324 at comcast.net> wrote:
> I think if the programmer doesn't want to check for nulls, they
> shouldn't be putting nulls in their collections or streams - so Optional
> should allow null. However, if you're taking a stream from unknown code
> you don't have the same guarantee of a non-null value. So I propose
> another method in Optional:
>
> public Optional<T> nonNull() {
> return value != null ? this : Optional.empty();
> }
>
> Now your example is the following (assuming you want the same behaviour):
>
> if (optional.isPresent()) {
> Object obj = optional.nonNull().orElseThrow(...);
> ...
> }
>
> Assuming you want an exception thrown, this does eliminate the helpful
> behaviour of throwing an exception at the location the null originated
> from. But it does give other clients the option of not having any exception.
>
> On Fri, 21 Sep 2012 12:21:14 -0300 Lucas Cavalcanti wrote:
>
>> If you call .get() without checking you're doing it wrong. There's no way
>> to ensure this won't happen.
>>
>> But if the type is Optional<> I know I should write code for the absent
>> value. If the type is not optional, there is no way to know if I should
>> check for null.
>> So this is the biggest value.
>>
>> if I have to do:
>>
>> if (optional.isPresent()) {
>> Object obj = optional.get();
>> if (obj == null) {
>> throw something;
>> }
>> ...
>> }
>>
>> there is no point of having an optional type.
>>
>> On Fri, Sep 21, 2012 at 12:05 PM, Peter Levart <peter.levart at
> gmail.com>wrote:
>>
>>> On 09/21/2012 04:42 PM, Lucas Cavalcanti wrote:
>>>
>>> The point of having an Optional type is not having to care about null
>>> pointer exceptions anymore.
>>>
>>> Therefore this class should NOT allow null as a valid present value.
> null
>>> is an absent value.
>>>
>>>
>>> If you don't check Optional (.isPresent()) and blindly call .get() you
>>> will get NoSuchElementException which is no different to having no
> Optional
>>> class and just returning null and checking for null in such cases.
>>>
>>> Besides fluent API offered by Optional, your proposed Optional has not
>>> value over null.
>>>
>>> The 3-state Optional (non-null value, null value, empty) has a
> benefit in
>>> that it can express the 3rd option in a way that does not force using
>>> exceptions.
>>>
>>> Regards, Peter
>>>
>>>
>>>
>>> Regards,
>>> Lucas
>>> On Fri, Sep 21, 2012 at 10:44 AM, Peter Levart <peter.levart at
> gmail.com>wrote:
>>>
>>>> I actually like Optional as a name, especially because it has
> additional
>>>> targeted API that simplifies logic by allowing calling it's methods
> in a
>>>> chain...
>>>>
>>>> When I see where it's used in Stream, for example:
>>>>
>>>> Optional<T> findFirst();
>>>>
>>>> I can only imagine that it's purpose was to allow null values as
>>>> elements of streams. That is, it allows to differentiate between a
>>>> not-present (elements of a stream) and an element of 'null'...
>>>>
>>>> An alternative of throwing NoSuchElementException was replaced by
>>>> returning an Optional.
>>>>
>>>> Regards, Peter
>>>>
>>>> P.S.
>>>>
>>>> As to implementation details, here's a way to implement Optional in a
>>>> single final class and not having additional boolean flag:
>>>>
>>>>
>>>> public final class Optional<T> implements Serializable {
>>>>
>>>> private static long serialVersionUID = 1L;
>>>>
>>>> /**
>>>> * Common instance for {@code empty()}.
>>>> */
>>>> private final static Optional<?> EMPTY = new Optional<>(null);
>>>>
>>>> /**
>>>> * Value, if present.
>>>> */
>>>> private final T value;
>>>>
>>>> public Optional(T value) {
>>>> this.value = value;
>>>> }
>>>>
>>>> /**
>>>> * An empty object.
>>>> *
>>>> * Note: Though it may be tempting to do so, avoid testing if an
>>>> object
>>>> * is empty by comparing with {@code ==} against instances
> returned
>>>> * {@code Option.empty()}. There is no guarantee that it is a
>>>> singleton.
>>>> *
>>>> * @param <T> Type of the non-existent value.
>>>> * @return an empty object.
>>>> */
>>>> public static<T> Optional<T> empty() {
>>>> return (Optional<T>) EMPTY;
>>>> }
>>>>
>>>> /**
>>>> * Returns the value of this object.
>>>> *
>>>> * @return the value of this object.
>>>> * @throws NoSuchElementException if there is no value present.
>>>> */
>>>> public T get() {
>>>> if (this == EMPTY) {
>>>> throw new NoSuchElementException("No value present");
>>>> }
>>>> return value;
>>>> }
>>>>
>>>> /**
>>>> * Return {@code true} if there is a value present otherwise
> {@code
>>>> false}.
>>>> * @return {@code true} if there is a value present otherwise
>>>> {@code false}.
>>>> */
>>>> public boolean isPresent() {
>>>> return this != EMPTY;
>>>> }
>>>>
>>>> /**
>>>> * Return the value if present otherwise return {@code other}.
>>>> *
>>>> * @param other value to be returned if there is no value present.
>>>> * @return the value if present otherwise return {@code other}.
>>>> */
>>>> public T orElse(T other) {
>>>> return this != EMPTY ? value : other;
>>>> }
>>>>
>>>> /**
>>>> * Return the value if present otherwise return result of {@code
>>>> other}.
>>>> *
>>>> * @param other Factory who's result is returned if there is no
>>>> value present.
>>>> * @return the value if present otherwise return result of {@code
>>>> other}.
>>>> */
>>>> public T orElse(Factory<T> other) {
>>>> return this != EMPTY ? value : other.make();
>>>> }
>>>>
>>>> /**
>>>> * Return the value otherwise throw an exception to be created
> by the
>>>> * provided factory.
>>>> *
>>>> * @param <V> Type of the exception to be thrown.
>>>> * @param exceptionFactory The factory which will return the
>>>> exception to
>>>> * be thrown.
>>>> * @return the value.
>>>> * @throws V if there is no value present.
>>>> */
>>>> public<V extends Throwable> T orElseThrow(Factory<V>
>>>> exceptionFactory) throws V {
>>>> if (this != EMPTY) {
>>>> return value;
>>>> } else {
>>>> throw exceptionFactory.make();
>>>> }
>>>> }
>>>>
>>>> /**
>>>> * Return the value otherwise throw an exception of the provided
>>>> class.
>>>> * Exception will be thrown with the message "No value present".
>>>> *
>>>> * @param <V> Type of the exception to be thrown.
>>>> * @param exceptionClass The class if exception to be thrown. Must
>>>> support
>>>> * the default zero arguments constructor.
>>>> * @return the value.
>>>> * @throws V if there is no value present.
>>>> */
>>>> public<V extends Throwable> T orElseThrow(Class<V> exceptionClass)
>>>> throws V {
>>>> if (this != EMPTY) {
>>>> return value;
>>>> } else {
>>>> try {
>>>> throw exceptionClass.newInstance();
>>>> } catch (InstantiationException |
> IllegalAccessException e) {
>>>> throw new IllegalStateException("Unexpected exception
>>>> attempting to throw " + exceptionClass, e);
>>>> }
>>>> }
>>>> }
>>>>
>>>> public<V> Optional<V> map(Mapper<T, V> mapper) {
>>>> return this != EMPTY ? new Optional<>(mapper.map(value)) :
>>>> Optional.<V>empty();
>>>> }
>>>>
>>>> @Override
>>>> public boolean equals(Object o) {
>>>> if (this == o) {
>>>> return true;
>>>> }
>>>> if (this == EMPTY || o == EMPTY || o == null || Optional.class
>>>> != o.getClass()) {
>>>> return false;
>>>> }
>>>>
>>>> return Objects.equals(value, ((Optional)o).value);
>>>> }
>>>>
>>>> @Override
>>>> public int hashCode() {
>>>> int result = Objects.hashCode(value);
>>>> result = 31 * result + (this != EMPTY ? 1 : 0);
>>>> return result;
>>>> }
>>>>
>>>> @Override
>>>> public String toString() {
>>>> return this != EMPTY ? String.format("Optional[%s]", value) :
>>>> "Optional.empty";
>>>> }
>>>>
>>>> // Serialization
>>>>
>>>> private Object writeReplace() throws ObjectStreamException {
>>>> if (this == EMPTY) {
>>>> return EmptyProxy.INSTANCE;
>>>> }
>>>> else {
>>>> return this;
>>>> }
>>>> }
>>>>
>>>> private static final class EmptyProxy implements Serializable {
>>>> private static final EmptyProxy INSTANCE = new EmptyProxy();
>>>> private Object readResolve() throws ObjectStreamException {
>>>> return EMPTY;
>>>> }
>>>> }
>>>> }
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On 09/21/2012 03:11 PM, Vitaly Davidovich wrote:
>>>>>
>>>>> I disagree, as I mentioned on that other thread as well. :) A lot of
>>>>> types can be considered as containers in the abstract - that's not a
>>>>> very interesting distinction. In this case, a library class is added
>>>>> to make a language feature a bit less error prone (i.e. null and
>>>>> associated NPEs that unsuspecting developers hit). Given this,
>>>>> Optional sounds correct and more targeted. Moreover, given that
>>>>> Optional is meant to replace use of null, I don't think it should
>>>>> allow null as a valid value. If null and "absent" have different
>>>>> meaning in a given scenario then don't use Optional for those.
>>>>>
>>>>> Sent from my phone
>>>>>
>>>>> On Sep 21, 2012 9:00 AM, "Paul Benedict" <pbenedict at apache.org
>>>>> <mailto:pbenedict at apache.org>> wrote:
>>>>>
>>>>>> On Fri, Sep 21, 2012 at 7:19 AM, Vitaly Davidovich
>>>>> <vitalyd at gmail.com <mailto:vitalyd at gmail.com>> wrote:
>>>>>> Why not implement this like Guava with two concrete subtypes of
>>>>> Optional:
>>>>>> Present and Absent? It seems cleaner and I don't think
>>>>> performance will be
>>>>>> worse as compiler will only ever see two possible receivers and
>>>>> can use a
>>>>>> PIC to eliminate calls via vtable in those cases.
>>>>>
>>>>> I think this thread touches on an email I wrote earlier, which is
>>>>> Optional is not really a good name choice. It's all focusing on
>>>>> its potential lack of value rather than just being what it is
> -- a
>>>>> container.
>>>>>
>>>>>> On Sep 21, 2012 7:42 AM, "Peter Levart" <peter.levart at
> gmail.com
>>>>> <mailto:peter.levart at gmail.com>> wrote:
>>>>>> Maybe the intention was to allow null values to be wrapped in
>>>>> non-empty
>>>>>> Optional? In that case the check for non-null in constructor is
>>>>> wrong...
>>>>>
>>>>> Peter, I agree that a present value of null and an absent value
>>>>> (defaults to null) need to be differentiated. Yes, it looks
> wrong.
>>>>>
>>>>> Paul
>>>>>
>>>>
>>>>
>>>>
>>>>
>>>
>>>
>
More information about the lambda-dev
mailing list