Thursday, December 5, 2013

Learning Guava Source Code

Ordering 是一个特殊的Comparator 实例。然而由于其良好的扩展性,可轻轻松构造复杂的comparator,比如加强型的容器的比较、排序等等;同时,Ordering提供链式方法调用,使用代码非常简洁漂亮。
Ordering<String> ordering = Ordering.from(String.CASE_INSENSITIVE_ORDER);"A", "a")


Ordering<String> ordering = Ordering.natural().nullsFirst().reverse().lexicographical().reverse().nullsLast();


Ordering<String> ordering = = Ordering.nullsFirst().reverse();
Collections.sort(names, ordering);

Ordering 详解


usingToString()按对象的字符串形式做字典排序[lexicographical ordering]




greatestOf(Iterable iterable, int k)获取可迭代对象中最大的k个元素
min(E, E)返回两个参数中最小的那个。如果相等,则返回第一个参数
min(E, E, E, E...)返回多个参数中最小的那个。如果有超过一个参数都最小,则返回第一个最小的参数


  • 基类
public abstract class Ordering<T> implements Comparator<T> {
    public <S extends T> Ordering<S> reverse() {
        return new ReverseOrdering<S>(this);
  • 子类
final class ReverseOrdering<T> extends Ordering<T> implements Serializable {
     ReverseOrdering(Ordering<? super T> forwardOrder) {
        this.forwardOrder = checkNotNull(forwardOrder);



Guava overflow detection
public static long checkedAdd(long a, long b) {
long result = a + b;
checkNoOverflow((a ^ b) &lt; 0 | (a ^ result) &gt;= 0); // if false, throw exception
return result;

// on overflow in case 1: a,b same sign, 2: a, b different sign, a and result same sign
public static long checkedSubtract(long a, long b) {
long result = a - b;
checkNoOverflow((a ^ b) &gt;= 0 | (a ^ result) &gt;= 0);
return result;

public static short checkedCast(long value) {
short result = (short) value;
checkArgument(result == value, "Out of range: %s", value);
return result;

public static int multAccum(int oldAcc, int newVal, int scale)
                  throws ArithmeticException {
  final long res = intRangeCheck(
   ((long) oldAcc) + intRangeCheck((long) newVal * (long) scale)
  return (int) res; // safe down-cast

public static final CharMatcher DIGIT = new RangesMatcher(
      "CharMatcher.DIGIT", ZEROES.toCharArray(), NINES.toCharArray());
public boolean matches(char c) {
int index = Arrays.binarySearch(rangeStarts, c);
if (index &gt;= 0) {
return true;
} else {
index = ~index - 1;
return index &gt;= 0 && c &lt;= rangeEnds[index];

Use bitset 
public static final CharMatcher JAVA_ISO_CONTROL =inRange('\u0000', '\u001f').or(inRange('\u007f', '\u009f'))
static CharMatcher inRange(final char startInclusive, final char endInclusive,
String description) {
return new FastMatcher(description) {
@Override public boolean matches(char c) {
return startInclusive &lt;= c && c &lt;= endInclusive;

@Override void setBits(BitSet table) {
table.set(startInclusive, endInclusive + 1);

Using Guava

List<Character> chars = Lists.charactersOf(string);
List<Character> chars = Chars.asList(string.toCharArray());
public static List<Character> convert(String string) {
return new AbstractList<Character>() {

public Character get(int index) {
return string.charAt(index);

public int size() {
return string.length();

List<Character> chars = string.chars()  // IntStream
.mapToObj(e -> (char)e) // Stream<Character>
乍看 checkArgument 與 checkState 感覺會有點像,是的!如果你只使用 assert 的話,基本上都是給個判斷條件,然後在不成立時產生錯誤。使用 checkArgument 與 checkState 的差別除了一個會丟出 IllegalArgumentException,一個是丟出 IllegalStateException 之外,最主要的是在語義差別,checkArgument 名稱表明這個方法是用於檢查引數,而 checkState 名稱表明,這個方法是用於檢查物件的狀態。 returns a non-loading cache. Just what you want. Just use
Cache<String, String> cache = CacheBuilder.newBuilder().build();
    CacheLoader<String, String> loader;
    loader = new CacheLoader<String, String>() {
        public String load(String key) {
            return key.toUpperCase();
    LoadingCache<String, String> cache;
    cache = CacheBuilder.newBuilder().maximumSize(3).build(loader);

Note: Many soft references may affect the system performance – it’s preferred to use maximumSize().

Now, let’s see how to handle cache null values. By default, Guava Cache will throw exceptions if you try to load a null value – as it doesn’t make any sense to cache a null.
But if null value means something in your code, then you can make good use of the Optional class as in the following example:
The biggest single reason that checkNotNull returns its argument is so it can be used in constructors, like so:
public Foo(Bar bar) { = checkNotNull(bar);
But the main reason that checkArgument doesn't do something similar is that you'd have to pass the argument separately anyway, and it just doesn't seem worth it -- especially with more complicated precondition checks, which can sometimes be more readable on their own line. Just because something can be a one-liner doesn't mean that it should be, if it doesn't increase readability.
natural()Uses the natural ordering on Comparable types.
usingToString()Compares objects by the lexicographical ordering of their string representations, as returned by toString().
Making a preexisting Comparator into an Ordering is as simple as using Ordering.from(Comparator).
But the more common way to create a custom Ordering is to skip the Comparator entirely in favor of extending the Ordering abstract class directly:
Ordering<String> byLengthOrdering = new Ordering<String>() {
  public int compare(String left, String right) {
    return, right.length());
reverse()Returns the reverse ordering.
nullsFirst()Returns an Ordering that orders nulls before non-null elements, and otherwise behaves the same as the original Ordering. See also nullsLast()
compound(Comparator)Returns an Ordering which uses the specified Comparator to "break ties."
lexicographical()Returns an Ordering that orders iterables lexicographically by their elements.
onResultOf(Function)Returns an Ordering which orders values by applying the function to them and then comparing the results using the original Ordering.

    List<Integer> integers = Arrays.asList(3, 2, 1);


Ordering<Person> ordering = Ordering
  .onResultOf(new Function<Person, Comparable>() {
      public Comparable apply(Person person) {
          return person.age;
                .onResultOf(new Function<String, Integer>() {
                    public Integer apply(String p) {
                        return p == null ? null : p.length();
Ordering 本身就是比較器,這看看它的類別定義就知道了:
            .onResultOf(p -> p == null ? null : p.length())
public abstract class Ordering<T> extends Object implements Comparator<T>
    Collections.sort(numbers, Ordering.natural().reversed());

    Integer maxValue = Ordering.natural().max(numbers);

    Integer minValue = Ordering.natural().min(numbers);

Comparator<String> byLength = new Comparator<String>() {
    public int compare(String left, String right) {
        return, right.length());
    Comparator<String> reversedByLength = Ordering.from(byLength).reversed();
    Collections.sort(random, reversedByLength);


Ordering by field
ComparisonChain performs a "lazy" comparison: it only performs comparisons until it finds a nonzero result, after which it ignores further input.
   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(this.aString, that.aString)
         .compare(this.anInt, that.anInt)
         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
HashBasedTable<String, String, String> hashBasedTable = HashBasedTable.create();
hashBasedTable.put("key1", "key2", "mike");

String value = hashBasedTable.get("key1", "key2"); // "mike"
Alternatively, one could look into a Guava Table, as that does the same sort of thing, with a better interface to it (something like the one I have above).
Multi-level HashMaps are not necessarily bad, it depends on your algorithm. The bad thing is that it's more difficult to manage. Consider using interfaces (something like repository) for HasMap values, this may make your design cleaner. Other option is to use composite keys in a HashMap.

MultiKeyMap multiKeyMap=MultiKeyMap.decorate(new LinkedHahMap())
multiKeyMap.put("key1","key2","key3","value1") // Last parameter is value against defined keys.
This is how we create a map with multiple keys. Now let’s see how to fetch value out of multiKeyMap for one combination of keys.
PS :- One point to note is you have to provide combination of key in the same sequence that you provided while puting into map.
MultiKey which is again an another way to solve above use case.A MultiKey allows multiple map keys to be merged together

MultiKey multiKey=new MultiKey("key1","key2","key3")
MultikeyMap multiKeyMap=MultiKeyMap.decorator(new LinkedHashMap())
//Map map = new HashMap(); you can also use simple Map while using Multikey.
//To fetch value from map using multikey, we simply do as follows :-
this.cache = CacheBuilder.newBuilder()
    .expireAfterAccess(5, TimeUnit.SECONDS)
    .build(new CacheLoader<String, Record>() {

  public Record load(String key) throws Exception {
    return getFromDatabase(key);


How about google guava?:
String alphaOnly = input.replaceAll("[^\\p{Alpha}]+","");
String alphaAndDigits = input.replaceAll("[^\\p{Alpha}\\p{Digit}]+","");
(All of these can be significantly improved by precompiling the regex pattern and storing it in a constant)
Or, with Guava:
private static final CharMatcher ALNUM =
  CharMatcher.inRange('a', 'z').or(CharMatcher.inRange('A', 'Z'))
  .or(CharMatcher.inRange('0', '9')).precomputed();
// ...
String alphaAndDigits = ALNUM.retainFrom(input);
Graph<Integer> graph = GraphBuilder.directed().build();  // graph is empty
graph.putEdge(1, 2);  // this adds 1 and 2 as nodes of this graph, and puts
                      // an edge between them
if (graph.nodes().contains(1)) {  // evaluates to "true"
Guava now provides a new, consistent hashing API that is much more user-friendly than the various hashing APIs provided in the JDK. See Hashing Explained. For a file, you can get the MD5 sum, CRC32 (with version 14.0+) or many other hashes easily:
HashCode md5 = Files.hash(file, Hashing.md5());
byte[] md5Bytes = md5.asBytes();
String md5Hex = md5.toString();

HashCode crc32 = Files.hash(file, Hashing.crc32());
int crc32Int = crc32.asInt();

// the Checksum API returns a long, but it's padded with 0s for 32-bit CRC
// this is the value you would get if using that API directly
long checksumResult = crc32.padToLong();
Once a Hasher has been given all its input, its hash() method can be used to retrieve a HashCode. (The behavior of hash() is unspecified if called more than once.) HashCodesupports equality testing and such, as well as asInt()asLong()asBytes() methods, and additionally, writeBytesTo(array, offset, maxLength), which writes the first maxLength bytes of the hash into the array.

Hasher hasher = hf.newHasher().putString("123", Charsets.UTF_8);


Exception in thread "main" java.lang.IllegalStateException: Cannot re-use a Hasher after calling hash() on it


BloomFilter<Person> friends = BloomFilter.create(personFunnel, 500, 0.01);
for(Person friend : friendsList) {
// much later
if (friends.mightContain(dude)) {
  // the probability that dude reached this place if he isn't a friend is 1%
  // we might, for example, start asynchronously loading things for dude while we do a more expensive exact check
2) If you’re hashing a String, don’t use String#getBytes. Instead, let us do the conversion to bytes for you.
  Hashing.md5().hashBytes(myString.getBytes(Charsets.UTF_8)); // Don’t do this.
  Hashing.md5().hashString(myString, Charsets.UTF_8); // Do this!
More importantly, never use the parameter-less version of String#getBytes because it silently uses the default Charset under the hood [2] (which is bad bad bad).

3) Instead of converting your HashCode instance to a primitive (like an int or long), instead use HashCode as a first class object! It’s simple, immutable, thread-safe, and suitable for adding to collections or exposing in APIs.
  int hash = Hashing.md5().hashBytes(bytez).asInt(); // Don’t do this.
  HashCode hash = Hashing.md5().hashBytes(bytez); // Do this!
In this example, we’re also losing bits of our hash code by collaring the 128-bit MD5 HashCode instance down to only 32-bits. The HashCode instance retains the full hash of the data.
    String result = Joiner.on(",").join(names);
    List<String> result = Splitter.on("-").trimResults()
    String result = Joiner.on(",").useForNull("nameless").join(names);
    String result = Joiner.on(" , ").withKeyValueSeparator(" = ")
    List<String> result = Splitter.on("-").trimResults()
    Map<String, String> result = Splitter.on(",")
8. Split String with multiple separators
    String input = "apple.banana,,orange,,.";
    List<String> result = Splitter.onPattern("[.,]")
    List<String> result = Splitter.fixedLength(3).splitToList(input);
    List<String> result = Splitter.on(",")

Map 相关的 Joiner 和 Splitter

第一个问题:D瓜哥需要从 URL 中获取相关请求的参数,并且将其转化成 Key-Value 形式放到 Map对象,方便后续操作。
URL 中,参数的格式大家应该都了解:。以 ? 分割后,后面的就是参数。如果自己手动写,还有一个一个分割,实在是懒得动手了。其实 Guava中内置了非常方便的方法来解决这个问题。代码如下:
int paramSeparater = url.indexOf("?");
String host = url.substring(0, paramSeparater);
String params = fromUrl.substring(paramSeparater + 1);
Map<String, String> paramMap = Maps.newHashMap();
Map<String, String> paramMap = Splitter.on("&").withKeyValueSeparator("=").split(params);
反过来,我们可能还需有将 Map 对象转化成 URL 的参数,来拼接出一个带参数的 URL。Guava 中也有非常方便的相关方法。代码如下:
Map<String, String> paramMap = Maps.newHashMap();
paramMap.put("userName", "diguage");
paramMap.put("webSite", "");
String url = url + "?" + Joiner.on("&").withKeyValueSeparator("=").join(paramMap);

我们的项目中,使用了 Spring JdbcTemplate,并基于这个这个东东写了一个 BaseDao,再结合注解,就可以获取表名和字段名。为了统一,规定将数据表以及字段的多个字母以下划线分割。大家都知道,Java 中类名以及属性名,都是驼峰命名法。那么就需要一个转化。 Guava 也提供了很方便的方法。代码如下:
1String tableName =, clazz.getSimpleName());
在上述代码中, CaseFormat 中设定了几个常用的格式:
  • LOWER_CAMEL – 以小写字母开头的驼峰命名规则。例如: lowerCamel。这个规则符合表示 Java 属性以及 Java 方法的命名规则。
  • LOWER_HYPHEN – 将单词的小写形式以连接符( - )连接的。例如: lower-hyphen
  • LOWER_UNDERSCORE – 将单词的小写形式以连接符( _ )连接的。例如: lower_underscore
  • UPPER_CAMEL – 以大写字母开头的驼峰命名规则。例如: UpperCamel。这个规则符合表示 Java 或 C++ 类名的命名规则。
  • UPPER_UNDERSCORE – 将单词的大写形式以连接符( _ )连接的。例如: UPPER_UNDERSCORE。这个规则符合表示 Java 或 C++ 常量的命名规则。
1String className =, tableName);
最后一个问题:需要将一个当前 URL 传递到下一个请求中,方便做跳转回来。作为参数传递,肯定需要对 URL 编码,否则作为参数的 URL 的参数就可能丢失了。 Guava 中通过也可以很好的支持:
1String currentUrl = UrlEscapers.urlFormParameterEscaper().escape("");
compare(a, b, Ordering.natural().nullsFirst())
return ComparisonChain.start() .compare(user.getUpdateDate(), other.getUser().getUpdateDate(), Ordering.natural().nullsLast()) .result();
   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(this.aString, that.aString)
         .compare(this.anInt, that.anInt)
         .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
Because the compiler can infer the type from the variable declaration.
List<String> list = Lists.newArrayList(),
the compiler will understand that the type of the collection (the type of E) will be <String>, since you expect to get a List of String.
It was useful to avoid rewriting entire <> arguments, but with Java7 and diamond operator you can avoid it using
List<String> list = new ArrayList<>();
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
This works for up to 5 key/value pairs, otherwise you can use its builder:
Map<String, String> test = ImmutableMap.<String, String>builder()
    .put("k1", "v1")
    .put("k2", "v2")
  • note that Guava's ImmutableMap implementation differs from Java's HashMap implementation (most notably it is immutable and does not permit null keys/values)

    Map<String, String> transMap = 
      Maps.transformValues(immutableMap, new Function<Integer, String>() {

        public String apply(Integer input) {
          return "BTC-" + input; //new value in transformed map
Why Guava does not provide a way to transform map keys

checkArgument(count > 0, "must be positive: %s", count);
Google Guava EventBus - an Easy and Elegant Way for Your Publisher - Subscriber Use Cases
    EventBus eventBus = new EventBus("test");
    EventListener listener = new EventListener();


    // when OurTestEvent(200));

    public void listen(OurTestEvent event) {
        lastMessage = event.getMessage();

Limiting the size of InputStreams
public class LimitedSizeInputStream extends InputStream {

    private final InputStream original;
    private final long maxSize;
    private long total;

    public LimitedSizeInputStream(InputStream original, long maxSize) {
        this.original = original;
        this.maxSize = maxSize;

    public int read() throws IOException {
        int i =;
        if (i>=0) incrementCounter(1);
        return i;

    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);

    public int read(byte b[], int off, int len) throws IOException {
        int i =, off, len);
        if (i>=0) incrementCounter(i);
        return i;

    private void incrementCounter(int size) throws IOException {
        total += size;
        if (total>maxSize) throw new IOException("InputStream exceeded maximum size in bytes.");

The main difference of the implementation above with BoundedInputStream is that BoundedInputStream does not throw an exception when the limit is exceeded (it just closes the stream)

Hashing a file
HashCode hashCode = Files.hash(file, Hashing.md5());


String value = Objects.firstNonNull(someString,"default value");
firstNonNull 方法可以在当你并不确定对象是否是空的情况下,用于作为一种提供默认值的方式。 需要注意的是,如果两个参数都为空,那么会抛出NullPointerException错误。

新版本中Objects.firstNonNull已经是Deprecated的了,使用MoreObjects.firstNonNull(T first,T second)替换。

Closer closer = Closer.create();
} catch (Throwable t) {
    throw closer.rethrow(t);
} finally {
Using Preconditions
equals, hashCode
Use ComparisonChain
ComparisonChain.start().compare(this.anInt, that.anInt).compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast()).result();
Objects.toStringHelper("MyObject").add("x", 1).toString();

String: Joiner
Joiner joiner = Joiner.on("; ").skipNulls();
joiner.join("Harry", null, "Ron", "Hermione");
final Joiner.MapJoiner mapJoiner = Joiner.on('&').withKeyValueSeparator("=");
final ImmutableMap<String, String> values = ImmutableMap.of("name", "mrhaki", "worksAt", "JDriven");
assert mapJoiner.join(values).equals("name=mrhaki&worksAt=JDriven");

Splitter.on(',').trimResults().omitEmptyStrings().split("foo,bar,,   qux");

String noControl = CharMatcher.JAVA_ISO_CONTROL.removeFrom(string); // remove control characters
String spaced = CharMatcher.WHITESPACE.trimAndCollapseFrom(string, ' ');
bytes = string.getBytes(Charsets.UTF_8);




Google Guava RateLimiter

* TODO(cpovirk): make SleepingStopwatch the last parameter throughout the class so that the
* overloads follow the usual convention: Foo(int), Foo(int, SleepingStopwatch)

class RateLimiterFilter extends Filter {
    val limiter = RateLimiter.create(100)
    def init(filterConfig: FilterConfig) {}
    def doFilter(request: ServletRequest, response: ServletResponse, chain: FilterChain) {
        if(limiter.tryAcquire()) {
            chain.doFilter(request, response)
        } else {
    def destroy() {}


Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts