guava notes

Reference

Optional

Optional 可以用來處理 null value 與避免 NullPointerException
public class OptionalTest {


    @Test
    public void test() {
        try {
            Optional.of(null);
            Assert.fail("Optional.of shouldn't accept null");
        } catch (NullPointerException ex) {
        }
        Optional opt = Optional.of("Test");
        Assert.assertTrue(opt.isPresent());
        Assert.assertEquals("Test", opt.get());
        Assert.assertEquals("Test", opt.or("QQ"));
        Assert.assertEquals("Test", opt.orNull());
        Assert.assertEquals(ImmutableSet.of("Test"), opt.asSet());

        Optional nullableOptional = Optional.fromNullable(null);
        Assert.assertFalse(nullableOptional.isPresent());
        try {
            Assert.assertNull(nullableOptional.get());
            Assert.fail();
        } catch (IllegalStateException ex) {
        }
        Assert.assertEquals("QQ", nullableOptional.or("QQ"));
        Assert.assertNull(nullableOptional.orNull());
        Assert.assertEquals(ImmutableSet.of(), nullableOptional.asSet());
        Assert.assertEquals(Optional.absent(), nullableOptional);
    }

}

ComparisonChain

ComparisonChain 可以用比較漂亮的程式實作 compare
public class ComparisonChainTest {

    @Test
    public void test() {
        NumbersObject n1 = new NumbersObject(1,2,3);
        NumbersObject n2 = new NumbersObject(1,2,4);
        NumbersObject n3 = new NumbersObject(1,3,4);
        NumbersObject n4 = new NumbersObject(2,2,4);

        List<NumbersObject> list = Arrays.asList(n4, n3, n2, n1);
        Collections.sort(list, (o1, o2) -> ComparisonChain.start()
                .compare(o1.a,o2.a)
                .compare(o1.b,o2.b)
                .compare(o1.c,o2.c)
                .result());
        Assert.assertTrue(n1 == list.get(0));
        Assert.assertTrue(n2 == list.get(1));
        Assert.assertTrue(n3 == list.get(2));
        Assert.assertTrue(n4 == list.get(3));
    }

    final static class NumbersObject {
        private final int a ;
        private final int b;
        private final int c;
        NumbersObject(int a, int b, int c) {
            this.a = a;
            this.b = b;
            this.c = c;
        }
    }

}

Ordering

Ordering 其實就是 Comparator, 可以傳給 Collections. 例如: Collections.sort(list, Ordering)

usingToString

用 toString 的結果排序
@Test
public void usingToString() {
    NumbersObject n1 = new NumbersObject(1, 2, 3);
    NumbersObject n2 = new NumbersObject(1, 2, 4);
    NumbersObject n3 = new NumbersObject(-1, 2, -3);
    NumbersObject n4 = new NumbersObject(-2, 3, 5);
    List<NumbersObject> numbers = Arrays.asList(n1, n2, n3, n4);
    Collections.sort(numbers, Ordering.usingToString());
    Assert.assertEquals(n3, numbers.get(0));
    Assert.assertEquals(n4, numbers.get(1));
    Assert.assertEquals(n1, numbers.get(2));
    Assert.assertEquals(n2, numbers.get(3));
}

private final class NumbersObject {

    public final Integer a;
    public final Integer b;
    public final Integer c;

    public NumbersObject(Integer a, Integer b, Integer c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("a",a)
                .add("b",b)
                .add("c",c)
                .toString();
    }
}

nullsFirst & nullsLast

排序的時候, null 放在最前面位置(或最後).
物件本身是 Comparable, 可以直接拿 nullsFirst 回傳的 Ordering 來排序, 若物件本身不是 Comparable 就要提供排序的方式
@Test
public void nullsFirst_NotComparable() {
    NumbersObject n1 = new NumbersObject(1, 2, 3);
    NumbersObject n2 = new NumbersObject(1, 2, 4);
    NumbersObject n3 = new NumbersObject(-1, 2, -3);
    NumbersObject n4 = new NumbersObject(-2, 3, 5);
    NumbersObject nullNumber = new NumbersObject(null,null,null);
    List<NumbersObject> numbers = Arrays.asList(n1, n2, n3, n4, nullNumber);
    Ordering ordering = Ordering.natural().nullsFirst().onResultOf(new Function<NumbersObject, Integer>() {
        @Override
        public Integer apply(NumbersObject numbersObject) {
            return numbersObject.a;
        }
    });
    Collections.sort(numbers, ordering);
    Assert.assertEquals(nullNumber, numbers.get(0));
    Assert.assertEquals(n4, numbers.get(1));
    Assert.assertEquals(n3, numbers.get(2));
    Assert.assertEquals(n1, numbers.get(3));
    Assert.assertEquals(n2, numbers.get(4));
}

