Written in Jane’s book 2018-10-21 20:07


Hi ~ I am a Guava

Introduction to the

Guava is an extension of Google’s Java-based library collection: collections, caches, primitive types, concurrent libraries, annotations, string handling, I/O, and more.

The document address

Github.com/google/guav… ## Project address github.com/google/guav… ## Source code description

  • Com.google.com mon. Annotations:

Common annotation type.

  • com.google.common.base

Basic utility class libraries and interfaces that make using the Java language more enjoyable.

  • com.google.common.cache

Cache toolkit, a very simple and powerful in-JVM cache.

  • com.google.common.collect

Collection interface extension and implementation with generics, as well as utility classes and sorting.

  • com.google.common.escape

Escape tools.

  • com.google.common.eventbus

Publish subscribe style event bus.

  • com.google.common.graph

Process graph-based data structure data.

  • com.google.common.hash

Hash toolkit. Hash tools more complex than those provided by Object.hashCode(), including Bloom filters, Hash functions: FarmHash, Fingerprint64, HMAC algorithms.

  • com.google.common.html

Html string escape.

  • com.google.common.io

I/O toolkit. Simplify IO operations, especially the entire IO streams and files in Java 5 and 6.

  • com.google.common.math

Primitive arithmetic types and a toolkit for supernumeration. This includes operations not provided by the JDK.

  • com.google.common.net

Network toolkit.

  • com.google.common.primitives

Static toolkit for eight primitive and unsigned types.

  • com.google.common.reflect

Reflector kit.

  • com.google.common.util.concurrent

Multithreaded toolkit.

  • com.google.common.xml

XML string escape

  • com.google.thirdparty.publicsuffix

The fundamental tools

1.Optional

Create an Optional instance

methods role
Optional.of(T) Creates an Optional instance of the specified reference. If the reference is null, it fails quickly
Optional.absent() Create the Optional instance with the missing reference
Optional.fromNullable(T) Creates an Optional instance of the specified reference. If the reference is null, it is missing

Using Optional instances

methods role
boolean isPresent() Returns true if Optional contains a non-null reference (the reference exists)
T get If return reference, Optional contains reference is missing, it throws the Java. Lang. An IllegalStateException
T or(T) Returns the reference contained in Optional, or the specified value if the reference is missing
T orNull() Returns the reference contained in Optional, or NULL if the reference is missing
Set asSet() Returns a singleton immutable set of Optional contained references, a single element set if the reference exists, or an empty set if the reference is missing.

2.Preconditions

Method declaration (without additional parameters) describe Check for exceptions thrown on failure
checkArgument(boolean) Checks whether Boolean is true to check the arguments passed to the method. IllegalArgumentException
checkNotNull(T) Check if value is null. This method returns value directly, so you can use checkNotNull inline. NullPointerException
checkState(boolean) Used to check some state of an object. IllegalStateException
checkElementIndex(int index, int size) Checks whether index is valid as an index value for a list, string, or array. index>=0 && index<size * IndexOutOfBoundsException
checkPositionIndex(int index, int size) Checks whether index is valid as a positional value for a list, string, or array. index>=0 && index<=size * IndexOutOfBoundsException
checkPositionIndexes(int start, int end, int size) Checks that the range of positions represented by [start, end] is valid for a list, string, or array * IndexOutOfBoundsException

3.Ordering

Create a collator

methods describe
natural() Do natural sorting for collatable types, such as number by size, date by order
usingToString() Do a Lexicographical ordering of objects as strings.
from(Comparator) Converts the given Comparator to a collator

Chain call method: With chain calls, other collators can be derived from a given collator

methods describe
reverse() Gets the semantically opposite collator.
nullsFirst() Use the current collator, but add the null value to the top.
nullsLast() Use the current collator, but add the null value to the bottom.
compound(Comparator) Synthesize another comparator to handle equality in the current collator.
lexicographical() Returns a collator for Iterable Iterable based on a collator that handles type T.
onResultOf(Function) Call Function on the elements in the collection and sort them by the return value using the current collator.

Using collators: Guava’s collator implements several methods for manipulating collections or element values

