From 1dfb0fb3e22c3616fdfa3a8249be526c44dbe890 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Tue, 18 Jul 2023 15:12:09 +0000 Subject: [PATCH] 8311188: Simplify and modernize equals and hashCode in java.text Reviewed-by: lancea, naoto, rriggs --- .../classes/java/text/AttributedString.java | 33 ++++++++----------- .../share/classes/java/text/ChoiceFormat.java | 5 +-- .../share/classes/java/text/Collator.java | 5 +-- .../java/text/CompactNumberFormat.java | 10 +++--- .../classes/java/text/DateFormatSymbols.java | 6 ++-- .../classes/java/text/DecimalFormat.java | 9 +++-- .../java/text/DecimalFormatSymbols.java | 5 ++- .../classes/java/text/FieldPosition.java | 20 +++++------ .../classes/java/text/MessageFormat.java | 6 ++-- .../share/classes/java/text/NumberFormat.java | 5 +-- .../classes/java/text/ParsePosition.java | 13 ++++---- .../classes/java/text/RuleBasedCollator.java | 5 +-- .../classes/java/text/SimpleDateFormat.java | 8 ++--- .../share/classes/sun/text/IntHashtable.java | 12 ++++--- .../sun/text/RuleBasedBreakIterator.java | 28 ++++------------ 15 files changed, 72 insertions(+), 98 deletions(-) diff --git a/src/java.base/share/classes/java/text/AttributedString.java b/src/java.base/share/classes/java/text/AttributedString.java index 48044b0ea5d..41eaaf40dad 100644 --- a/src/java.base/share/classes/java/text/AttributedString.java +++ b/src/java.base/share/classes/java/text/AttributedString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -618,7 +618,7 @@ public class AttributedString { int currIndex = runIndex; int runStart = runStarts[currIndex]; while (runStart >= beginIndex && - valuesMatch(value, getAttribute(attribute, currIndex - 1))) { + Objects.equals(value, getAttribute(attribute, currIndex - 1))) { currIndex--; runStart = runStarts[currIndex]; } @@ -632,7 +632,7 @@ public class AttributedString { int currIndex = runIndex; int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength; while (runLimit <= endIndex && - valuesMatch(value, getAttribute(attribute, currIndex + 1))) { + Objects.equals(value, getAttribute(attribute, currIndex + 1))) { currIndex++; runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength; } @@ -650,22 +650,13 @@ public class AttributedString { // returns whether all specified attributes have equal values in the runs with the given indices private boolean attributeValuesMatch(Set attributes, int runIndex1, int runIndex2) { for (Attribute key : attributes) { - if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) { + if (!Objects.equals(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) { return false; } } return true; } - // returns whether the two objects are either both null or equal - private static final boolean valuesMatch(Object value1, Object value2) { - if (value1 == null) { - return value2 == null; - } else { - return value1.equals(value2); - } - } - /** * Appends the contents of the CharacterIterator iterator into the * StringBuilder buf. @@ -760,6 +751,7 @@ public class AttributedString { // Object methods. See documentation in that class. + @Override public boolean equals(Object obj) { if (this == obj) { return true; @@ -775,6 +767,7 @@ public class AttributedString { return true; } + @Override public int hashCode() { return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex; } @@ -861,7 +854,7 @@ public class AttributedString { int runStart = currentRunStart; int runIndex = currentRunIndex; while (runStart > beginIndex && - valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) { + Objects.equals(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) { runIndex--; runStart = runStarts[runIndex]; } @@ -902,7 +895,7 @@ public class AttributedString { int runLimit = currentRunLimit; int runIndex = currentRunIndex; while (runLimit < endIndex && - valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) { + Objects.equals(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) { runIndex++; runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex; } @@ -1081,11 +1074,10 @@ class AttributeEntry implements Map.Entry { this.value = value; } + @Override public boolean equals(Object o) { - if (!(o instanceof AttributeEntry other)) { - return false; - } - return other.key.equals(key) && Objects.equals(other.value, value); + return o instanceof AttributeEntry other + && other.key.equals(key) && Objects.equals(other.value, value); } public Attribute getKey() { @@ -1100,8 +1092,9 @@ class AttributeEntry implements Map.Entry { throw new UnsupportedOperationException(); } + @Override public int hashCode() { - return key.hashCode() ^ (value==null ? 0 : value.hashCode()); + return key.hashCode() ^ Objects.hashCode(value); } public String toString() { diff --git a/src/java.base/share/classes/java/text/ChoiceFormat.java b/src/java.base/share/classes/java/text/ChoiceFormat.java index cf87f4452cf..84a3e4ef7ad 100644 --- a/src/java.base/share/classes/java/text/ChoiceFormat.java +++ b/src/java.base/share/classes/java/text/ChoiceFormat.java @@ -497,6 +497,7 @@ public class ChoiceFormat extends NumberFormat { /** * Generates a hash code for the message format object. */ + @Override public int hashCode() { int result = choiceLimits.length; if (choiceFormats.length > 0) { @@ -509,11 +510,11 @@ public class ChoiceFormat extends NumberFormat { /** * Equality comparison between two */ + @Override public boolean equals(Object obj) { - if (obj == null) return false; if (this == obj) // quick check return true; - if (getClass() != obj.getClass()) + if (obj == null || getClass() != obj.getClass()) return false; ChoiceFormat other = (ChoiceFormat) obj; return (Arrays.equals(choiceLimits, other.choiceLimits) diff --git a/src/java.base/share/classes/java/text/Collator.java b/src/java.base/share/classes/java/text/Collator.java index efbf495ac6c..78fb7c654b6 100644 --- a/src/java.base/share/classes/java/text/Collator.java +++ b/src/java.base/share/classes/java/text/Collator.java @@ -530,10 +530,7 @@ public abstract class Collator if (this == that) { return true; } - if (that == null) { - return false; - } - if (getClass() != that.getClass()) { + if (that == null || getClass() != that.getClass()) { return false; } Collator other = (Collator) that; diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index 5b95b945799..f8603e85fe8 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -2354,7 +2354,11 @@ public final class CompactNumberFormat extends NumberFormat { @Override public boolean equals(Object obj) { - if (!super.equals(obj)) { + if (this == obj) { + return true; + } + + if (!super.equals(obj)) { // super does null and class checks return false; } @@ -2369,9 +2373,7 @@ public final class CompactNumberFormat extends NumberFormat { } /** - * Returns the hash code for this {@code CompactNumberFormat} instance. - * - * @return hash code for this {@code CompactNumberFormat} + * {@return the hash code for this {@code CompactNumberFormat} instance} */ @Override public int hashCode() { diff --git a/src/java.base/share/classes/java/text/DateFormatSymbols.java b/src/java.base/share/classes/java/text/DateFormatSymbols.java index e09d8088640..231061ac0ec 100644 --- a/src/java.base/share/classes/java/text/DateFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DateFormatSymbols.java @@ -683,6 +683,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { /** * Override equals */ + @Override public boolean equals(Object obj) { if (this == obj) return true; @@ -695,10 +696,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { && Arrays.equals(shortWeekdays, that.shortWeekdays) && Arrays.equals(ampms, that.ampms) && Arrays.deepEquals(getZoneStringsWrapper(), that.getZoneStringsWrapper()) - && ((localPatternChars != null - && localPatternChars.equals(that.localPatternChars)) - || (localPatternChars == null - && that.localPatternChars == null))); + && Objects.equals(localPatternChars, that.localPatternChars)); } // =======================privates=============================== diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index 3e0f1e3246f..ba7846ea404 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -2918,10 +2918,13 @@ public class DecimalFormat extends NumberFormat { @Override public boolean equals(Object obj) { - if (obj == null) - return false; + if (this == obj) { + return true; + } + if (!super.equals(obj)) - return false; // super does class check + return false; // super does null and class checks + DecimalFormat other = (DecimalFormat) obj; return ((posPrefixPattern == other.posPrefixPattern && positivePrefix.equals(other.positivePrefix)) diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java index 795e087a351..b5f2b404f78 100644 --- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java +++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -741,9 +741,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable { */ @Override public boolean equals(Object obj) { - if (obj == null) return false; if (this == obj) return true; - if (getClass() != obj.getClass()) return false; + if (obj == null || getClass() != obj.getClass()) return false; DecimalFormatSymbols other = (DecimalFormatSymbols) obj; return (zeroDigit == other.zeroDigit && groupingSeparator == other.groupingSeparator && diff --git a/src/java.base/share/classes/java/text/FieldPosition.java b/src/java.base/share/classes/java/text/FieldPosition.java index 26d7da7f6ec..7b9d23bafcb 100644 --- a/src/java.base/share/classes/java/text/FieldPosition.java +++ b/src/java.base/share/classes/java/text/FieldPosition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,6 +38,8 @@ package java.text; +import java.util.Objects; + /** * {@code FieldPosition} is a simple class used by {@code Format} * and its subclasses to identify fields in formatted output. Fields can @@ -218,28 +220,22 @@ public class FieldPosition { /** * Overrides equals */ + @Override public boolean equals(Object obj) { - if (obj == null) return false; if (!(obj instanceof FieldPosition other)) return false; - if (attribute == null) { - if (other.attribute != null) { - return false; - } - } - else if (!attribute.equals(other.attribute)) { + if (!Objects.equals(attribute, other.attribute)) return false; - } return (beginIndex == other.beginIndex && endIndex == other.endIndex && field == other.field); } /** - * Returns a hash code for this FieldPosition. - * @return a hash code value for this object + * {@return a hash code for this FieldPosition} */ + @Override public int hashCode() { return (field << 24) | (beginIndex << 16) | endIndex; } @@ -270,7 +266,7 @@ public class FieldPosition { /** * Return true if the receiver wants a {@code Format.Field} value and * {@code attribute} is equal to it, or true if the receiver - * represents an inteter constant and {@code field} equals it. + * represents an integer constant and {@code field} equals it. */ private boolean matchesField(Format.Field attribute, int field) { if (this.attribute != null) { diff --git a/src/java.base/share/classes/java/text/MessageFormat.java b/src/java.base/share/classes/java/text/MessageFormat.java index e339b9eec3a..2df3b2f0aa3 100644 --- a/src/java.base/share/classes/java/text/MessageFormat.java +++ b/src/java.base/share/classes/java/text/MessageFormat.java @@ -47,6 +47,7 @@ import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.Objects; /** @@ -1132,6 +1133,7 @@ public class MessageFormat extends Format { /** * Equality comparison between two message format objects */ + @Override public boolean equals(Object obj) { if (this == obj) // quick check return true; @@ -1140,8 +1142,7 @@ public class MessageFormat extends Format { MessageFormat other = (MessageFormat) obj; return (maxOffset == other.maxOffset && pattern.equals(other.pattern) - && ((locale != null && locale.equals(other.locale)) - || (locale == null && other.locale == null)) + && Objects.equals(locale,other.locale) && Arrays.equals(offsets,other.offsets) && Arrays.equals(argumentNumbers,other.argumentNumbers) && Arrays.equals(formats,other.formats)); @@ -1150,6 +1151,7 @@ public class MessageFormat extends Format { /** * Generates a hash code for the message format object. */ + @Override public int hashCode() { return pattern.hashCode(); // enough for reasonable distribution } diff --git a/src/java.base/share/classes/java/text/NumberFormat.java b/src/java.base/share/classes/java/text/NumberFormat.java index 6d893bc4ec7..4628870bbdb 100644 --- a/src/java.base/share/classes/java/text/NumberFormat.java +++ b/src/java.base/share/classes/java/text/NumberFormat.java @@ -711,13 +711,10 @@ public abstract class NumberFormat extends Format { */ @Override public boolean equals(Object obj) { - if (obj == null) { - return false; - } if (this == obj) { return true; } - if (getClass() != obj.getClass()) { + if (obj == null || getClass() != obj.getClass()) { return false; } NumberFormat other = (NumberFormat) obj; diff --git a/src/java.base/share/classes/java/text/ParsePosition.java b/src/java.base/share/classes/java/text/ParsePosition.java index e24c1bc6924..71caee3bd7f 100644 --- a/src/java.base/share/classes/java/text/ParsePosition.java +++ b/src/java.base/share/classes/java/text/ParsePosition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,18 +122,17 @@ public class ParsePosition { /** * Overrides equals */ + @Override public boolean equals(Object obj) { - if (obj == null) return false; - if (!(obj instanceof ParsePosition other)) - return false; - return (index == other.index && errorIndex == other.errorIndex); + return obj instanceof ParsePosition other + && index == other.index && errorIndex == other.errorIndex; } /** - * Returns a hash code for this ParsePosition. - * @return a hash code value for this object + * {@return a hash code for this ParsePosition} */ + @Override public int hashCode() { return (errorIndex << 16) | index; } diff --git a/src/java.base/share/classes/java/text/RuleBasedCollator.java b/src/java.base/share/classes/java/text/RuleBasedCollator.java index 047fd9d4b14..fc98da4d2e8 100644 --- a/src/java.base/share/classes/java/text/RuleBasedCollator.java +++ b/src/java.base/share/classes/java/text/RuleBasedCollator.java @@ -729,9 +729,9 @@ public class RuleBasedCollator extends Collator{ * @return true if the current table-based collation object is the same * as the table-based collation object obj; false otherwise. */ + @Override public boolean equals(Object obj) { - if (obj == null) return false; - if (!super.equals(obj)) return false; // super does class check + if (!super.equals(obj)) return false; // super does null and class checks RuleBasedCollator other = (RuleBasedCollator) obj; // all other non-transient information is also contained in rules. return (getRules().equals(other.getRules())); @@ -740,6 +740,7 @@ public class RuleBasedCollator extends Collator{ /** * Generates the hash code for the table-based collation object */ + @Override public int hashCode() { return getRules().hashCode(); } diff --git a/src/java.base/share/classes/java/text/SimpleDateFormat.java b/src/java.base/share/classes/java/text/SimpleDateFormat.java index 4eb08f6f5f6..b4bb3e3f31e 100644 --- a/src/java.base/share/classes/java/text/SimpleDateFormat.java +++ b/src/java.base/share/classes/java/text/SimpleDateFormat.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -2409,9 +2409,7 @@ public class SimpleDateFormat extends DateFormat { } /** - * Returns the hash code value for this {@code SimpleDateFormat} object. - * - * @return the hash code value for this {@code SimpleDateFormat} object. + * {@return the hash code value for this {@code SimpleDateFormat} object} */ @Override public int hashCode() @@ -2431,7 +2429,7 @@ public class SimpleDateFormat extends DateFormat { public boolean equals(Object obj) { if (!super.equals(obj)) { - return false; // super does class check + return false; // super does null and class checks } SimpleDateFormat that = (SimpleDateFormat) obj; return (pattern.equals(that.pattern) diff --git a/src/java.base/share/classes/sun/text/IntHashtable.java b/src/java.base/share/classes/sun/text/IntHashtable.java index af2c1d37d84..73d7220fe18 100644 --- a/src/java.base/share/classes/sun/text/IntHashtable.java +++ b/src/java.base/share/classes/sun/text/IntHashtable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -91,12 +91,13 @@ public final class IntHashtable { rehash(); } + @Override public boolean equals (Object that) { - if (that.getClass() != this.getClass()) return false; - - IntHashtable other = (IntHashtable) that; + if (!(that instanceof IntHashtable other)) { + return false; + } if (other.size() != count || other.defaultValue != defaultValue) { - return false; + return false; } for (int i = 0; i < keyList.length; ++i) { int key = keyList[i]; @@ -106,6 +107,7 @@ public final class IntHashtable { return true; } + @Override public int hashCode() { // NOTE: This function isn't actually used anywhere in this package, but it's here // in case this class is ever used to make sure we uphold the invariants about diff --git a/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java b/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java index 4d46cbd1c9c..c648fb40875 100644 --- a/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java +++ b/src/java.base/share/classes/sun/text/RuleBasedBreakIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,6 +46,8 @@ import java.text.BreakIterator; import java.text.CharacterIterator; import java.text.StringCharacterIterator; import java.util.MissingResourceException; +import java.util.Objects; + import sun.text.CompactByteArray; import sun.text.SupplementaryCharacterData; @@ -498,24 +500,9 @@ public class RuleBasedBreakIterator extends BreakIterator { */ @Override public boolean equals(Object that) { - try { - if (that == null) { - return false; - } - - RuleBasedBreakIterator other = (RuleBasedBreakIterator) that; - if (checksum != other.checksum) { - return false; - } - if (text == null) { - return other.text == null; - } else { - return text.equals(other.text); - } - } - catch(ClassCastException e) { - return false; - } + return that instanceof RuleBasedBreakIterator other + && checksum == other.checksum + && Objects.equals(text, other.text); } /** @@ -527,8 +514,7 @@ public class RuleBasedBreakIterator extends BreakIterator { } /** - * Compute a hashcode for this BreakIterator - * @return A hash code + * {@return hashcode for this BreakIterator} */ @Override public int hashCode() {