java.util.Optional fields

William Clark wclark1324 at comcast.net
Sat Sep 22 06:51:04 PDT 2012


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