methods describe Please see the other
greatestOf(Iterable iterable, int k) Gets the largest k elements of an iterable. leastOf
isOrdered(Iterable) Determines whether an iterable is sorted by a collator: elements with equal collation values are allowed. isStrictlyOrdered
sortedCopy(Iterable) Determines whether an iterable has been sorted strictly by the collator: sorting elements of equal value is not allowed. immutableSortedCopy
min(E, E) Returns the smallest of the two arguments. If equal, the first argument is returned. max(E, E)
min(E, E, E, E…) Returns the smallest of multiple arguments. If more than one argument is minimum, the first smallest argument is returned. max(E, E, E, E…)
min(Iterable) Returns the smallest element in the iterator. If there are no elements in the iterable, NoSuchElementException is thrown. max(Iterable), min(Iterator), max(Iterator)

A collection of

1. Immutable sets

Associate mutable and immutable sets

Variable set interface JDK or Guava Immutable version
Collection JDK ImmutableCollection
List JDK ImmutableList
Set JDK ImmutableSet
SortedSet/NavigableSet JDK ImmutableSortedSet
Map JDK ImmutableMap
SortedMap JDK ImmutableSortedMap
Multiset Guava ImmutableMultiset
SortedMultiset Guava ImmutableSortedMultiset
Multimap Guava ImmutableMultimap
ListMultimap Guava ImmutableListMultimap
SetMultimap Guava ImmutableSetMultimap
BiMap Guava ImmutableBiMap
ClassToInstanceMap Guava ImmutableClassToInstanceMap
Table Guava ImmutableTable

Create a way

1.ImmutableSet.copyOf()

Set<String> sets = new HashSet<>();
sets.add("set obj1");
sets.add("set obj2");
ImmutableSet<String> immutableSet = ImmutableSet.copyOf(sets);
System.out.println(immutableSet.size());
Copy the code

2.ImmutableSet.of()

ImmutableSet<String> immutableSet2 = ImmutableSet.of("a", "b", "c", "a", "d", "a");
System.out.println(immutableSet2.size());

Copy the code

3.ImmutableSet.Builder()

ImmutableSet immutableSet1 = ImmutableSet.builder().add("ImmutableSet obj1").add("ImmutableSet obj2").build();
System.out.println(immutableSet1.size());
Copy the code

2. New collection types

Multiset

Like Set, you can add data repeatedly, but not sequentially

/* Multiset Multiset = hashmultiset.create (); multiset.add("a"); multiset.add("b"); multiset.add("c"); multiset.add("b"); multiset.add("a"); System.out.println("multiset size:"+multiset.size()); //multiset size:5Copy the code

Multimap

Mapping a key to multiple values.

Multimap<String,String> multimap = HashMultimap.create(); multimap.put("key1","key1 obj1"); multimap.put("key1","key1 obj2"); multimap.put("key1","key1 obj3"); Iterator<String> stringIterator = multimap.get("key1").iterator(); System.out.println("key values:"); while (stringIterator.hasNext()){ System.out.println(stringIterator.next()); } /* key values: key1 obj3 key1 obj2 key1 obj1 */ Map<String,Collection<String>> Map = multimap.asmap (); Iterator<String > stringIterator1 = map.get("key1").iterator(); System.out.println("map key values:"); while (stringIterator1.hasNext()){ System.out.println(stringIterator1.next()); } /* map key values: key1 obj3 key1 obj2 key1 obj1 */Copy the code

BiMap

Bidirectional mapping

BiMap<String, Integer> userIds = HashBiMap.create();
userIds.put("User1",1);
userIds.put("User2",2);
userIds.put("User3",3);
userIds.put("User4",4);
String userForId = userIds.inverse().get(2);
System.out.println(userForId);
Copy the code

Table

There are two keys that support all types: row and column.

HashBasedTable hashBasedTable = HashBasedTable.create();
hashBasedTable.put("row1","column1","row1+column1:value");
hashBasedTable.put("row1","column2","row1+column2:value");
hashBasedTable.put("row2","column1","row2+column1:value");
hashBasedTable.put("row3","column2","row2+column2:value");
Map<String,String> hashBasedTableRowMap = hashBasedTable.row("row1");
Iterator<String> iterator = hashBasedTableRowMap.keySet().iterator();
while (iterator.hasNext()){
    String column = iterator.next();
    String value = hashBasedTableRowMap.get(column);
    System.out.println("column:"+column + "  value:"+ value);
}
/*
column:column1  value:row1+column1:value
column:column2  value:row1+column2:value
*/
Copy the code

ClassToInstanceMap

Special Map: the key is the type and the value is the object that corresponds to the type indicated by the key.

