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