@Test
public void nullsFirst_Comparable() {
    List<Integer> list = Arrays.asList(5, 2, 6, 7, 3, null);
    Collections.sort(list, Ordering.natural().nullsFirst());
    Assert.assertEquals((Integer) null, list.get(0));
    Assert.assertEquals((Integer) 2, list.get(1));
    Assert.assertEquals((Integer) 3, list.get(2));
    Assert.assertEquals((Integer) 5, list.get(3));
    Assert.assertEquals((Integer) 6, list.get(4));
    Assert.assertEquals((Integer) 7, list.get(5));
}

@Test
public void nullsLast_Comparable() {
    List<Integer> list = Arrays.asList(5, 2, 6, 7, 3, null);
    Collections.sort(list, Ordering.natural().nullsLast());
    Assert.assertEquals((Integer) 2, list.get(0));
    Assert.assertEquals((Integer) 3, list.get(1));
    Assert.assertEquals((Integer) 5, list.get(2));
    Assert.assertEquals((Integer) 6, list.get(3));
    Assert.assertEquals((Integer) 7, list.get(4));
    Assert.assertEquals((Integer) null, list.get(5));
}

@Test
public void nullsLast_NotComparable() {
    NumbersObject n1 = new NumbersObject(1, 2, 3);
    NumbersObject n2 = new NumbersObject(1, 2, 4);
    NumbersObject n3 = new NumbersObject(-1, 2, -3);
    NumbersObject n4 = new NumbersObject(-2, 3, 5);
    NumbersObject nullNumber = new NumbersObject(null,null,null);
    List<NumbersObject> numbers = Arrays.asList(n1, n2, n3, n4, nullNumber);
    Ordering ordering = Ordering.natural().nullsLast().onResultOf(new Function<NumbersObject, Integer>() {
        @Override
        public Integer apply(NumbersObject numbersObject) {
            return numbersObject.a;
        }
    });
    Collections.sort(numbers, ordering);
    Assert.assertEquals(n4, numbers.get(0));
    Assert.assertEquals(n3, numbers.get(1));
    Assert.assertEquals(n1, numbers.get(2));
    Assert.assertEquals(n2, numbers.get(3));
    Assert.assertEquals(nullNumber, numbers.get(4));
}

private final class NumbersObject {

    public final Integer a;
    public final Integer b;
    public final Integer c;

    public NumbersObject(Integer a, Integer b, Integer c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("a",a)
                .add("b",b)
                .add("c",c)
                .toString();
    }
}

compound

可以組合多個 Comparator, 在上一個 Comparator 無法決定時就交給下一個 Comparator 判斷.
在排列的屬性有優先順序的時候可以讓程式變簡單.
例如: 先排 a, 再 b, 再 c. null 的話就排前面
@Test
public void compound() {
    NumbersObject n1 = new NumbersObject(1, 2, 3);
    NumbersObject n2 = new NumbersObject(1, 2, 4);
    NumbersObject n3 = new NumbersObject(-1, 2, -3);
    NumbersObject n4 = new NumbersObject(-2, 3, 5);
    NumbersObject nullNumber = new NumbersObject(null,null,null);
    List<NumbersObject> numbers = Arrays.asList(n1, n2, n3, n4, nullNumber);
    Comparator<NumbersObject> byNullFirstA = Ordering.natural().nullsFirst().onResultOf((t) -> t.a);
    Comparator<NumbersObject> byNullFirstB = Ordering.natural().nullsFirst().onResultOf((t) -> t.b);
    Comparator<NumbersObject> byNullFirstC = Ordering.natural().nullsFirst().onResultOf((t) -> t.c);
    Ordering orderByABC = Ordering.compound(Arrays.asList(byNullFirstA, byNullFirstB, byNullFirstC));
    Collections.sort(numbers, orderByABC);
    Assert.assertEquals(nullNumber, numbers.get(0));
    Assert.assertEquals(n4, numbers.get(1));
    Assert.assertEquals(n3, numbers.get(2));
    Assert.assertEquals(n1, numbers.get(3));
    Assert.assertEquals(n2, numbers.get(4));
}

private final class NumbersObject {

    public final Integer a;
    public final Integer b;
    public final Integer c;

    public NumbersObject(Integer a, Integer b, Integer c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("a",a)
                .add("b",b)
                .add("c",c)
                .toString();
    }
}