ClassToInstanceMap<Number> numberDefaults= MutableClassToInstanceMap.create();
numberDefaults.putInstance(Integer.class, Integer.valueOf(0));
Copy the code

RangeSet

Represents a set of disconnected, non-empty intervals. The notion of intervals will be explained later.

RangeSet<Integer> rangeSet = TreeRangeSet.create(); rangeSet.add(Range.closed(1, 10)); / / {} [1, 10] System. Out. The println (rangeSet. AsRanges (), toString ()); rangeSet.add(Range.closedOpen(11, 15)); Println (rangeset.asRanges ().toString())); rangeset.add (range.closedOpen (15,)); {[1,10], [11,20]} system.out.println (rangeset.asranges ().tostring ()); rangeset.add (range.openclosed (0, {[1,10], [11,20)} system.out.println (rangeset.asranges ().tostring ()); rangeset.remove (range.open (5,)); 10)); / / split [1, 10]; {[1, 5], [10, 10], [11, 20)} System. Out. Println (rangeSet. AsRanges (), toString ()); / * * * rangeSet most basic operation, */ Boolean isContains = rangeset.contains (1); system.out.println ("isContains:"+isContains); /** * returns the interval containing the given element; if no such interval exists, */ Range<Integer> Range = rangeset.rangeconsavilion (1); system.out.println (" Range :"+ Range);Copy the code

3. Assemble utility classes

Iterables

methods describe note
concat(Iterable) Lazy views that concatenate multiple iterables concat(Iterable…)
frequency(Iterable, Object) Returns the number of occurrences of the object in iterable Compare with collections. frequency (Collection, Object); Multiset
partition(Iterable, int) If the iterable is partitioned by a specified size, the resulting subset cannot be modified Lists. Partition (List, int); paddedPartition(Iterable, int)
getFirst(Iterable, T default) Return the first element of iterable, or the default if iterable is empty Compare to iterable.iterator ().next (); FluentIterable.first()
getLast(Iterable) Returns the last element of iterable, or NoSuchElementException if iterable is empty Default getLast (Iterable, T); FluentIterable.last()
elementsEqual(Iterable, Iterable) Returns true if all elements in both iterable are equal and in the same order Compared with the List. The equals (Object)
unmodifiableIterable(Iterable) Returns an immutable view of iterable Compare with collections.unmodified ablecollection (Collection)
limit(Iterable, int) Limit the number of elements of iterable to limit a given value FluentIterable.limit(int)
getOnlyElement(Iterable) Gets a unique element in iterable, failing quickly if iterable is empty or has multiple elements getOnlyElement(Iterable, T default)
#### FluentIterable
Copy yourself into an immutable set
Type of conversion methods
ImmutableSet toImmutableSet()
ImmutableSortedSet toImmutableSortedSet(Comparator)

######Lists, Sets, Maps, Multisets, Multimaps, Tables all have their own static class methods

The cache

The basic use

LoadingCache<String, String> stringStringLoadingCache = CacheBuilder.newBuilder().build(new CacheLoader<String, String>() {
    @Override
    public String load(String key) throws Exception {
        if(key.equals("key2")){
            System.out.println("load key2");
            return "values2";
        }
        System.out.println("load else");
        return "values0";
    }
    public Map<String, String> loadAll(Iterable<? extends String> keys) throws Exception {
        System.out.println("loadAll:"+keys.toString());
        Map<String,String> loadAll = new HashMap<String, String>();
        Iterator keysIt = keys.iterator();
        while (keysIt.hasNext()){
            String key = (String) keysIt.next();
            loadAll.put(key,key+":::values");
        }
        return loadAll;
    }


});
stringStringLoadingCache.put("key1","value1");
String values1 = stringStringLoadingCache.getUnchecked("key1");
System.out.println(values1);
String values2 = stringStringLoadingCache.getUnchecked("key2");
System.out.println(values2);
String values3 = stringStringLoadingCache.getUnchecked("key3");
System.out.println(values3);
String values11 = stringStringLoadingCache.getUnchecked("key1");
System.out.println(values11);
Set<String> keySet = Sets.newSet("key4");
try {
    ImmutableMap<String, String> immutableMap = stringStringLoadingCache.getAll(keySet);
    System.out.println(immutableMap.toString());
} catch (ExecutionException e) {
    e.printStackTrace();
}
/*
value1
load key2
values2
load else
values0
value1
loadAll:[key4]
{key4=key4:::values}
 */
