1 /*
   2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.util;
  26 
  27 import java.util.function.IntConsumer;
  28 import java.util.function.IntSupplier;
  29 import java.util.function.Supplier;
  30 
  31 /**
  32  * A container object which may or may not contain a {@code int} value.
  33  * If a value is present, {@code isPresent()} will return {@code true} and
  34  * {@code get()} will return the value.
  35  *
  36  * <p>Additional methods that depend on the presence or absence of a contained
  37  * value are provided, such as {@link #orElse(java.lang.Object) orElse()}
  38  * (return a default value if value not present) and
  39  * {@link #ifPresent(java.util.function.Consumer) ifPresent()} (execute a block
  40  * of code if the value is present.)
  41  *
  42  * @since 1.8
  43  */
  44 public final class OptionalInt {
  45     /**
  46      * Common instance for {@code empty()}.
  47      */
  48     private final static OptionalInt EMPTY = new OptionalInt();
  49 
  50     /**
  51      * If true then the value is present, otherwise indicates no value is present
  52      */
  53     private final boolean isPresent;
  54     private final int value;
  55 
  56     /**
  57      * Construct a non-empty instance
  58      *
  59      * @param value the int value to be present.
  60      */
  61     private OptionalInt(int value) {
  62         this.isPresent = true;
  63         this.value = value;
  64     }
  65 
  66     /**
  67      * Construct an empty instance.
  68      *
  69      * @implNote generally only one empty instance, {@link OptionalInt#EMPTY},
  70      * should exist per VM.
  71      */
  72     private OptionalInt() {
  73         this.isPresent = false;
  74         this.value = 0;
  75     }
  76 
  77     /**
  78      * Return an empty {@code OptionalInt}.  No value is present for this Optional.
  79      *
  80      * @apiNote Though it may be tempting to do so, avoid testing if an object
  81      * is empty by comparing with {@code ==} against instances returned
  82      * {@code Option.empty()}. There is no guarantee that it is a singleton.
  83      * Instead, use {@code isPresent()}.
  84      *
  85      *  @return an empty {@code OptionalInt}.
  86      */
  87     @SuppressWarnings("unchecked")
  88     public static OptionalInt empty() {
  89         return EMPTY;
  90     }
  91 
  92     /**
  93      * Create a new {@code OptionalInt} with a present value
  94      * @param value The int value
  95      * @param value new {@code OptionalInt} with a present value.
  96      */
  97     public static OptionalInt of(int value) {
  98         return new OptionalInt(value);
  99     }
 100 
 101     /**
 102      * If a value is present in this {@code OptionalInt}, returns the value,
 103      * otherwise throws {@code NoSuchElementException}.
 104      *
 105      * @return the value held by this {@code OptionalInt}.
 106      * @throws NoSuchElementException if there is no value present.
 107      *
 108      * @see OptionalInt#isPresent()
 109      */
 110     public int getAsInt() {
 111         if (!isPresent) {
 112             throw new NoSuchElementException("No value present");
 113         }
 114         return value;
 115     }
 116 
 117     /**
 118      * Return {@code true} if there is a value present, otherwise {@code false}.
 119      *
 120      * @return {@code true} if there is a value present, otherwise {@code false}.
 121      */
 122     public boolean isPresent() {
 123         return isPresent;
 124     }
 125 
 126     /**
 127      * Execute the specified consumer with the value if a value is present,
 128      * otherwise do nothing.
 129      *
 130      * @param consumer block to be executed if a value is present.
 131      * @throws NullPointerException if value is present and {@code consumer} is
 132      * null.
 133      */
 134     public void ifPresent(IntConsumer consumer) {
 135         if (isPresent)
 136             consumer.accept(value);
 137     }
 138 
 139     /**
 140      * Return the value if present, otherwise return {@code other}.
 141      *
 142      * @param other value to be returned if there is no value present.
 143      * @return the value, if present, otherwise {@code other}.
 144      */
 145     public int orElse(int other) {
 146         return isPresent ? value : other;
 147     }
 148 
 149     /**
 150      * Return the value if present, otherwise invoke {@code other} and return
 151      * the result of that invocation.
 152      *
 153      * @param other {@code IntSupplier} who's result is returned if there is no
 154      * value present.
 155      * @return the value if present otherwise return result of {@code other}.
 156      * @throws NullPointerException if value is absent and {@code other} is null.
 157      */
 158     public int orElseGet(IntSupplier other) {
 159         return isPresent ? value : other.getAsInt();
 160     }
 161 
 162     /**
 163      * Return the contained value, if present, otherwise throw an exception
 164      * to be created by the provided supplier.
 165      *
 166      * @param <V> Type of the exception to be thrown.
 167      * @param exceptionSupplier The supplier which will return the exception to
 168      * be thrown.
 169      * @return the value.
 170      * @throws V if there is no value present.
 171      * @throws NullPointerException if value is absent and
 172      * {@code exceptionSupplier} is null.
 173      */
 174     public<V extends Throwable> int orElseThrow(Supplier<V> exceptionSupplier) throws V {
 175         if (isPresent) {
 176             return value;
 177         } else {
 178             throw exceptionSupplier.get();
 179         }
 180     }
 181 
 182     @Override
 183     public boolean equals(Object o) {
 184         if (this == o) {
 185             return true;
 186         }
 187 
 188         if (!(o instanceof OptionalInt)) {
 189             return false;
 190         }
 191 
 192         OptionalInt other = (OptionalInt) o;
 193         return (isPresent && other.isPresent) ? value == other.value : isPresent == other.isPresent;
 194     }
 195 
 196     @Override
 197     public int hashCode() {
 198         return Integer.hashCode(value);
 199     }
 200 
 201     @Override
 202     public String toString() {
 203         return isPresent
 204                         ? String.format("IntOptional[%s]", value)
 205                         : "IntOptional.empty";
 206     }
 207 }