1 /* 2 * The contents of this file are Copyright (c) 2014, 3 * https://programmingideaswithjake.wordpress.com/about/ made available under 4 * free license, 5 * https://programmingideaswithjake.wordpress.com/2014/10/05/java-functional-lazy-instantiation/ 6 * https://github.com/EZGames/functional-java/blob/master/LICENSE : 7 * "There is no license on this code. 8 * It's true open-ware. Do what you want with it. 9 * It's only meant to be helpful 10 * I'd prefer that you don't take credit for it, though. You don't have to give 11 * credit; just don't take it." 12 * Portions Copyright (c) 2018, 2020, Chris Fraire <cfraire@me.com>. 13 */ 14 package org.opengrok.indexer.util; 15 16 import java.util.function.Supplier; 17 18 /** 19 * {@code LazilyInstantiate} is a quick class to make lazily instantiating 20 * objects easy. All you need to know for working with this class is its two 21 * public methods: one static factory for creating the object, and another for 22 * initiating the instantiation and retrieval of the object. 23 * <p> 24 * Also, another benefit is that it's thread safe, but only blocks when 25 * initially instantiating the object. After that, it stops blocking and removes 26 * unnecessary checks for whether the object is instantiated. 27 * <p> 28 * Here's an example of it being used for implementing a singleton: 29 * <code> 30 * public class Singleton<br> 31 * {<br> 32 * private static Supplier<Singleton> instance = 33 * LazilyInstantiate.using(() -> new Singleton());<br> 34 * //other fields<br> 35 * <br> 36 * public static getInstance()<br> 37 * {<br> 38 * instance.get();<br> 39 * }<br> 40 * <br> 41 * //other methods<br> 42 * <br> 43 * private Singleton()<br> 44 * {<br> 45 * //contructor stuff<br> 46 * }<br> 47 * }<br> 48 * </code> 49 * <p> 50 * So, here are the changes you'll need to apply in your code: 51 * <ul> 52 * <li>Change the type of the lazily instantiated object to a {@code Supplier} 53 * of that <i>type</i> 54 * <li>Have it set to LazilyInstantiate.using() where the argument is 55 * {@code () -> <instantiation code>} You could also use a method reference, 56 * which, for the example above, would be {@code Singleton::new} instead of 57 * {@code () -> new Singleton()}</li> 58 * <li>Whatever asks for the object, asks for the {@code Supplier} object, then 59 * {@code .get()}</li> 60 * </ul> 61 * 62 * @param <T> the type of object that you're trying to lazily instantiate 63 */ 64 public class LazilyInstantiate<T> implements Supplier<T> { 65 66 private final Supplier<T> supplier; 67 private Supplier<T> current; 68 private volatile boolean active; 69 using(Supplier<T> supplier)70 public static <T> LazilyInstantiate<T> using(Supplier<T> supplier) { 71 return new LazilyInstantiate<>(supplier); 72 } 73 74 /** 75 * Executes the {@link #using(java.util.function.Supplier)} supplier in a 76 * thread-safe manner if it has not yet been executed, and keeps the result 77 * to provide to every caller of this method. 78 * @return the result of {@code supplier} 79 */ 80 @Override get()81 public T get() { 82 return current.get(); 83 } 84 85 /** 86 * Gets a value indicating if the instance is active and no longer 87 * technically lazy, since {@link #get()} has been called. 88 */ isActive()89 public boolean isActive() { 90 return active; 91 } 92 LazilyInstantiate(Supplier<T> supplier)93 private LazilyInstantiate(Supplier<T> supplier) { 94 this.supplier = supplier; 95 this.current = this::swapper; 96 } 97 98 //swaps the itself out for a supplier of an instantiated object swapper()99 private synchronized T swapper() { 100 if (!(current instanceof Factory)) { 101 T obj = supplier.get(); 102 current = new Factory<>(obj); 103 active = true; 104 } 105 return current.get(); 106 } 107 108 private static class Factory<U> implements Supplier<U> { 109 110 private final U obj; 111 Factory(U obj)112 Factory(U obj) { 113 this.obj = obj; 114 } 115 116 @Override get()117 public U get() { 118 return obj; 119 } 120 } 121 } 122