/* Copyright 2013 The jeo project. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.jeo.util; import java.util.NoSuchElementException; /** * Utility object for dealing with references that may be null. * <p> * This class is inspired by guava's Optional class. * </p> * @author Justin Deoliveira, OpenGeo */ public class Optional<T> { /** * Creates the new optional from the specified (possibly <code>null</code>) value. */ public static <X> Optional<X> of(X value) { return new Optional<X>(value); } /** * Creates a new empty optional. */ public static <X> Optional<X> empty() { return new Optional<X>(null); } T value; private Optional(T value) { this.value = value; } /** * Returns <code>true</code> if the value is present, ie. not-null. */ public boolean isPresent() { return value != null; } /** * Invokes the specified consumer if the optional is present. */ public void ifPresent(Consumer<T> c) { if (isPresent()) { c.accept(get()); } } /** * Returns the value or throws {@link NoSuchElementException} if the value does not * exist. */ public T get() { return get("null value"); } /** * Returns the value or throws {@link NoSuchElementException} if the value does not * exist. * @param errMsg The message to use for the exception if the value is null. */ public T get(String errMsg) { if (value == null) { throw new NoSuchElementException(errMsg); } return value; } /** * Converts the value (if set) to the specified class. * <p> * This method calls {@link Convert#to(Object, Class)} to do the conversion. If no conversion can be done * {@link Optional#empty()} is returned. * </p> * * @param type The type to convert to. * */ public <X> Optional<X> to(Class<X> type) { if (value == null) { return (Optional<X>) this; } return Convert.to(value, type); } /** * Returns the underlying value if the optional is present, otherwise returns the * specified fallback. * * @param fallback Value to return if this optional is empty. */ public T orElse(T fallback) { return value != null ? value : fallback; } /** * Returns the underlying value if the optional is present, otherwise throws the * exception supplied by <tt>err</tt>. * */ public T orElseThrow(Supplier<RuntimeException> err) { if (value != null) { return value; } throw err.get(); } /** * Maps the optional to a different type. * * @param f The mapping function. * * @return The new optional, or empty if this optoinal is empty. */ public <R> Optional<R> map(Function<T,R> f) { if (!isPresent()) { return (Optional<R>) this; } return Optional.of(f.apply(get())); } /** * Applies a predicate to the optional, returning empty if the value doesn't match the * predicate. * * @param filter The predicate to apply to the value. */ public Optional<T> filter(Predicate<T> filter) { if (!isPresent()) { return this; } if (filter.test(get())) { return this; } return empty(); } }