001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. 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 */ 017package org.apache.juneau.commons.lang; 018 019import static org.apache.juneau.commons.utils.Shorts.*; 020 021import java.util.concurrent.atomic.*; 022 023import org.apache.juneau.commons.utils.*; 024 025/** 026 * A simple mutable boolean value. 027 * 028 * <p> 029 * This class extends {@link Holder}<{@link Boolean}> and provides a convenient way to pass mutable 030 * boolean references to lambdas, inner classes, or methods. Unlike {@link Flag}, this class supports three 031 * states: <c>true</c>, <c>false</c>, and <c>null</c>. 032 * 033 * <h5 class='section'>Notes:</h5><ul> 034 * <li class='note'> 035 * This class is <b>not thread-safe</b>. For concurrent access, use {@link AtomicBoolean} instead. 036 * <li class='note'> 037 * This class supports three states (<c>true</c>, <c>false</c>, <c>null</c>). If you only need 038 * two states (<c>true</c>/<c>false</c>), consider using {@link Flag} instead. 039 * </ul> 040 * 041 * <h5 class='section'>Example:</h5> 042 * <p class='bjava'> 043 * <jc>// Create a boolean value to track if a condition was met</jc> 044 * BooleanHolder <jv>found</jv> = BooleanHolder.<jsm>create</jsm>(); 045 * 046 * <jc>// Use in a lambda</jc> 047 * list.forEach(<jv>x</jv> -> { 048 * <jk>if</jk> (<jv>x</jv>.matches(criteria)) { 049 * <jv>found</jv>.set(<jk>true</jk>); 050 * } 051 * }); 052 * 053 * <jk>if</jk> (<jv>found</jv>.isTrue()) { 054 * <jsm>log</jsm>(<js>"Match found!"</js>); 055 * } 056 * </p> 057 * 058 * <h5 class='section'>See Also:</h5><ul> 059 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsLang">Lang Package</a> 060 * <li class='jc'>{@link Flag} 061 * </ul> 062 */ 063@SuppressWarnings({ 064 "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants 065}) 066public class BooleanHolder extends Holder<Boolean> { 067 068 /** 069 * Creates a new boolean value initialized to <c>false</c>. 070 * 071 * <h5 class='section'>Example:</h5> 072 * <p class='bjava'> 073 * BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>create</jsm>(); 074 * <jsm>assertEquals</jsm>(<jk>false</jk>, <jv>value</jv>.get()); 075 * </p> 076 * 077 * @return A new boolean value. 078 */ 079 public static BooleanHolder create() { 080 return of(false); 081 } 082 083 /** 084 * Creates a new boolean value with the specified initial value. 085 * 086 * <h5 class='section'>Example:</h5> 087 * <p class='bjava'> 088 * BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>of</jsm>(<jk>true</jk>); 089 * <jsm>assertEquals</jsm>(<jk>true</jk>, <jv>value</jv>.get()); 090 * </p> 091 * 092 * @param value The initial value. Can be <jk>null</jk>. 093 * @return A new boolean value. 094 */ 095 public static BooleanHolder of(Boolean value) { 096 return new BooleanHolder(value); 097 } 098 099 /** 100 * Constructor. 101 * 102 * @param value The initial value. Can be <jk>null</jk>. 103 */ 104 public BooleanHolder(Boolean value) { 105 super(value); 106 } 107 108 /** 109 * Checks if the current value is equal to the specified value. 110 * 111 * <p> 112 * Uses {@link Shorts#eq(Object, Object)} for deep equality comparison, which handles nulls safely. 113 * 114 * <h5 class='section'>Example:</h5> 115 * <p class='bjava'> 116 * BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>of</jsm>(<jk>true</jk>); 117 * <jsm>assertTrue</jsm>(<jv>value</jv>.is(<jk>true</jk>)); 118 * <jsm>assertFalse</jsm>(<jv>value</jv>.is(<jk>false</jk>)); 119 * 120 * <jc>// Handles null safely</jc> 121 * BooleanHolder <jv>empty</jv> = BooleanHolder.<jsm>of</jsm>(<jk>null</jk>); 122 * <jsm>assertTrue</jsm>(<jv>empty</jv>.is(<jk>null</jk>)); 123 * </p> 124 * 125 * @param value The value to compare to. Can be <jk>null</jk>. 126 * @return <jk>true</jk> if the current value is equal to the specified value. 127 */ 128 @Override 129 public boolean is(Boolean value) { 130 return eq(get(), value); 131 } 132 133 /** 134 * Checks if the current value matches any of the specified values. 135 * 136 * <p> 137 * Uses {@link Shorts#eq(Object, Object)} for deep equality comparison of each value. 138 * 139 * <h5 class='section'>Example:</h5> 140 * <p class='bjava'> 141 * BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>of</jsm>(<jk>true</jk>); 142 * <jsm>assertTrue</jsm>(<jv>value</jv>.isAny(<jk>true</jk>, <jk>null</jk>)); 143 * <jsm>assertFalse</jsm>(<jv>value</jv>.isAny(<jk>false</jk>)); 144 * </p> 145 * 146 * @param values The values to compare to. Must not be <jk>null</jk>. 147 * @return <jk>true</jk> if the current value matches any of the specified values. 148 */ 149 public boolean isAny(Boolean...values) { 150 reqnn("values", values); 151 var current = get(); 152 for (var value : values) 153 if (eq(current, value)) 154 return true; 155 return false; 156 } 157 158 /** 159 * Returns <c>true</c> if the value is not set to <c>true</c> (i.e., it's <c>false</c> or <c>null</c>). 160 * 161 * <h5 class='section'>Example:</h5> 162 * <p class='bjava'> 163 * BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>of</jsm>(<jk>false</jk>); 164 * <jk>if</jk> (<jv>value</jv>.isNotTrue()) { 165 * <jsm>log</jsm>(<js>"Value is not true"</js>); 166 * } 167 * </p> 168 * 169 * @return <c>true</c> if the value is not set to <c>true</c>, <c>false</c> otherwise. 170 */ 171 public boolean isNotTrue() { return ! isTrue(); } 172 173 /** 174 * Returns <c>true</c> if the value is set to <c>true</c>. 175 * 176 * <h5 class='section'>Example:</h5> 177 * <p class='bjava'> 178 * BooleanHolder <jv>value</jv> = BooleanHolder.<jsm>of</jsm>(<jk>true</jk>); 179 * <jk>if</jk> (<jv>value</jv>.isTrue()) { 180 * <jsm>log</jsm>(<js>"Value is true"</js>); 181 * } 182 * </p> 183 * 184 * @return <c>true</c> if the value is set to <c>true</c>, <c>false</c> otherwise (including when <c>null</c>). 185 */ 186 public boolean isTrue() { return ObjectUtils.isTrue(get()); } 187}