All Downloads are FREE. Search and download functionalities are using the official Maven repository.

panda.lang.Objects Maven / Gradle / Ivy

package panda.lang;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;

import panda.lang.builder.CompareToBuilder;
import panda.lang.builder.EqualsBuilder;
import panda.lang.builder.ToStringBuilder;
import panda.lang.mutable.MutableInt;

/**
 * utility class for Object. 
 */
public abstract class Objects {
	/**
	 * 

* Singleton used as a {@code null} placeholder where {@code null} has another meaning. *

*

* For example, in a {@code HashMap} the {@link java.util.HashMap#get(java.lang.Object)} method * returns {@code null} if the {@code Map} contains {@code null} or if there is no matching key. * The {@code Null} placeholder can be used to distinguish between these two cases. *

*

* Another example is {@code Hashtable}, where {@code null} cannot be stored. *

*

* This instance is Serializable. *

*/ public static final Null NULL = new Null(); // Defaulting // ----------------------------------------------------------------------- /** *

* Returns a default value if the object passed is {@code null}. *

* *
	 * defaultIfNull(null, null)      = null
	 * defaultIfNull(null, "")        = ""
	 * defaultIfNull(null, "zz")      = "zz"
	 * defaultIfNull("abc", *)        = "abc"
	 * defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
	 * 
* * @param the type of the object * @param object the {@code Object} to test, may be {@code null} * @param defaultValue the default value to return, may be {@code null} * @return {@code object} if it is not {@code null}, defaultValue otherwise */ public static T defaultIfNull(final T object, final T defaultValue) { return object != null ? object : defaultValue; } /** *

* Returns the first value in the array which is not {@code null}. If all the values are * {@code null} or the array is {@code null} or empty then {@code null} is returned. *

* *
	 * firstNonNull(null, null)      = null
	 * firstNonNull(null, "")        = ""
	 * firstNonNull(null, null, "")  = ""
	 * firstNonNull(null, "zz")      = "zz"
	 * firstNonNull("abc", *)        = "abc"
	 * firstNonNull(null, "xyz", *)  = "xyz"
	 * firstNonNull(Boolean.TRUE, *) = Boolean.TRUE
	 * firstNonNull()                = null
	 * 
* * @param the component type of the array * @param values the values to test, may be {@code null} or empty * @return the first value from {@code values} which is not {@code null}, or {@code null} if * there are no non-null values */ @SafeVarargs public static T firstNonNull(final T... values) { if (values != null) { for (final T val : values) { if (val != null) { return val; } } } return null; } // Null-safe equals/hashCode // ----------------------------------------------------------------------- /** *

* Compares two objects for equality, where either one or both objects may be {@code null}. *

* *
	 * equals(null, null)                  = true
	 * equals(null, "")                    = false
	 * equals("", null)                    = false
	 * equals("", "")                      = true
	 * equals(Boolean.TRUE, null)          = false
	 * equals(Boolean.TRUE, "true")        = false
	 * equals(Boolean.TRUE, Boolean.TRUE)  = true
	 * equals(Boolean.TRUE, Boolean.FALSE) = false
	 * 
* * @param object1 the first object, may be {@code null} * @param object2 the second object, may be {@code null} * @return {@code true} if the values of both objects are the same */ public static boolean equals(final Object object1, final Object object2) { if (object1 == object2) { return true; } if (object1 == null || object2 == null) { return false; } return object1.equals(object2); } /** *

* Compares two objects for inequality, where either one or both objects may be {@code null}. *

* *
	 * notEqual(null, null)                  = false
	 * notEqual(null, "")                    = true
	 * notEqual("", null)                    = true
	 * notEqual("", "")                      = false
	 * notEqual(Boolean.TRUE, null)          = true
	 * notEqual(Boolean.TRUE, "true")        = true
	 * notEqual(Boolean.TRUE, Boolean.TRUE)  = false
	 * notEqual(Boolean.TRUE, Boolean.FALSE) = true
	 * 
* * @param object1 the first object, may be {@code null} * @param object2 the second object, may be {@code null} * @return {@code false} if the values of both objects are the same */ public static boolean notEqual(final Object object1, final Object object2) { return Objects.equals(object1, object2) == false; } /** *

* Gets the hash code of an object returning zero when the object is {@code null}. *

* *
	 * hashCode(null)   = 0
	 * hashCode(obj)    = obj.hashCode()
	 * 
* * @param obj the object to obtain the hash code of, may be {@code null} * @return the hash code of the object, or zero if null */ public static int hashCode(final Object obj) { // hashCode(Object) retained for performance, as hash code is often critical return obj == null ? 0 : obj.hashCode(); } /** *

* Gets the hash code for multiple objects. *

*

* This allows a hash code to be rapidly calculated for a number of objects. The hash code for a * single object is the not same as {@link #hashCode(Object)}. The hash code for * multiple objects is the same as that calculated by an {@code ArrayList} containing the * specified objects. *

* *
	 * hash((Object[]) null)  = 0
	 * hash(new Object[0])    = 1
	 * hash(a)                = 31 + a.hashCode()
	 * hash(a,b)              = (31 + a.hashCode()) * 31 + b.hashCode()
	 * hash(a,b,c)            = ((31 + a.hashCode()) * 31 + b.hashCode()) * 31 + c.hashCode()
	 * 
* * @param a the objects to obtain the hash code of, may be {@code null} * @return the hash code of the objects, or zero if null */ public static int hash(final Object... a) { if (a == null) { return 0; } int hash = 1; for (final Object object : a) { hash = hash * 31 + hashCode(object); } return hash; } // Identity ToString // ----------------------------------------------------------------------- /** *

* Gets the toString that would be produced by {@code Object} if a class did not override * toString itself. {@code null} will return {@code null}. *

* *
	 * identityToString(null)         = null
	 * identityToString("")           = "java.lang.String@1e23"
	 * identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
	 * 
* * @param object the object to create a toString for, may be {@code null} * @return the default toString text, or {@code null} if {@code null} passed in */ public static String identityToString(final Object object) { if (object == null) { return null; } StringBuilder buffer = new StringBuilder(); identityToString(buffer, object); return buffer.toString(); } /** *

* Appends the toString that would be produced by {@code Object} if a class did not override * toString itself. {@code null} will throw a NullPointerException for either of the two * parameters. *

* *
	 * identityToString(buf, "")            = buf.append("java.lang.String@1e23"
	 * identityToString(buf, Boolean.TRUE)  = buf.append("java.lang.Boolean@7fa"
	 * identityToString(buf, Boolean.TRUE)  = buf.append("java.lang.Boolean@7fa")
	 * 
* * @param buffer the buffer to append to * @param object the object to create a toString for */ public static void identityToString(StringBuilder buffer, Object object) { if (object == null) { throw new NullPointerException("Cannot get the toString of a null identity"); } buffer.append(object.getClass().getName()).append('@') .append(Integer.toHexString(System.identityHashCode(object))); } // ToString // ----------------------------------------------------------------------- /** *

* Gets the {@code toString} of an {@code Object} returning an empty string ("") if {@code null} * input. *

* *
	 * toString(null)         = ""
	 * toString("")           = ""
	 * toString("bat")        = "bat"
	 * toString(Boolean.TRUE) = "true"
	 * 
* * @see Strings#defaultString(String) * @see String#valueOf(Object) * @param obj the Object to {@code toString}, may be null * @return the passed in Object's toString, or {@code ""} if {@code null} input */ public static String toString(final Object obj) { return toString(obj, Strings.EMPTY); } /** *

* Gets the {@code toString} of an {@code Object} returning a specified text if {@code null} * input. *

* *
	 * toString(null, null)           = null
	 * toString(null, "null")         = "null"
	 * toString("", "null")           = ""
	 * toString("bat", "null")        = "bat"
	 * toString(Boolean.TRUE, "null") = "true"
	 * 
* * @see Strings#defaultString(String,String) * @see String#valueOf(Object) * @param obj the Object to {@code toString}, may be null * @param nullStr the String to return if {@code null} input, may be null * @return the passed in Object's toString, or {@code nullStr} if {@code null} input */ public static String toString(final Object obj, final String nullStr) { if (obj == null) { return nullStr; } if (obj instanceof CharSequence) { return obj.toString(); } if (obj.getClass().isArray()) { return Arrays.toString(obj); } String str = obj.toString(); return Strings.defaultString(str, nullStr); } // Comparable // ----------------------------------------------------------------------- /** *

* Null safe comparison of Comparables. *

* * @param type of the values processed by this method * @param values the set of comparable values, may be null * @return
    *
  • If any objects are non-null and unequal, the lesser object. *
  • If all objects are non-null and equal, the first. *
  • If any of the comparables are null, the lesser of the non-null objects. *
  • If all the comparables are null, null is returned. *
*/ @SafeVarargs public static > T min(final T... values) { T result = null; if (values != null) { for (final T value : values) { if (compare(value, result, true) < 0) { result = value; } } } return result; } /** *

* Null safe comparison of Comparables. *

* * @param type of the values processed by this method * @param values the set of comparable values, may be null * @return
    *
  • If any objects are non-null and unequal, the greater object. *
  • If all objects are non-null and equal, the first. *
  • If any of the comparables are null, the greater of the non-null objects. *
  • If all the comparables are null, null is returned. *
*/ @SafeVarargs public static > T max(final T... values) { T result = null; if (values != null) { for (final T value : values) { if (compare(value, result, false) > 0) { result = value; } } } return result; } /** *

* Null safe comparison of Comparables. {@code null} is assumed to be less than a non- * {@code null} value. *

* * @param type of the values processed by this method * @param c1 the first comparable, may be null * @param c2 the second comparable, may be null * @return a negative value if c1 < c2, zero if c1 = c2 and a positive value if c1 > c2 */ public static > int compare(final T c1, final T c2) { return compare(c1, c2, false); } /** *

* Null safe comparison of Comparables. *

* * @param type of the values processed by this method * @param c1 the first comparable, may be null * @param c2 the second comparable, may be null * @param nullGreater if true {@code null} is considered greater than a non-{@code null} value * or if false {@code null} is considered less than a Non-{@code null} value * @return a negative value if c1 < c2, zero if c1 = c2 and a positive value if c1 > c2 * @see java.util.Comparator#compare(Object, Object) */ public static > int compare(final T c1, final T c2, final boolean nullGreater) { if (c1 == c2) { return 0; } if (c1 == null) { return nullGreater ? 1 : -1; } if (c2 == null) { return nullGreater ? -1 : 1; } return c1.compareTo(c2); } /** * Find the "best guess" middle value among comparables. If there is an even number of total * values, the lower of the two middle values will be returned. * * @param type of values processed by this method * @param items to compare * @return T at middle position * @throws NullPointerException if items is {@code null} * @throws IllegalArgumentException if items is empty or contains {@code null} values */ @SafeVarargs public static > T median(final T... items) { Asserts.notEmpty(items); Asserts.noNullElements(items); TreeSet sort = new TreeSet(); Collections.addAll(sort, items); @SuppressWarnings("unchecked") // we know all items added were T instances final T result = (T)sort.toArray()[(sort.size() - 1) / 2]; return result; } /** * Find the "best guess" middle value among comparables. If there is an even number of total * values, the lower of the two middle values will be returned. * * @param type of values processed by this method * @param comparator to use for comparisons * @param items to compare * @return T at middle position * @throws NullPointerException if items or comparator is {@code null} * @throws IllegalArgumentException if items is empty or contains {@code null} values */ @SafeVarargs public static T median(final Comparator comparator, final T... items) { Asserts.notEmpty(items, "null/empty items"); Asserts.noNullElements(items); Asserts.notNull(comparator, "null comparator"); TreeSet sort = new TreeSet(comparator); Collections.addAll(sort, items); @SuppressWarnings("unchecked") // we know all items added were T instances T result = (T)sort.toArray()[(sort.size() - 1) / 2]; return result; } // Mode // ----------------------------------------------------------------------- /** * Find the most frequently occurring item. * * @param type of values processed by this method * @param items to check * @return most populous T, {@code null} if non-unique or no items supplied */ @SafeVarargs public static T mode(final T... items) { if (Arrays.isNotEmpty(items)) { final HashMap occurrences = new HashMap(items.length); for (final T t : items) { final MutableInt count = occurrences.get(t); if (count == null) { occurrences.put(t, new MutableInt(1)); } else { count.increment(); } } T result = null; int max = 0; for (final Map.Entry e : occurrences.entrySet()) { final int cmp = e.getValue().intValue(); if (cmp == max) { result = null; } else if (cmp > max) { max = cmp; result = e.getKey(); } } return result; } return null; } // Null // ----------------------------------------------------------------------- /** *

* Class used as a null placeholder where {@code null} has another meaning. *

*

* For example, in a {@code HashMap} the {@link java.util.HashMap#get(java.lang.Object)} method * returns {@code null} if the {@code Map} contains {@code null} or if there is no matching key. * The {@code Null} placeholder can be used to distinguish between these two cases. *

*

* Another example is {@code Hashtable}, where {@code null} cannot be stored. *

*/ public static class Null implements Serializable { /** * Required for serialization support. Declare serialization compatibility with Commons Lang * 1.0 * * @see java.io.Serializable */ private static final long serialVersionUID = 7092611880189329093L; /** * Restricted constructor - singleton. */ Null() { super(); } /** *

* Ensure singleton. *

* * @return the singleton value */ private Object readResolve() { return Objects.NULL; } } /** * is empty * * @param o object * @return true if object is an empty string */ public static boolean isEmpty(Object o) { if (o == null) { return true; } if (o instanceof CharSequence) { return ((CharSequence)o).length() == 0; } else if (o instanceof Collection) { return ((Collection)o).isEmpty(); } else if (o instanceof Map) { return ((Map)o).isEmpty(); } else if (o.getClass().isArray()) { return Array.getLength(o) == 0; } else { return false; } } /** * is not empty * * @param o object * @return true if object is not an empty string */ public static boolean isNotEmpty(Object o) { return !isEmpty(o); } /** * Determine if the given objects are equal, returning true if both are * null or false if only one is null. *

* Compares arrays with Arrays.equals, performing an equality check based on the * array elements rather than the array reference. * * @param o1 first Object to compare * @param o2 second Object to compare * @return whether the given objects are equal * @see java.util.Arrays#equals */ public static boolean nullSafeEquals(Object o1, Object o2) { if (o1 == o2) { return true; } if (o1 == null || o2 == null) { return false; } if (o1.equals(o2)) { return true; } if (o1.getClass().isArray() && o2.getClass().isArray()) { if (o1 instanceof Object[] && o2 instanceof Object[]) { return Arrays.equals((Object[])o1, (Object[])o2); } if (o1 instanceof boolean[] && o2 instanceof boolean[]) { return Arrays.equals((boolean[])o1, (boolean[])o2); } if (o1 instanceof byte[] && o2 instanceof byte[]) { return Arrays.equals((byte[])o1, (byte[])o2); } if (o1 instanceof char[] && o2 instanceof char[]) { return Arrays.equals((char[])o1, (char[])o2); } if (o1 instanceof double[] && o2 instanceof double[]) { return Arrays.equals((double[])o1, (double[])o2); } if (o1 instanceof float[] && o2 instanceof float[]) { return Arrays.equals((float[])o1, (float[])o2); } if (o1 instanceof int[] && o2 instanceof int[]) { return Arrays.equals((int[])o1, (int[])o2); } if (o1 instanceof long[] && o2 instanceof long[]) { return Arrays.equals((long[])o1, (long[])o2); } if (o1 instanceof short[] && o2 instanceof short[]) { return Arrays.equals((short[])o1, (short[])o2); } } return false; } /** * Return a hex String form of an object's identity hash code. * * @param obj the object * @return the object's identity code in hex notation */ public static String getIdentityHexString(Object obj) { return Integer.toHexString(System.identityHashCode(obj)); } /** * create a ToStringBuilder instance * @return ToStringBuilder instance */ public static ToStringBuilder toStringBuilder() { return new ToStringBuilder(); } /** * @return EqualsBuilder instance */ public static EqualsBuilder equalsBuilder() { return new EqualsBuilder(); } /** * @return CompareToBuilder instance */ public static CompareToBuilder compareToBuilder() { return new CompareToBuilder(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy