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.AssertionUtils.*; 020import static org.apache.juneau.commons.utils.Utils.*; 021 022/** 023 * A simple mutable character value. 024 * 025 * <p> 026 * This class extends {@link Value}<{@link Character}> and provides a convenient way to pass mutable 027 * character references to lambdas, inner classes, or methods. 028 * 029 * <h5 class='section'>Notes:</h5><ul> 030 * <li class='note'> 031 * This class is <b>not thread-safe</b>. 032 * </ul> 033 * 034 * <h5 class='section'>Example:</h5> 035 * <p class='bjava'> 036 * <jc>// Create a character value to track the last character seen</jc> 037 * CharValue <jv>lastChar</jv> = CharValue.<jsm>create</jsm>(); 038 * 039 * <jc>// Use in a lambda to track state</jc> 040 * charStream.forEach(<jv>ch</jv> -> { 041 * <jk>if</jk> (Character.isUpperCase(<jv>ch</jv>)) { 042 * <jv>lastChar</jv>.set(<jv>ch</jv>); 043 * } 044 * }); 045 * 046 * <jsm>log</jsm>(<js>"Last uppercase char: "</js> + <jv>lastChar</jv>.get()); 047 * </p> 048 * 049 * <h5 class='section'>See Also:</h5><ul> 050 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsLang">Lang Package</a> 051 * </ul> 052 */ 053public class CharValue extends Value<Character> { 054 055 /** 056 * Creates a new character value initialized to <c>'\0'</c> (null character). 057 * 058 * <h5 class='section'>Example:</h5> 059 * <p class='bjava'> 060 * CharValue <jv>value</jv> = CharValue.<jsm>create</jsm>(); 061 * <jsm>assertEquals</jsm>('\0', <jv>value</jv>.get()); 062 * </p> 063 * 064 * @return A new character value. 065 */ 066 public static CharValue create() { 067 return of('\0'); 068 } 069 070 /** 071 * Creates a new character value with the specified initial value. 072 * 073 * <h5 class='section'>Example:</h5> 074 * <p class='bjava'> 075 * CharValue <jv>value</jv> = CharValue.<jsm>of</jsm>('A'); 076 * <jsm>assertEquals</jsm>('A', <jv>value</jv>.get()); 077 * </p> 078 * 079 * @param value The initial value. 080 * @return A new character value. 081 */ 082 public static CharValue of(Character value) { 083 return new CharValue(value); 084 } 085 086 /** 087 * Constructor. 088 * 089 * @param value The initial value. 090 */ 091 public CharValue(Character value) { 092 super(value); 093 } 094 095 /** 096 * Adds the specified value to the current value. 097 * 098 * <h5 class='section'>Example:</h5> 099 * <p class='bjava'> 100 * CharValue <jv>value</jv> = CharValue.<jsm>of</jsm>('A'); 101 * <jv>value</jv>.add((<jk>char</jk>)5); 102 * <jsm>assertEquals</jsm>('F', <jv>value</jv>.get()); 103 * </p> 104 * 105 * @param x The value to add. 106 * @return This object. 107 */ 108 public CharValue add(Character x) { 109 var v = get(); 110 set((char)((v == null ? 0 : v) + (x == null ? 0 : x))); 111 return this; 112 } 113 114 /** 115 * Adds the specified value to the current value and returns the new value. 116 * 117 * <h5 class='section'>Example:</h5> 118 * <p class='bjava'> 119 * CharValue <jv>value</jv> = CharValue.<jsm>of</jsm>('A'); 120 * <jk>char</jk> <jv>result</jv> = <jv>value</jv>.addAndGet((<jk>char</jk>)5); <jc>// Returns 'F'</jc> 121 * <jsm>assertEquals</jsm>('F', <jv>value</jv>.get()); 122 * </p> 123 * 124 * @param x The value to add. 125 * @return The new value after addition. 126 */ 127 public Character addAndGet(Character x) { 128 var v = get(); 129 var result = (char)((v == null ? 0 : v) + (x == null ? 0 : x)); 130 set(result); 131 return result; 132 } 133 134 /** 135 * Decrements the value by 1. 136 * 137 * <h5 class='section'>Example:</h5> 138 * <p class='bjava'> 139 * CharValue <jv>value</jv> = CharValue.<jsm>of</jsm>('B'); 140 * <jv>value</jv>.decrement(); 141 * <jsm>assertEquals</jsm>('A', <jv>value</jv>.get()); 142 * </p> 143 * 144 * @return This object. 145 */ 146 public CharValue decrement() { 147 var v = get(); 148 set((char)((v == null ? 0 : v) - 1)); 149 return this; 150 } 151 152 /** 153 * Decrements the value by 1 and returns the new value. 154 * 155 * <h5 class='section'>Example:</h5> 156 * <p class='bjava'> 157 * CharValue <jv>value</jv> = CharValue.<jsm>of</jsm>('B'); 158 * <jk>char</jk> <jv>result</jv> = <jv>value</jv>.decrementAndGet(); <jc>// Returns 'A'</jc> 159 * <jsm>assertEquals</jsm>('A', <jv>value</jv>.get()); 160 * </p> 161 * 162 * @return The decremented value. 163 */ 164 public Character decrementAndGet() { 165 var v = get(); 166 var result = (char)((v == null ? 0 : v) - 1); 167 set(result); 168 return result; 169 } 170 171 /** 172 * Increments the value by 1. 173 * 174 * <h5 class='section'>Example:</h5> 175 * <p class='bjava'> 176 * CharValue <jv>value</jv> = CharValue.<jsm>of</jsm>('A'); 177 * <jv>value</jv>.increment(); 178 * <jsm>assertEquals</jsm>('B', <jv>value</jv>.get()); 179 * </p> 180 * 181 * @return This object. 182 */ 183 public CharValue increment() { 184 var v = get(); 185 set((char)((v == null ? 0 : v) + 1)); 186 return this; 187 } 188 189 /** 190 * Increments the value by 1 and returns the new value. 191 * 192 * <h5 class='section'>Example:</h5> 193 * <p class='bjava'> 194 * CharValue <jv>value</jv> = CharValue.<jsm>of</jsm>('A'); 195 * <jk>char</jk> <jv>result</jv> = <jv>value</jv>.incrementAndGet(); <jc>// Returns 'B'</jc> 196 * <jsm>assertEquals</jsm>('B', <jv>value</jv>.get()); 197 * </p> 198 * 199 * @return The incremented value. 200 */ 201 public Character incrementAndGet() { 202 var v = get(); 203 var result = (char)((v == null ? 0 : v) + 1); 204 set(result); 205 return result; 206 } 207 208 /** 209 * Checks if the current value is equal to the specified character. 210 * 211 * <p> 212 * Uses {@link org.apache.juneau.commons.utils.Utils#eq(Object, Object)} for deep equality comparison, which handles nulls safely. 213 * 214 * <h5 class='section'>Example:</h5> 215 * <p class='bjava'> 216 * CharValue <jv>value</jv> = CharValue.<jsm>of</jsm>('A'); 217 * <jsm>assertTrue</jsm>(<jv>value</jv>.is('A')); 218 * <jsm>assertFalse</jsm>(<jv>value</jv>.is('B')); 219 * </p> 220 * 221 * @param value The character to compare to. 222 * @return <jk>true</jk> if the current value is equal to the specified character. 223 */ 224 public boolean is(Character value) { 225 return eq(get(), value); 226 } 227 228 /** 229 * Checks if the current value matches any of the specified characters. 230 * 231 * <p> 232 * Uses {@link org.apache.juneau.commons.utils.Utils#eq(Object, Object)} for deep equality comparison of each character. 233 * 234 * <h5 class='section'>Example:</h5> 235 * <p class='bjava'> 236 * CharValue <jv>value</jv> = CharValue.<jsm>of</jsm>('B'); 237 * <jsm>assertTrue</jsm>(<jv>value</jv>.isAny('A', 'B', 'C')); 238 * <jsm>assertFalse</jsm>(<jv>value</jv>.isAny('X', 'Y')); 239 * </p> 240 * 241 * @param values The characters to compare to. 242 * @return <jk>true</jk> if the current value matches any of the specified characters. 243 */ 244 public boolean isAny(Character...values) { 245 assertArgNotNull("values", values); 246 var current = get(); 247 for (var value : values) 248 if (eq(current, value)) 249 return true; 250 return false; 251 } 252 253 /** 254 * Checks if the current value matches any character in the specified string. 255 * 256 * <h5 class='section'>Example:</h5> 257 * <p class='bjava'> 258 * CharValue <jv>value</jv> = CharValue.<jsm>of</jsm>('B'); 259 * <jsm>assertTrue</jsm>(<jv>value</jv>.isAny(<js>"ABC"</js>)); 260 * <jsm>assertFalse</jsm>(<jv>value</jv>.isAny(<js>"XYZ"</js>)); 261 * 262 * <jc>// Null/empty string returns false</jc> 263 * <jsm>assertFalse</jsm>(<jv>value</jv>.isAny((<jk>null</jk>)); 264 * <jsm>assertFalse</jsm>(<jv>value</jv>.isAny(<js>""</js>)); 265 * </p> 266 * 267 * @param values The string containing characters to compare to. 268 * @return <jk>true</jk> if the current value matches any character in the string. 269 */ 270 public boolean isAny(String values) { 271 if (values == null || values.isEmpty()) 272 return false; 273 var current = get(); 274 if (current == null) 275 return false; 276 return values.indexOf(current) >= 0; 277 } 278}