Copy the code

1. Create CacheLoader and simply implement V load(K key). 2. Get the element using get() or getUnchecked(). 3. GetAll () calls the loadAll() method to increase efficiency. 4. Put () Displays inserted data. ###### Cache Reclaiming

  • Volume-based recycling

CacheBuilder. MaximumSize (long) : create limit CacheBuilder. MaximumWeight (long) : create a weight limit CacheBuilder. Weigher (weigher) : create a weighting function

  • Timing recovery

ExpireAfterAccess (long, TimeUnit) : Reclaims cache entries that have not been read/written within a given time. Note that this cache is recycled in the same order as a size-based collection. ExpireAfterWrite (long, TimeUnit) : The cache item is reclaimed if it has not been write accessed (created or overwritten) within a given time. This is desirable if you think that cached data always becomes stale and unusable after a fixed time.

  • Reference-based collection

Cachebuilder.weakkeys () : Uses weak reference storage keys. Cached entries can be garbage collected when there are no other (strong or soft) references to the key. Because garbage collection relies only on the identity (==), caches that use weak reference keys compare the equals key instead of the == key. Cachebuilder.weakvalues () : Uses weak references to store values. Cached items can be garbage collected when there are no other (strong or soft) references to the value. Because garbage collection relies only on the identity (==), caches that use weak reference values compare values with == instead of equals. Cachebuilder.softvalues () : Stores values using soft references. Soft references are recycled in the order of least recently used globally only in response to memory needs. Given the performance impact of using soft references, we generally recommend using cache size limits that are more predictive of performance (see above, based on capacity reclamation). Caches that use soft-reference values also compare values with == instead of equals.

  • Explicitly clear

Cache.invalidate(key) : clears individual entries. Cache.invalidateAll(keys) : Deletes data in batches. Cache.invalidateall () : clears all Cache entries.

  • Removing listeners

CacheBuilder. RemovalListener (removalListener) : remove listening in.

  • The refresh

Loadingcache.refresh (K) : Refresh means to load a new value for the key. Cacheloader.reload (K, V)] : recalculates on reload. CacheBuilder. RefreshAfterWrite (long, TimeUnit) : time refresh function.

###### Statistics cacheBuilder.recordStats () : Enables statistics. Cache.stats() : Returns CacheStats statistics. Cachestats.hitrate () : cache hit ratio; CacheStats. AverageLoadPenalty () : loading a new value, the average time unit for ns; Cachestats.evictioncount () : Total number of cache entries reclaimed, excluding explicit cleanup

String handling

The connector

Joiner joiner = Joiner.on(":").skipNulls();
String string = joiner.join("AAA", null, "BBB", "CCC");
String string0 = joiner.join(Arrays.asList("DDD", "EEEE"));
System.out.println(string);
System.out.println(string0);
Copy the code

splitter

Iterable<String> stringSet= Splitter.on(',')
        //.limit(3)
        .omitEmptyStrings()
        .trimResults()
        .split("a,b,,c,d,e,f");
Iterator<String> iterator = stringSet.iterator();
while (iterator.hasNext()){
    System.out.println(iterator.next());
}
Copy the code
  • Break up the factory
methods describe sample
Splitter.on(char) Split by single character Splitter. On (‘; ‘)
Splitter.on(CharMatcher) Split by character matcher Splitter.on(CharMatcher.BREAKING_WHITESPACE)
Splitter.on(String) Split by string Splitter. On (“, “)
Splitter.on(Pattern)

Splitter.onPattern(String)
Split by regular expression Splitter. OnPattern (” \ “r”? \ n “).
Splitter.fixedLength(int) Split according to fixed length; The last paragraph may be shorter than a given length, but will not be empty. Splitter.fixedLength(3)
  • Split to modify
methods describe
omitEmptyStrings() Empty strings are automatically ignored from the result
trimResults() Removes leading and trailing whitespace from the resulting string
trimResults(CharMatcher) Given a matcher, remove leading and trailing matching characters from the result string
limit(int) Limit the number of split strings

## Native type handling

  • A utility class corresponding to a primitive type
Primitive types Guava tools
byte Bytes, SignedBytes, UnsignedBytes
short Shorts
int Ints, UnsignedInteger, UnsignedInts
long Longs, UnsignedLong, UnsignedLongs
float Floats
double Doubles
char Chars
boolean Booleans
  • Native array tools