lexicographical

跟 Collections.sort 不同, loxicographical 是用來替很多個 iterable 作排序
@Test
public void lexicographically() {
    ImmutableList<String> empty = ImmutableList.of();
    ImmutableList<String> a = ImmutableList.of("a");
    ImmutableList<String> aa = ImmutableList.of("a", "a");
    ImmutableList<String> ab = ImmutableList.of("a", "b");
    ImmutableList<String> b = ImmutableList.of("b");
    List<ImmutableList<String>> all = Arrays.asList(b,a,ab,aa,empty);
    Ordering<Iterable<String>> c = Ordering.<String>natural().lexicographical();
    Collections.sort(all, c);
    Assert.assertEquals(empty, all.get(0));
    Assert.assertEquals(a, all.get(1));
    Assert.assertEquals(aa, all.get(2));
    Assert.assertEquals(ab, all.get(3));
    Assert.assertEquals(b, all.get(4));
}

@Test
public void lexicographicallyReverse() {
    ImmutableList<String> empty = ImmutableList.of();
    ImmutableList<String> a = ImmutableList.of("a");
    ImmutableList<String> aa = ImmutableList.of("a", "a");
    ImmutableList<String> ab = ImmutableList.of("a", "b");
    ImmutableList<String> b = ImmutableList.of("b");
    List<ImmutableList<String>> all = Arrays.asList(b,a,ab,aa,empty);
    Ordering<Iterable<String>> c = Ordering.<String>natural().lexicographical().reverse();
    Collections.sort(all, c);
    Assert.assertEquals(empty, all.get(4));
    Assert.assertEquals(a, all.get(3));
    Assert.assertEquals(aa, all.get(2));
    Assert.assertEquals(ab, all.get(1));
    Assert.assertEquals(b, all.get(0));
}

@Test
public void reverseLexicographically() {
    ImmutableList<String> empty = ImmutableList.of();
    ImmutableList<String> a = ImmutableList.of("a");
    ImmutableList<String> aa = ImmutableList.of("a", "a");
    ImmutableList<String> ab = ImmutableList.of("a", "b");
    ImmutableList<String> b = ImmutableList.of("b");
    List<ImmutableList<String>> all = Arrays.asList(b,a,ab,aa,empty);
    Ordering<Iterable<String>> c = Ordering.<String>natural().reverse().lexicographical();
    Collections.sort(all, c);
    System.out.println(all);
    Assert.assertEquals(empty, all.get(0));
    Assert.assertEquals(b, all.get(1));
    Assert.assertEquals(a, all.get(2));
    Assert.assertEquals(ab, all.get(3));
    Assert.assertEquals(aa, all.get(4));
}

onResultOf

就是自訂排序方式, 直行完後會再往前呼叫其他排序法
@Test
public void onResultOf() {
    Comparator<Integer> c = Ordering.<Integer>natural().onResultOf((x) -> Optional.ofNullable(x).orElse(4)%5);
    List<Integer> list = Arrays.asList(5, 11, 4, 1, 2, 5, 7, 9, null);
    Collections.sort(list, c);
    System.out.println(list);
    Assert.assertEquals(5, list.get(0).intValue());
    Assert.assertEquals(5, list.get(1).intValue());
    Assert.assertEquals(11, list.get(2).intValue());
    Assert.assertEquals(1, list.get(3).intValue());
    Assert.assertEquals(2, list.get(4).intValue());
    Assert.assertEquals(7, list.get(5).intValue());
    Assert.assertEquals(4, list.get(6).intValue());
    Assert.assertEquals(9, list.get(7).intValue());
    Assert.assertEquals(null, list.get(8));
}

@Test
public void onResultOf_reverse() {
    Comparator<Integer> c = Ordering.<Integer>natural().reverse().onResultOf((x) -> Optional.ofNullable(x).orElse(4)%5);
    List<Integer> list = Arrays.asList(5, 11, 4, 1, 2, 5, 7, 9, null);
    Collections.sort(list, c);
    System.out.println(list);
    Assert.assertEquals(5, list.get(8).intValue());
    Assert.assertEquals(5, list.get(7).intValue());
    Assert.assertEquals(11, list.get(5).intValue());
    Assert.assertEquals(1, list.get(6).intValue());
    Assert.assertEquals(2, list.get(3).intValue());
    Assert.assertEquals(7, list.get(4).intValue());
    Assert.assertEquals(4, list.get(0).intValue());
    Assert.assertEquals(9, list.get(1).intValue());
    Assert.assertEquals(null, list.get(2));
}

