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 org.apache.juneau.commons.utils.*; 022 023/** 024 * A simple mutable integer value. 025 * 026 * <p> 027 * This class extends {@link Holder}<{@link Integer}> and adds a convenience method for incrementing 028 * the value, which is useful for counting operations in lambdas and loops. 029 * 030 * <h5 class='section'>Notes:</h5><ul> 031 * <li class='note'> 032 * This class is <b>not thread-safe</b>. For concurrent access, use {@link java.util.concurrent.atomic.AtomicInteger} instead. 033 * </ul> 034 * 035 * <h5 class='section'>Example:</h5> 036 * <p class='bjava'> 037 * <jc>// Create a counter</jc> 038 * IntegerHolder <jv>counter</jv> = IntegerHolder.<jsm>create</jsm>(); 039 * 040 * <jc>// Use in a lambda to count valid items</jc> 041 * list.forEach(<jv>x</jv> -> { 042 * <jk>if</jk> (<jv>x</jv>.isValid()) { 043 * <jv>counter</jv>.getAndIncrement(); 044 * } 045 * }); 046 * 047 * <jsm>log</jsm>(<js>"Valid items: "</js> + <jv>counter</jv>.get()); 048 * </p> 049 * 050 * <h5 class='section'>See Also:</h5><ul> 051 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsLang">Lang Package</a> 052 * </ul> 053 */ 054@SuppressWarnings({ 055 "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants 056}) 057public class IntegerHolder extends Holder<Integer> { 058 059 /** 060 * Creates a new integer value initialized to <c>0</c>. 061 * 062 * <h5 class='section'>Example:</h5> 063 * <p class='bjava'> 064 * IntegerHolder <jv>counter</jv> = IntegerHolder.<jsm>create</jsm>(); 065 * <jsm>assertEquals</jsm>(0, <jv>counter</jv>.get()); 066 * </p> 067 * 068 * @return A new integer value. 069 */ 070 public static IntegerHolder create() { 071 return of(0); 072 } 073 074 /** 075 * Creates a new integer value with the specified initial value. 076 * 077 * <h5 class='section'>Example:</h5> 078 * <p class='bjava'> 079 * IntegerHolder <jv>counter</jv> = IntegerHolder.<jsm>of</jsm>(42); 080 * <jsm>assertEquals</jsm>(42, <jv>counter</jv>.get()); 081 * </p> 082 * 083 * @param value The initial value. Can be <jk>null</jk> (treated as <c>0</c>). 084 * @return A new integer value. 085 */ 086 public static IntegerHolder of(Integer value) { 087 return new IntegerHolder(value); 088 } 089 090 /** 091 * Constructor. 092 */ 093 public IntegerHolder() { 094 super(0); 095 } 096 097 /** 098 * Constructor. 099 * 100 * @param value The initial value. Can be <jk>null</jk> (treated as <c>0</c>). 101 */ 102 public IntegerHolder(Integer value) { 103 super(value == null ? 0 : value); 104 } 105 106 /** 107 * Adds the specified value to the current value. 108 * 109 * <h5 class='section'>Example:</h5> 110 * <p class='bjava'> 111 * IntegerHolder <jv>value</jv> = IntegerHolder.<jsm>of</jsm>(10); 112 * <jv>value</jv>.add(5); 113 * <jsm>assertEquals</jsm>(15, <jv>value</jv>.get()); 114 * </p> 115 * 116 * @param x The value to add. Can be <jk>null</jk> (treated as <c>0</c>). 117 * @return This object. 118 */ 119 public IntegerHolder add(Integer x) { 120 var v = get(); 121 set((v == null ? 0 : v) + (x == null ? 0 : x)); 122 return this; 123 } 124 125 /** 126 * Adds the specified value to the current value and returns the new value. 127 * 128 * <h5 class='section'>Example:</h5> 129 * <p class='bjava'> 130 * IntegerHolder <jv>value</jv> = IntegerHolder.<jsm>of</jsm>(10); 131 * <jk>int</jk> <jv>result</jv> = <jv>value</jv>.addAndGet(5); <jc>// Returns 15</jc> 132 * <jsm>assertEquals</jsm>(15, <jv>value</jv>.get()); 133 * </p> 134 * 135 * @param x The value to add. Can be <jk>null</jk> (treated as <c>0</c>). 136 * @return The new value after addition. 137 */ 138 public Integer addAndGet(Integer x) { 139 var v = get(); 140 var result = (v == null ? 0 : v) + (x == null ? 0 : x); 141 set(result); 142 return result; 143 } 144 145 /** 146 * Decrements the value by 1. 147 * 148 * <h5 class='section'>Example:</h5> 149 * <p class='bjava'> 150 * IntegerHolder <jv>counter</jv> = IntegerHolder.<jsm>of</jsm>(5); 151 * <jv>counter</jv>.decrement(); 152 * <jsm>assertEquals</jsm>(4, <jv>counter</jv>.get()); 153 * </p> 154 * 155 * @return This object. 156 */ 157 public IntegerHolder decrement() { 158 var v = get(); 159 set((v == null ? 0 : v) - 1); 160 return this; 161 } 162 163 /** 164 * Decrements the value by 1 and returns the new value. 165 * 166 * <h5 class='section'>Example:</h5> 167 * <p class='bjava'> 168 * IntegerHolder <jv>counter</jv> = IntegerHolder.<jsm>of</jsm>(5); 169 * <jk>int</jk> <jv>result</jv> = <jv>counter</jv>.decrementAndGet(); <jc>// Returns 4</jc> 170 * <jsm>assertEquals</jsm>(4, <jv>counter</jv>.get()); 171 * </p> 172 * 173 * @return The decremented value. 174 */ 175 public Integer decrementAndGet() { 176 var v = get(); 177 var result = (v == null ? 0 : v) - 1; 178 set(result); 179 return result; 180 } 181 182 /** 183 * Returns the current value and then increments it. 184 * 185 * <p> 186 * This is a convenience method commonly used for counting operations in lambdas and loops. 187 * 188 * <h5 class='section'>Example:</h5> 189 * <p class='bjava'> 190 * IntegerHolder <jv>counter</jv> = IntegerHolder.<jsm>of</jsm>(5); 191 * <jk>int</jk> <jv>current</jv> = <jv>counter</jv>.getAndIncrement(); <jc>// Returns 5</jc> 192 * <jk>int</jk> <jv>next</jv> = <jv>counter</jv>.get(); <jc>// Returns 6</jc> 193 * </p> 194 * 195 * @return The value before it was incremented. 196 */ 197 public Integer getAndIncrement() { 198 var v = get(); 199 var result = v == null ? 0 : v; 200 set(result + 1); 201 return result; 202 } 203 204 /** 205 * Increments the value by 1. 206 * 207 * <h5 class='section'>Example:</h5> 208 * <p class='bjava'> 209 * IntegerHolder <jv>counter</jv> = IntegerHolder.<jsm>of</jsm>(5); 210 * <jv>counter</jv>.increment(); 211 * <jsm>assertEquals</jsm>(6, <jv>counter</jv>.get()); 212 * </p> 213 * 214 * @return This object. 215 */ 216 public IntegerHolder increment() { 217 var v = get(); 218 set((v == null ? 0 : v) + 1); 219 return this; 220 } 221 222 /** 223 * Increments the value by 1 and returns the new value. 224 * 225 * <h5 class='section'>Example:</h5> 226 * <p class='bjava'> 227 * IntegerHolder <jv>counter</jv> = IntegerHolder.<jsm>of</jsm>(5); 228 * <jk>int</jk> <jv>result</jv> = <jv>counter</jv>.incrementAndGet(); <jc>// Returns 6</jc> 229 * <jsm>assertEquals</jsm>(6, <jv>counter</jv>.get()); 230 * </p> 231 * 232 * @return The incremented value. 233 */ 234 public Integer incrementAndGet() { 235 var v = get(); 236 var result = (v == null ? 0 : v) + 1; 237 set(result); 238 return result; 239 } 240 241 /** 242 * Checks if the current value is equal to the specified value. 243 * 244 * <p> 245 * Uses {@link Shorts#eq(Object, Object)} for deep equality comparison, which handles nulls safely. 246 * 247 * <h5 class='section'>Example:</h5> 248 * <p class='bjava'> 249 * IntegerHolder <jv>value</jv> = IntegerHolder.<jsm>of</jsm>(42); 250 * <jsm>assertTrue</jsm>(<jv>value</jv>.is(42)); 251 * <jsm>assertFalse</jsm>(<jv>value</jv>.is(43)); 252 * </p> 253 * 254 * @param value The value to compare to. Can be <jk>null</jk>. 255 * @return <jk>true</jk> if the current value is equal to the specified value. 256 */ 257 @Override 258 public boolean is(Integer value) { 259 return eq(get(), value); 260 } 261 262 /** 263 * Checks if the current value matches any of the specified values. 264 * 265 * <p> 266 * Uses {@link Shorts#eq(Object, Object)} for deep equality comparison of each value. 267 * 268 * <h5 class='section'>Example:</h5> 269 * <p class='bjava'> 270 * IntegerHolder <jv>value</jv> = IntegerHolder.<jsm>of</jsm>(5); 271 * <jsm>assertTrue</jsm>(<jv>value</jv>.isAny(3, 5, 7)); 272 * <jsm>assertFalse</jsm>(<jv>value</jv>.isAny(1, 2)); 273 * </p> 274 * 275 * @param values The values to compare to. Must not be <jk>null</jk>. 276 * @return <jk>true</jk> if the current value matches any of the specified values. 277 */ 278 public boolean isAny(Integer...values) { 279 reqnn("values", values); 280 var current = get(); 281 for (var value : values) 282 if (eq(current, value)) 283 return true; 284 return false; 285 } 286}