2024/03/11

Guava in Java - ObjectUtilities

基本工具

CommonObjectUtilities

equals

當使用 Object.equals 時,如果遇到某個物件為 null,就會發生問題

com.google.common.base.Objects.equal 可做 null Object 的比較

JDK 提供類似的 java.util.Objects.equals()

    @Test
    public void equals() {
        com.google.common.base.Objects.equal("a", "a"); // returns true
        com.google.common.base.Objects.equal(null, "a"); // returns false
        com.google.common.base.Objects.equal("a", null); // returns false
        com.google.common.base.Objects.equal(null, null); // returns true
        // JDK 提供類似的 java.util.Objects.equals()
        java.util.Objects.equals("a", "a"); // returns true
        java.util.Objects.equals(null, "a"); // returns false
        java.util.Objects.equals("a", null); // returns false
        java.util.Objects.equals(null, null); // returns true

        String a = null;
        String b = "b";
        Exception exception = assertThrows(NullPointerException.class, () -> {
            a.equals(b);
        });
        Exception exception2 = assertThrows(NullPointerException.class, () -> {
            b.equals(a);
        });
    }

hashCode

簡化 hashCode 的做法,可直接根據多個 fields 產生 hash

    @Test
    public void hashCodeTest() {
        InnerClass innerClass = new InnerClass();
        int hash1 = innerClass.hashCode();
        int hash2 = innerClass.hashCode2();
        assertEquals(hash1, hash2);;
    }

    public static class InnerClass {
        private String a="a";
        private String b="b";

        @Override
        public int hashCode() {
            return com.google.common.base.Objects.hashCode(a, b);
        }
        // JDK 有對應類似的 java.util.Objects.hash
        public int hashCode2() {
            return java.util.Objects.hash(a, b);
        }
    }

toString

利用 MoreObjects.toStringHelper() 簡化 toString

    @Test
    public void toStringTest() {
        InnerClass2 cls = new InnerClass2();
        String clsString = cls.toString();
//        System.out.printf("clsString=%s%n", clsString);
        assertEquals(clsString, "InnerClass2{a=a, b=2, x=1}");;
    }

    public static class InnerClass2 {
        private String a="a";
        private int b=2;

        @Override
        public String toString() {
            return com.google.common.base.MoreObjects.toStringHelper(this)
                    .add("a", a)
                    .add("b", b)
                    .add("x", 1)
                    .toString();
        }
    }

compare/compareTo

guava 提供 ComparisonChain,他是 fluent Comparator 可改善 compareTo 的寫法

    class Person implements Comparable<Person> {
        private String lastName;
        private String firstName;
        private int zipCode;

        public int compareTo(Person that) {
            return ComparisonChain.start()
                    .compare(this.firstName, that.firstName)
                    .compare(this.lastName, that.lastName)
                    .compare(this.zipCode, that.zipCode, Ordering.natural().nullsLast())
                    .result();
        }

        public int compareTo2(Person other) {
            int cmp = lastName.compareTo(other.lastName);
            if (cmp != 0) {
                return cmp;
            }
            cmp = firstName.compareTo(other.firstName);
            if (cmp != 0) {
                return cmp;
            }
            return Integer.compare(zipCode, other.zipCode);
        }
    }

Throwable

package guava.basic;

import java.util.List;

import com.google.common.base.Throwables;

public class ThrowableTest {
    public static void main(String[] args) {

        ThrowableTest tester = new ThrowableTest();

        try {
            System.out.println("invalidInputExceptionTest");
            tester.invalidInputExceptionTest();
        } catch (InvalidInputException e) {
            //get the root cause
            System.out.println("invalidInputExceptionTest getRootCause");
            System.out.println(Throwables.getRootCause(e));

        } catch (Exception e) {
            //get the stack trace in string format
            System.out.println("invalidInputExceptionTest getStackTraceAsString");
            System.out.println(Throwables.getStackTraceAsString(e));
        }

        System.out.println("");
        try {
            System.out.println("indexOutOfBoundsExceptionTest");
            tester.indexOutOfBoundsExceptionTest();
        } catch (Exception e) {
            System.out.println("indexOutOfBoundsExceptionTest getStackTraceAsString");
            List<Throwable> elist = Throwables.getCausalChain(e);
            for( Throwable t1: elist ) {
                System.out.println(Throwables.getStackTraceAsString(t1));
            }
//            System.out.println(Throwables.getStackTraceAsString(e));
        }
    }

    public void invalidInputExceptionTest() throws InvalidInputException {
        try {
            sqrt(-1.0);
        } catch (Throwable e) {
            //check the type of exception and throw it
            Throwables.propagateIfInstanceOf(e, InvalidInputException.class);
            // Throws throwable as-is only if it is a RuntimeException or an Error.
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);
        }
    }

    public void indexOutOfBoundsExceptionTest() {
        try {
            int[] data = {1, 2, 3};
            getValue(data, 4);
        } catch (Throwable e) {
            Throwables.propagateIfInstanceOf(e, IndexOutOfBoundsException.class);
            Throwables.throwIfUnchecked(e);
            throw new RuntimeException(e);
        }
    }

    public double sqrt(double input) throws InvalidInputException {
        if (input < 0) throw new InvalidInputException();
        return Math.sqrt(input);
    }

    public double getValue(int[] list, int index) throws IndexOutOfBoundsException {
        return list[index];
    }
}

class InvalidInputException extends Exception {
}

執行結果

invalidInputExceptionTest
invalidInputExceptionTest getRootCause
com.maxkit.guava.InvalidInputException

indexOutOfBoundsExceptionTest
indexOutOfBoundsExceptionTest getStackTraceAsString
java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 3
    at com.maxkit.guava.ThrowableTest.getValue(ThrowableTest.java:71)
    at com.maxkit.guava.ThrowableTest.indexOutOfBoundsExceptionTest(ThrowableTest.java:57)
    at com.maxkit.guava.ThrowableTest.main(ThrowableTest.java:31)

References

Home · google/guava Wiki · GitHub

Guava Guide | Baeldung

Guava:Google开源的Java工具库,太强大了 | Java程序员进阶之路

Google Guava 工具類 的介紹和使用 - HackMD

# Google Guava官方教程

專欄文章:Guava 教學

沒有留言:

張貼留言