greatestOf 與 leastOf

拿排序過資料的最後幾筆與最前幾筆.
@Test
public void greatestOf() {
    NumbersObject n1 = new NumbersObject(1, 2, 3);
    NumbersObject n2 = new NumbersObject(1, 2, 4);
    NumbersObject n3 = new NumbersObject(-1, 2, -3);
    NumbersObject n4 = new NumbersObject(-2, 3, 5);
    NumbersObject nullNumber = new NumbersObject(null,null,null);
    List<NumbersObject> numbers = Arrays.asList(n1, n2, n3, n4, nullNumber);
    List<NumbersObject> greatestOf = Ordering.natural().greatestOf(numbers,3);
    Assert.assertEquals(n4, greatestOf.get(0));
    Assert.assertEquals(n3, greatestOf.get(1));
    Assert.assertEquals(n1, greatestOf.get(2));
}

@Test
public void leastOf() {
    NumbersObject n1 = new NumbersObject(1, 2, 3);
    NumbersObject n2 = new NumbersObject(2, 2, 4);
    NumbersObject n3 = new NumbersObject(-1, 2, -3);
    NumbersObject n4 = new NumbersObject(-2, 3, 5);
    NumbersObject nullNumber = new NumbersObject(null,null,null);
    List<NumbersObject> numbers = Arrays.asList(n1, n2, n3, n4, nullNumber);
    List<NumbersObject> leastOf = Ordering.natural().leastOf(numbers,3);
    Assert.assertEquals(nullNumber, leastOf.get(0));
    Assert.assertEquals(n2, leastOf.get(1));
    Assert.assertEquals(n1, leastOf.get(2));
}

private final class NumbersObject implements Comparable<NumbersObject> {

    public final Integer a;
    public final Integer b;
    public final Integer c;

    public NumbersObject(Integer a, Integer b, Integer c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }

    @Override
    public String toString() {
        return MoreObjects.toStringHelper(this)
                .add("a",a)
                .add("b",b)
                .add("c",c)
                .toString();
    }

    @Override
    public int compareTo(NumbersObject o) {
        if (a == null && o.a == null) {
            return 0;
        } else if (a == null) {
            return -1;
        } else if (o.a == null) {
            return 1;
        } else {
            return Ints.compare(o.a,a);
        }
    }
}

ImmutableXXX

沒有 ImmutableSet 的時候會用 Collections.unmodifiableSet, 差別是 ImmutableSet 有很多好用的 api 讓程式簡單很多.
另外 ImmutableXXX 在能夠避免線性成長的 copy time 時候會盡量避免. 例如 ImmutableList.copyOf(ImmutableSet)
@Test(expected = UnsupportedOperationException.class)
public void of() {
    ImmutableSet.of("a","b").add("a");
}

@Test(expected = UnsupportedOperationException.class)
public void copyOf() {
    ImmutableSet.copyOf(Arrays.asList("a","b","c")).add("");
}

@Test
public void listCopyOfSet() {
    ImmutableList immutableList = ImmutableList.copyOf(ImmutableSet.of("a","b"));
}

Multipleset

像是 set 一樣, 差別是一個同樣的資料可以存多筆. 也可以記錄某種資料總共有幾筆.
@RunWith(Parameterized.class)
public class MultisetTest {

    @Parameterized.Parameters
    public static Collection<Object[]> data() {
        return Arrays.asList(new Object[][] {
                { HashMultiset.create() },
                {TreeMultiset.create() },
                {LinkedHashMultiset.create() },
                {ConcurrentHashMultiset.create()},
        });
    }

    private final Multiset<String> testee;

    public MultisetTest(Multiset<String> testee) {
        this.testee = testee;
    }

    @Test
    public void test() {
        testee.addAll(Arrays.asList("A","B","A"));
        Assert.assertEquals(2, testee.count("A"));
        Assert.assertEquals(1, testee.count("B"));
    }

}

public class ImmutableMultisetTest {

    @Test
    public void count() {
        ImmutableMultiset set = ImmutableMultiset.of("A","B","A");
        Assert.assertEquals(2,set.count("A"));
        Assert.assertEquals(1,set.count("B"));
    }

}

別名演算法 Alias Method

 題目 每個伺服器支援不同的 TPM (transaction per minute) 當 request 來的時候, 系統需要馬上根據 TPM 的能力隨機找到一個適合的 server. 雖然稱為 "隨機", 但還是需要有 TPM 作為權重. 解法 別名演算法...