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 021 022/** 023 * A simple mutable float value. 024 * 025 * <p> 026 * This class extends {@link Holder}<{@link Float}> and provides a convenient way to pass mutable 027 * float 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 float value to track a running sum</jc> 037 * FloatHolder <jv>sum</jv> = FloatHolder.<jsm>create</jsm>(); 038 * 039 * <jc>// Use in a lambda to accumulate values</jc> 040 * list.forEach(<jv>x</jv> -> { 041 * <jv>sum</jv>.set(<jv>sum</jv>.get() + <jv>x</jv>.floatValue()); 042 * }); 043 * 044 * <jsm>log</jsm>(<js>"Total: "</js> + <jv>sum</jv>.get()); 045 * </p> 046 * 047 * <h5 class='section'>See Also:</h5><ul> 048 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommonsLang">Lang Package</a> 049 * </ul> 050 */ 051@SuppressWarnings({ 052 "java:S1192" // Duplicated literals (argument/property names) read more clearly inline than as constants 053}) 054public class FloatHolder extends Holder<Float> { 055 056 /** 057 * Creates a new float value initialized to <c>0.0f</c>. 058 * 059 * <h5 class='section'>Example:</h5> 060 * <p class='bjava'> 061 * FloatHolder <jv>value</jv> = FloatHolder.<jsm>create</jsm>(); 062 * <jsm>assertEquals</jsm>(0.0f, <jv>value</jv>.get()); 063 * </p> 064 * 065 * @return A new float value. 066 */ 067 public static FloatHolder create() { 068 return of(0.0f); 069 } 070 071 /** 072 * Creates a new float value with the specified initial value. 073 * 074 * <h5 class='section'>Example:</h5> 075 * <p class='bjava'> 076 * FloatHolder <jv>value</jv> = FloatHolder.<jsm>of</jsm>(3.14f); 077 * <jsm>assertEquals</jsm>(3.14f, <jv>value</jv>.get()); 078 * </p> 079 * 080 * @param value The initial value. Can be <jk>null</jk>. 081 * @return A new float value. 082 */ 083 public static FloatHolder of(Float value) { 084 return new FloatHolder(value); 085 } 086 087 /** 088 * Constructor. 089 * 090 * @param value The initial value. Can be <jk>null</jk>. 091 */ 092 public FloatHolder(Float value) { 093 super(value); 094 } 095 096 /** 097 * Checks if the current value equals the specified value within the given precision. 098 * 099 * <p> 100 * This method handles <jk>null</jk> values safely and performs precision-based equality comparison 101 * using absolute difference. The comparison returns <jk>true</jk> if the absolute difference between 102 * the two values is less than or equal to the specified precision. 103 * 104 * <h5 class='section'>Example:</h5> 105 * <p class='bjava'> 106 * FloatHolder <jv>value</jv> = FloatHolder.<jsm>of</jsm>(3.14f); 107 * <jsm>assertTrue</jsm>(<jv>value</jv>.is(3.14f, 0.01f)); <jc>// Exact match within 0.01</jc> 108 * <jsm>assertTrue</jsm>(<jv>value</jv>.is(3.15f, 0.02f)); <jc>// Within 0.02</jc> 109 * <jsm>assertFalse</jsm>(<jv>value</jv>.is(3.15f, 0.001f)); <jc>// Not within 0.001</jc> 110 * 111 * <jc>// Handles null values</jc> 112 * FloatHolder <jv>empty</jv> = FloatHolder.<jsm>create</jsm>(); 113 * <jv>empty</jv>.set(<jk>null</jk>); 114 * <jsm>assertFalse</jsm>(<jv>empty</jv>.is(3.14f, 0.01f)); <jc>// Null doesn't match any value</jc> 115 * 116 * <jc>// Precision-based comparison</jc> 117 * FloatHolder <jv>pi</jv> = FloatHolder.<jsm>of</jsm>(3.14159f); 118 * <jsm>assertTrue</jsm>(<jv>pi</jv>.is(3.14f, 0.002f)); <jc>// Within 0.002 precision</jc> 119 * </p> 120 * 121 * @param other The value to compare with. 122 * @param precision The maximum allowed difference for equality. Must be non-negative. 123 * @return <jk>true</jk> if the absolute difference between the values is less than or equal to precision. 124 * @throws IllegalArgumentException if precision is negative. 125 */ 126 public boolean is(float other, float precision) { 127 req(precision >= 0, "Precision must be non-negative"); 128 var v = get(); 129 if (v == null) { 130 return false; 131 } 132 return Math.abs(v - other) <= precision; 133 } 134 135 /** 136 * Checks if the current value matches any of the specified values within the given precision. 137 * 138 * <p> 139 * This method handles <jk>null</jk> values safely and performs precision-based equality comparison 140 * for each value using absolute difference. 141 * 142 * <h5 class='section'>Example:</h5> 143 * <p class='bjava'> 144 * FloatHolder <jv>value</jv> = FloatHolder.<jsm>of</jsm>(3.14f); 145 * <jsm>assertTrue</jsm>(<jv>value</jv>.isAny(0.01f, 2.5f, 3.15f, 5.0f)); <jc>// Matches 3.15f within 0.01</jc> 146 * <jsm>assertFalse</jsm>(<jv>value</jv>.isAny(0.001f, 1.0f, 2.0f, 5.0f)); <jc>// No match within 0.001</jc> 147 * 148 * <jc>// Empty array returns false</jc> 149 * <jsm>assertFalse</jsm>(<jv>value</jv>.isAny(0.01f)); 150 * </p> 151 * 152 * @param precision The maximum allowed difference for equality. Must be non-negative and is the first parameter. 153 * @param values The values to compare to. Must not be <jk>null</jk>. 154 * @return <jk>true</jk> if the current value matches any of the specified values within the precision. 155 * @throws IllegalArgumentException if precision is negative. 156 */ 157 public boolean isAny(float precision, float...values) { 158 req(precision >= 0, "Precision must be non-negative"); 159 reqnn("values", values); 160 var v = get(); 161 if (v == null) 162 return false; 163 for (var value : values) 164 if (Math.abs(v - value) <= precision) 165 return true; 166 return false; 167 } 168}