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 string value. 025 * 026 * <p> 027 * This class extends {@link Holder}<{@link String}> and adds convenience methods for string 028 * equality testing, which are useful in lambdas and conditional logic. 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 synchronization or atomic classes. 033 * </ul> 034 * 035 * <h5 class='section'>Example:</h5> 036 * <p class='bjava'> 037 * <jc>// Create a mutable string</jc> 038 * StringHolder <jv>name</jv> = StringHolder.<jsm>of</jsm>(<js>"John"</js>); 039 * 040 * <jc>// Check equality</jc> 041 * <jk>if</jk> (<jv>name</jv>.is(<js>"John"</js>)) { 042 * <jsm>System</jsm>.<jsf>out</jsf>.println(<js>"Name is John"</js>); 043 * } 044 * 045 * <jc>// Check multiple values</jc> 046 * <jk>if</jk> (<jv>name</jv>.isAny(<js>"John"</js>, <js>"Jane"</js>, <js>"Bob"</js>)) { 047 * <jsm>System</jsm>.<jsf>out</jsf>.println(<js>"Name found"</js>); 048 * } 049 * </p> 050 * 051 * <h5 class='section'>See Also:</h5><ul> 052 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsLang">Lang Package</a> 053 * </ul> 054 */ 055@SuppressWarnings({ 056 "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants 057}) 058public class StringHolder extends Holder<String> { 059 060 /** 061 * Creates a new empty string value. 062 * 063 * <h5 class='section'>Example:</h5> 064 * <p class='bjava'> 065 * StringHolder <jv>name</jv> = StringHolder.<jsm>create</jsm>(); 066 * <jsm>assertNull</jsm>(<jv>name</jv>.get()); 067 * </p> 068 * 069 * @return A new string value. 070 */ 071 public static StringHolder create() { 072 return of(null); 073 } 074 075 /** 076 * Creates a new string value with the specified initial value. 077 * 078 * <h5 class='section'>Example:</h5> 079 * <p class='bjava'> 080 * StringHolder <jv>name</jv> = StringHolder.<jsm>of</jsm>(<js>"Hello"</js>); 081 * <jsm>assertEquals</jsm>(<js>"Hello"</js>, <jv>name</jv>.get()); 082 * </p> 083 * 084 * @param value The initial value. Can be <jk>null</jk>. 085 * @return A new string value. 086 */ 087 public static StringHolder of(String value) { 088 return new StringHolder(value); 089 } 090 091 /** 092 * Constructor. 093 */ 094 public StringHolder() { 095 super(null); 096 } 097 098 /** 099 * Constructor. 100 * 101 * @param value The initial value. Can be <jk>null</jk>. 102 */ 103 public StringHolder(String value) { 104 super(value); 105 } 106 107 /** 108 * Checks if the current value is equal to the specified value. 109 * 110 * <p> 111 * Uses {@link Shorts#eq(Object, Object)} for deep equality comparison, which handles nulls safely. 112 * 113 * <h5 class='section'>Example:</h5> 114 * <p class='bjava'> 115 * StringHolder <jv>name</jv> = StringHolder.<jsm>of</jsm>(<js>"John"</js>); 116 * <jsm>assertTrue</jsm>(<jv>name</jv>.is(<js>"John"</js>)); 117 * <jsm>assertFalse</jsm>(<jv>name</jv>.is(<js>"Jane"</js>)); 118 * 119 * <jc>// Handles null safely</jc> 120 * StringHolder <jv>empty</jv> = StringHolder.<jsm>create</jsm>(); 121 * <jsm>assertTrue</jsm>(<jv>empty</jv>.is(<jk>null</jk>)); 122 * </p> 123 * 124 * @param value The value to compare to. Can be <jk>null</jk>. 125 * @return <jk>true</jk> if the current value is equal to the specified value. 126 */ 127 @Override 128 public boolean is(String value) { 129 return eq(get(), value); 130 } 131 132 /** 133 * Checks if the current value matches any of the specified values. 134 * 135 * <p> 136 * Uses {@link Shorts#eq(Object, Object)} for deep equality comparison of each value. 137 * 138 * <h5 class='section'>Example:</h5> 139 * <p class='bjava'> 140 * StringHolder <jv>name</jv> = StringHolder.<jsm>of</jsm>(<js>"John"</js>); 141 * <jsm>assertTrue</jsm>(<jv>name</jv>.isAny(<js>"John"</js>, <js>"Jane"</js>, <js>"Bob"</js>)); 142 * <jsm>assertFalse</jsm>(<jv>name</jv>.isAny(<js>"Alice"</js>, <js>"Charlie"</js>)); 143 * 144 * <jc>// Empty array returns false</jc> 145 * <jsm>assertFalse</jsm>(<jv>name</jv>.isAny()); 146 * </p> 147 * 148 * @param values The values to compare to. Must not be <jk>null</jk>. 149 * @return <jk>true</jk> if the current value matches any of the specified values. 150 */ 151 public boolean isAny(String...values) { 152 reqnn("values", values); 153 var current = get(); 154 for (var value : values) 155 if (eq(current, value)) 156 return true; 157 return false; 158 } 159}