001/* 002 * Java Genetic Algorithm Library (jenetics-7.2.0). 003 * Copyright (c) 2007-2023 Franz Wilhelmstötter 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 * Author: 018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com) 019 */ 020package io.jenetics.internal.util; 021 022import static java.lang.String.format; 023import static java.util.Objects.requireNonNull; 024 025import java.io.Externalizable; 026import java.io.IOException; 027import java.io.InvalidObjectException; 028import java.io.ObjectInput; 029import java.io.ObjectInputStream; 030import java.io.ObjectOutput; 031import java.io.Serial; 032import java.io.Serializable; 033import java.util.Objects; 034import java.util.function.Supplier; 035 036/** 037 * Class for lazy value initialization. 038 * 039 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 040 * @since 3.0 041 * @version 5.0 042 */ 043public final class Lazy<T> implements Supplier<T>, Serializable { 044 045 @Serial 046 private static final long serialVersionUID = 2L; 047 048 private final transient Supplier<T> _supplier; 049 050 private T _value; 051 private transient volatile boolean _evaluated; 052 053 private Lazy( 054 final T value, 055 final boolean evaluated, 056 final Supplier<T> supplier 057 ) { 058 _value = value; 059 _evaluated = evaluated; 060 _supplier = supplier; 061 } 062 063 private Lazy(final Supplier<T> supplier) { 064 this(null, false, requireNonNull(supplier)); 065 } 066 067 @Override 068 public T get() { 069 return _evaluated ? _value : evaluate(); 070 } 071 072 /** 073 * Return the evaluation state of the {@code Lazy} variable. 074 * 075 * @return {@code true} is the {@code Lazy} variable has been evaluated, 076 * {@code false} otherwise 077 */ 078 public boolean isEvaluated() { 079 return _supplier == null || _evaluated || _evaluated(); 080 } 081 082 private synchronized boolean _evaluated() { 083 return _evaluated; 084 } 085 086 private synchronized T evaluate() { 087 if (!_evaluated) { 088 _value = _supplier.get(); 089 _evaluated = true; 090 } 091 092 return _value; 093 } 094 095 @Override 096 public int hashCode() { 097 return Objects.hashCode(get()); 098 } 099 100 @Override 101 public boolean equals(final Object obj) { 102 return obj == this || 103 obj instanceof Lazy<?> other && 104 Objects.equals(other.get(), get()); 105 } 106 107 @Override 108 public String toString() { 109 return format("Lazy[%s]", isEvaluated() ? get() : "?"); 110 } 111 112 /** 113 * Create a new lazy value initialization. 114 * 115 * @param supplier the lazy value supplier 116 * @param <T> the value type 117 * @return a new lazy value initialization 118 * @throws java.lang.NullPointerException if the given supplier is 119 * {@code null} 120 */ 121 public static <T> Lazy<T> of(final Supplier<T> supplier) { 122 return new Lazy<>(supplier); 123 } 124 125 /** 126 * Create a new {@code Lazy} object with the given {@code value}. This 127 * method allows creating a <em>lazy</em> object with the given 128 * {@code value}. 129 * 130 * @since 3.7 131 * 132 * @param value the value this {@code Lazy} object is initialized with 133 * @param <T> the value type 134 * @return return a new lazy value with the given value 135 */ 136 public static <T> Lazy<T> ofValue(final T value) { 137 return new Lazy<>(value, true, null); 138 } 139 140 141 /************************************************************************** 142 * Java object serialization 143 *************************************************************************/ 144 145 static final class SerialProxy implements Externalizable { 146 147 @Serial 148 private static final long serialVersionUID = 1L; 149 150 private Lazy<?> _object; 151 152 public SerialProxy() { 153 } 154 155 SerialProxy(final Lazy<?> object) { 156 _object = object; 157 } 158 159 @Serial 160 private Object readResolve() { 161 return _object; 162 } 163 164 @Override 165 public void writeExternal(final ObjectOutput out) throws IOException { 166 out.writeObject(_object.get()); 167 } 168 169 @Override 170 public void readExternal(ObjectInput in) 171 throws IOException, ClassNotFoundException 172 { 173 _object = Lazy.ofValue(in.readObject()); 174 } 175 } 176 177 @Serial 178 private Object writeReplace() { 179 return new SerialProxy(this); 180 } 181 182 @Serial 183 private void readObject(final ObjectInputStream stream) 184 throws InvalidObjectException 185 { 186 throw new InvalidObjectException("Serialization proxy required."); 187 } 188 189}