The method signature describe A similar approach availability
The List asList (prim… backingArray) Turn the array into a List of the corresponding wrapper classes Arrays.asList Sign independent
prim[] toArray(Collection collection) Copy collections as arrays, as thread-safe as collection.toarray () Collection.toArray() Symbol has nothing to do
Prim [] concat (prim []… arrays) Concatenate multiple arrays of primitive types Iterables.concat Symbol has nothing to do
boolean contains(prim[] array, prim target) Determines whether an array of primitive types contains the given value Collection.contains Symbol has nothing to do
int indexOf(prim[] array, prim target) The index of the first occurrence of a given value in the array, or -1 if the value is not included List.indexOf Symbol has nothing to do
int lastIndexOf(prim[] array, prim target) The index at the end of the array for a given value, or -1 if it is not included List.lastIndexOf Symbol has nothing to do
The prim min (prim… array) The smallest value in the array Collections.min Symbolic correlation
Prim Max (prim… array) The largest value in the array Collections.max Symbols related
String the join (String separator, prim… array) Concatenate an array into a string using the given delimiter Joiner.on(separator).join Symbols related
Comparator<prim[]> lexicographicalComparator() Compares the comparators of native arrays in lexicographical order Ordering.natural().lexicographical() Symbols related
` ` ` `
Int [] ints = {1, 2, 3};
8,9,0 int [] ints0 = {};

List integerList = Ints.asList(ints); for (Integer integerListItem:integerList){ System.out.println(integerListItem); } //123 System.out.println(“================”);

int[] ints1 = Ints.toArray(integerList); for (int i :ints1){ System.out.println(i); } //123 System.out.println(“================”);

int[] ints2 = Ints.concat(ints,ints0); for (int i :ints2){ System.out.println(i); } //123890 System.out.println(“================”);

boolean isContains = Ints.contains(ints,2); System.out.println(isContains); //true System.out.println(“================”);

int index = Ints.indexOf(ints,0); System.out.println(index); //-1 System.out.println(“================”);

int index1 = Ints.indexOf(ints,1); System.out.println(index1); //0 System.out.println(“================”);

int max = Ints.max(ints2); System.out.println(max); //9 System.out.println(“================”);

int min = Ints.min(ints2); System.out.println(min); //1 System.out.println(“================”);

String string = Ints.join(“;” ,ints); System.out.println(string); / / 1. 2; 3 System.out.println(“================”);

Int c = Ints. ConstrainToRange (- 3,0,9); System.out.println(c); //0 System.out.println(“================”);

# # # # # # interval static method of build - from class Range build | interval description method of | | | -- - | -- - | | (a.. b) |open(C, C)| |[a..b] |closed(C, C)| |[a..b) |closedOpen(C, C)| |(a..b] |openClosed(C, C)| |(a.. + up) | greaterThan (C) | | | [a.. + up) atLeast (C) | | | (- up.. b) lessThan (C) | | | (- up.. b] atMost (C) | | (- up.. | | + up) all () - use explicitly specified boundary type structure | interval description method of | | | -- - | -- - | | | bounded interval range (C, BoundType, C, BoundType) | | no upper range: ((a.. + up) or [a. + up)) | downTo (C, BoundType) | | no lower interval: ((- up.. b) or (- up.. b]) | upTo (C, BoundType) | > BoundType types: BoundType. CLOSED or BoundType. OPEN # # # # special description - [a.. a] : Single-element intervals - [a.. A); (a.. A] : empty intervals, but they are valid - (a.. A) : Invalid interval #### interval operationCopy the code

The Range range0 = Range. ClosedOpen (0, 4); //[0,4) Range range1 = range.openclosed (3,5);//(3,5) system.out.println (range0.tostring ())); //[0..4) System.out.println(range1.toString()); //(3..5]

/ * *

  • Check whether the interval is empty

*/ boolean isEmpty = range0.isEmpty(); System.out.println(“isEmpty:”+isEmpty); //isEmpty:false

/ * *

  • Determine if there is an upper limit

*/ boolean hasLowerBound = range0.hasLowerBound(); boolean hasUpperBound = range0.hasUpperBound(); System.out.println(“hasLowerBound:”+hasLowerBound +” hasUpperBound:”+hasUpperBound); //hasLowerBound:true hasUpperBound:true

