[ Class Hierarchy | Latest Javadoc ]
open questions: why there isn't a checked function?
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())
.result();
}
- ordering
- factories:
natural()
, usingToString()
, and arbitrary()
.
- configurations:
reverse()
, nullsFirst()
, nullsLast()
, compound(comparator)
, lexicographical()
, and onResultOf(function)
.
- applications:
greatestOf(iterable, k)
, leastOf(iterable, k)
, isOrdered
, softCopy
, min(E, E...)
, and max(E, E...)
.
Ordering<String> byLength = new Ordering<String>() {
public int compare(String lhs, String rhs) {
return Ints.compare(lhs.length(), rhs.length());
}
};
- throwables
propagate(throwable)
;
propagateIfInstanceOf(throwable, class<e extends Exception>)
;
propagateIfPossible(throwable, class<e extends Throwable>)
;
-
immutable collections --- as defensive copies, easy-to-use, thread-safe, time & space savings w/o overhead of concurrent modification checks and extra space past capacity.
- immutableSet.copyOf(set), immutableMap.of("a", 1, "b", 2), ImmutableSet.builder().addAll(iterable).add(element).build().
- Multiset to count the number of occurrences of an element; alternatively,
Map<Key, Integer>
.
- Multimap to keep a set as a value. cf. a traditional way to represent a graph:
Map<V, Set<V>>
.
- ListMultimap to keep an ordered list of values associated with a key.
- SetMultimap to keep an unordered set of values associated with a key.
-
bi-map guarantees values are unique, allowing you to view the inverse BiMap<V, K>
with inverse()
.
-
table
rowMap()
views a Table<R, C, V>
as a Map<R, Map<C,V>>
while columnMap()
views it as a Map<C, Map<R,V>>
.
rowKeySet()
returns a Set<R>
, while columnKeySet()
returns a Set<C>
.
row(r)
returns a non-null Map<C, V>
, while column(c)
returns a non-null Map<R, V>>
.
cellSet()
returns a set of Table.Cell<R, C, V>
.
-
ClassToInstanceMap, alternatively, a Map<Class, Object>
.
- methods:
T getInstance(Class<T>)
and T putInstance(Class<T>, T)
;
-
factory methods for collection types
- for JDK collection types w/ raw constructors, factories can be found in Lists, Sets, Maps, and Queues.
- Guava collection types hides raw constructors, but rather exposes factory methods, e.g.
HashMultiset.create()
.
-
Lists.partition returns consecutive sublists of the same size except the last one, that are unmodifiable live views. Lists.reverse returns a modifiable, write-through view.
-
Sets
cartesianProduct(set...)
, newSetFromMap(map)
, and powerSet(set)
newSetFromMap(Maps.newConcurrentHashMap())
builds a thread-safe set.
difference(s1, s2)
, symmetricDifference(s1, s2)
, intersection(s1, s2)
, and union(s1, s2)
-
Maps has uniqueIndex()
, difference()
, and unmodifiableBiMap()
.
-
Iterables has concat()
, addAll()
, elementsEqual()
, getOnlyElement()
, and cycle()
.
- cache
- applicability --- when a value is expensive to compute or retrieve, and automated population and eviction of values is desirable.
- population by a cache loader when there is a sensible default function to load a value associated with a key, by a callable, or directly into a map.
- cacheBuilder.build(
new CacheLoader
<Key, Graph>() { load(Key key); loadAll(Iterable keys); });
- cache.
refresh
(key); // old value is returned while being asynchronously refreshed.
- cache.get(key,
new Callable
() { public Graph load(Key key); }
- cache.
asMap
().put
(key, graph);
- eviction
- cacheBuilder.
removalListener
(notifiableOfCauseKeyAndValueOnRemoval);
- timed:
expireAfterAccess
(duration), expireAfterWrite
(duration), refreshAfterWrite
(duration).
- max size to evict entries that haven't been used recently or very often.
- weightier when values have radically different memory footprints.
- tweaks on GC:
weakKeys
to store keys using weak references and softValues
to wrap values in soft references.
invalidate(key)
, invalidateAll(keys)
, and invalidateAll()
.
- statistics can help significantly in tuning with hit rate, average loading time, and eviction count.
- functions and predicates
- trade-offs between traditional imperative way vs. preposterously awkward functional style.
- net savings of lines of code, and lazily computed views in constant time.
- special predicates:
CharMatcher.forPredicate(predicateOfCharacter)
, Range.atMost(2)
as Predicate<Integer>
, and the like.
- function factories:
forMap()
, compose()
, constant()
, identity()
, and toStringFunction()
.
- predicate factories:
instanceOf
, assignableFrom
, isNull
, alwaysFalse
, alwaysTrue
, contains
, in
, equalTo
, compose
, and
, or
, and not
.
- filtering and manipulating collections & iterables.
Multimaps.index(employees, jobCategoryOf)
; // returns an immutable map keyed by job categories.
Maps.uniqueIndex(employees, employeeIdOf)
; // returns an immutable multi-map keyed by employee ids.
- strings
- Joiner instances are always immutable, and configuration methods return new joiners, that are thread-safe, and fit for
static final
constants.
Joiner.on("; ").skipNulls().join("Harry", null, "Ron", "Hermione"); // or, useForNull("null");
- Splitter.split returns an iterable of strings under complete control, and is set to work on any pattern, char, string, or char-matcher.
Splitter.on(',').trimResults().omitEmptyStrings().split("foo,bar,, qux");
- CharMatcher has static finals for most needs, and can be commonly obtained by
anyOf()
, is()
, inRange()
, negate()
, and()
, and or()
.
collapseFrom
, matchesAllOf
, removeFrom
, retainFrom
, trimFrom
, and replaceFrom
.
- primitives
- array & general utilities, byte conversion methods such as from & toByteArray, and unsigned support w/ parseUnsigned, valueOf, and toString.
-
ranges
- basics:
contains()
, containsAll()
, lowerEndPoint()
, upperEndPoint()
, and isEmpty()
.
- relations:
encloses()
, isConnected()
, intersection()
, and span()
.
asSet()
makes equal views of sets for ranges [2..4] and (1..5).
canonical()
makes equal views of ranges when their sets are equal.
-
discret domains
- non-static:
distance()
, maxValue()
, minValue()
, next()
and previous()
.
- hashing
- Object#hashCode tends to be very fast w/ weak collision prevention, but suitable for use in hash tables w/ a light performance hit on collisions. Beyond simple hash tables, there are many uses of hash functions, e.g. a bloom filter.
HashFunction hf = Hashing.md5();
HashCode hc = hf.newHasher()
.putLong(id)
.putString(name)
.putPerson(person, personFunnel)
.hash();
new Funnel<Person>() {
@Override
void funnel(Person person, Sink into) {
into
.putInt(person.id)
.putString(person.firstName)
.putString(person.lastName)
.putInt(birthYear);
}
};
- math: exhaustive overflow checks, optimized with benchmarks, and designed to be readable.
- service
AbstractIdleService
tends to have startUp(), and shutDown() methods extended while we do not need to perform any action in the "running" state.
AbstractExecutionThreadService
calls startUp(), invokes run() on a new thread, and calls triggerShutdown() and waits for the thread to die.
AbstractScheduledService
performs some periodic action by fixed rate, or delay schedule, or a custom scheduler.
protected void startUp() {
dispatcher.listenForConnections(port, queue);
}
protected void run() {
Connection connection;
while ((connection = queue.take() != POISON)) {
process(connection);
}
}
protected void triggerShutdown() {
dispatcher.stopListeningForConnections(queue);
queue.put(POISON);
}
class CrawlingService extends AbstractScheduledService {
private Set<Uri> visited;
private Queue<Uri> toCrawl;
protected void runOneIteration() throws Exception {
Uri uri = toCrawl.remove();
Collection<Uri> newUris = crawl(uri);
visited.add(uri);
for (Uri newUri : newUris) {
if (!visited.contains(newUri)) { toCrawl.add(newUri); }
}
}
protected Scheduler scheduler() {
return Scheduler.newFixedRateSchedule(0, 1, TimeUnit.SECONDS);
}
protected void startUp() throws Exception {
toCrawl = readStartingUris();
}
protected void shutDown() throws Exception {
saveUris(toCrawl);
}
}
- monitor is designed to provide a synchronization abstraction that supports waiting on arbitrary boolean conditions.
public class SafeBox<V> {
private final Monitor monitor = new Monitor();
private final Monitor.Guard valuePresent = new Monitor.Guard(monitor) {
public boolean isSatisfied() {
return value != null;
}
};
private final Monitor.Guard valueAbsent = new Monitor.Guard(monitor) {
public boolean isSatisfied() {
return value == null;
}
};
private V value;
public V get() throws InterruptedException {
monitor.enterWhen(valuePresent);
try {
V result = value;
value = null;
return result;
} finally {
monitor.leave();
}
}
public void set(V newValue) throws InterruptedException {
monitor.enterWhen(valueAbsent);
try {
value = newValue;
} finally {
monitor.leave();
}
}
}
- event bus - request-scoped, or at global scope
- traditional listener interface has a number of disadvantages as follows:
- one class can only implement a single response to a given event.
- listener interface method may conflict, and can't be named after its purpose.
- each event usually requires its own interface even for a family of events.
// typically subscribed by a container class.
class EventBusChangeRecorder {
@Subscribe void recordChangeInCustomer(ChangeEvent e) {
recordChange(e.getChange());
}
}
// typically registered on start-up, or lazy initialization.
eventBus.register(new EventBusChangeRecorder());
// posted much later.
public void changeCustomer() {
ChangeEvent event = getChangeEvent();
eventBus.post(event);
}
Juggling as a metaphor for software development --- different roles in the software development process juggle different "trinities"; project and program Managers juggle Features, Resources and Time, and software developers juggle correctness, performance and security.