001/* 002 * MIT License 003 * 004 * Copyright (c) 2023 Michael Cowan 005 * 006 * Permission is hereby granted, free of charge, to any person obtaining a copy 007 * of this software and associated documentation files (the "Software"), to deal 008 * in the Software without restriction, including without limitation the rights 009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010 * copies of the Software, and to permit persons to whom the Software is 011 * furnished to do so, subject to the following conditions: 012 * 013 * The above copyright notice and this permission notice shall be included in all 014 * copies or substantial portions of the Software. 015 * 016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 022 * SOFTWARE. 023 */ 024 025package io.blt.util; 026 027import io.blt.util.functional.ThrowingConsumer; 028import io.blt.util.functional.ThrowingSupplier; 029import java.util.function.Supplier; 030 031import static java.util.Objects.nonNull; 032 033/** 034 * Static utility methods for operating on {@code Object}. 035 */ 036public final class Obj { 037 038 private Obj() { 039 throw new IllegalAccessError("Utility class should be accessed statically and never constructed"); 040 } 041 042 /** 043 * Passes the {@code instance} to the {@code consumer}, then returns the {@code instance}. 044 * e.g. 045 * <pre>{@code 046 * var user = Obj.poke(new User(), u -> { 047 * u.setName("Greg"); 048 * u.setAge(15); 049 * }); 050 * }</pre> 051 * <p> 052 * Optionally, the {@code consumer} may throw which will bubble up. 053 * </p> 054 * 055 * @param instance instance to consume and return 056 * @param consumer operation to perform on {@code instance} 057 * @param <T> type of {@code instance} 058 * @param <E> type of {@code consumer} throwable 059 * @return {@code instance} after accepting side effects via {@code consumer}. 060 */ 061 public static <T, E extends Throwable> T poke(T instance, ThrowingConsumer<T, E> consumer) throws E { 062 consumer.accept(instance); 063 return instance; 064 } 065 066 /** 067 * Calls the {@code supplier} to retrieve an instance which is mutated by the {@code consumer} then returned. 068 * e.g. 069 * <pre>{@code 070 * var user = Obj.tap(User::new, u -> { 071 * u.setName("Greg"); 072 * u.setAge(15); 073 * }); 074 * }</pre> 075 * <p> 076 * Optionally, the {@code consumer} may throw which will bubble up. 077 * </p> 078 * 079 * @param supplier supplies an instance to consume and return 080 * @param consumer operation to perform on supplied instance 081 * @param <T> type of instance 082 * @param <E> type of {@code consumer} throwable 083 * @return Supplied instance after applying side effects via {@code consumer}. 084 */ 085 public static <T, E extends Throwable> T tap(Supplier<T> supplier, ThrowingConsumer<T, E> consumer) throws E { 086 return poke(supplier.get(), consumer); 087 } 088 089 /** 090 * Returns {@code value} if non-null, else invokes and returns the result of {@code supplier}. 091 * <p> 092 * Optionally, the {@code supplier} may throw which will bubble up. 093 * </p> 094 * e.g. 095 * <pre>{@code 096 * private URL homepageOrDefault(URL homepage) throws MalformedURLException { 097 * return orElseGet(homepage, () -> new URL("https://google.com")); 098 * } 099 * }</pre> 100 * 101 * @param value returned if non-null 102 * @param supplier called and returned if {@code value} is null 103 * @param <T> type of the returned value 104 * @param <E> type of {@code supplier} throwable 105 * @return {@code value} if non-null, the result of {@code supplier} 106 * @throws E {@code Throwable} that may be thrown if the {@code supplier} is invoked 107 */ 108 public static <T, E extends Throwable> T orElseGet(T value, ThrowingSupplier<T, E> supplier) throws E { 109 return nonNull(value) ? value : supplier.get(); 110 } 111 112}