/ * *

  • Returns the interval boundary type, CLOSED or OPEN; Throw an IllegalStateException if the range has no corresponding boundary.

*/ BoundType lowerBoundType = range0.lowerBoundType(); BoundType upperBoundType = range0.upperBoundType(); System.out.println(“hasLowerBound:”+hasLowerBound +” hasUpperBound:”+hasUpperBound); //hasLowerBound:true hasUpperBound:true

/ * *

  • Returns the endpoint value of the interval

*/ Comparable lowerEndpoint = range0.lowerEndpoint(); Comparable upperEndpoint = range0.upperEndpoint(); System.out.println(“lowerEndpoint:”+lowerEndpoint +” upperEndpoint:”+upperEndpoint); //lowerEndpoint:0 upperEndpoint:4

/ * *

  • Inclusion relationships between intervals

*/ boolean encloses = range0.encloses(range1); System.out.println(“encloses:”+encloses); //encloses:false

/ * *

  • Determine whether the interval is connected

*/ boolean isConnected = range0.isConnected(range1); System.out.println(“isConnected:”+isConnected); //isConnected:true

/ * *

  • Intersection: the maximum interval contained both in the first interval and in another interval

*/ Range range2 = range0.intersection(range1); System.out.println(“intersection:”+range2.toString()); //intersection:(3.. 4)

/ * *

  • Interzone: The smallest zone containing two zones at the same time

*/ Range rang3 = range0.span(range1); System.out.println(“span:”+rang3.toString()); //span:[0..5]

# # # # discrete domainCopy the code

ImmutableSortedSet set = ContiguousSet.create(range0, DiscreteDomain.integers()); Iterator iterator = set.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } //0 1 2 3

# # # # hash event bus [EventBus events publish/subscribe lightweight framework] mathematical operations (https://github.com/greenrobot/EventBus) # # # # # # # # check arithmetic overflow Mainly aimed at the three integer arithmetic, int, Long and BigInteger.Copy the code

Int i0 = integer. MAX_VALUE + 2; System.out.println(i0); / * * throws an exception here, Java. Lang. ArithmeticException: overflow * / int i1. = IntMath checkedAdd (Integer. MAX_VALUE, 2);

} catch (Exception e) { e.printStackTrace(); }

IntMath and LongMath have corresponding methods -checkedAdd () : add detection -CheckedSubstract () : divide detection -checkedmultiply () : multiply detection -checkedPow () : RoundingMode: DOWN: rounds to zero. UP: rounds to zero. -floor: round to zero. Rounding to negative infinity CEILING: rounding to positive infinity - UNNECESSARY: No rounding required, if using this mode to round, throw ArithmeticException - HALF_UP: Round to the nearest integer, where x.5 is rounded away from zero. -half_down: Rounds to the nearest integer, where x.5 is rounded to zero. Round to the nearest integer, where x.5 rounds to the adjacent even integer (IntMath as an example) - divide(int, int,RoundingMode) : divide -log2 (int,RoundingMode) : Log base 2 -log10 (int,RoundingMode) : log base 10 -sqrt (int,RoundingMode) : square root -gcd (int,int) : maximum common dimer -mod (int,int) : Factorial - pow(int,int) : power - isPowerOfTwo(int) : whether it is a power of 2 - factorial(int) : factorial - binomial(int,int) : #### mathematicalinteger (double) : find out if this float is an integer - roundToInt(double, RoundingMode) : roundToInt; - roundToLong(double, RoundingMode) : roundToLong; - roundToBigInteger(double, RoundingMode) : rounds to BigInteger; Raise exception for infinite decimals - log2(double, RoundingMode) : Floating point logarithm of 2, rounded to int, Faster than the JDK math.log (double) ## concurrency temp ## reflection temp ## I/O temp ## hash temp ## graphics temp ## project address [https://github.com/iamludaxu/ae/tree/master/app/src/test/java/gift/witch/android/ae/guava](https://github.com/iamludaxu / ae/tree/master/app/SRC/test/Java/gift/witch/android/ae/guava) # # reference [Google Guava official tutorial (in Chinese)] (http://ifeve.com/google-guava/) [Guava User Guide] (https://github.com/google/guava) < br > - call me Lu Daxu # #. A boring programmer who knows something about psychology. Tip, follow and like the article whether or not you get anything from it!Copy the code