Upload
igor-anishchenko
View
5.623
Download
2
Tags:
Embed Size (px)
DESCRIPTION
The Guava project contains several of Google’s core libraries that we rely on in our Java-based projects: collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, and so forth. There will be the slides presenting most useful and interesting features of Guava (v.12) that makes stuff simpler, better and code cleaner. We will cover most of the com.google.common.base.* classes and basic use of functions in collection and Google collections and few other features that are part of Guava and I find them very useful. Some of you will think that there is an overlap with Apache commons – and it’s true, but Guava is built with expectation that there is a Function and a Predicate class as well as various builders which makes it really cool and simple for many use cases.
Citation preview
Guava is…
What is Google Guava?
annotations
basic utilities
collections
concurrency
comparison
strings
primitives
ranges
functional idioms
I/o
caching
hashing
event bus
math
reflection
net/http
What in this presentation?
annotations
basic utilities
collections
concurrency
comparison
strings
primitives
ranges
functional idioms
I/O
caching
hashing
event bus
math
reflection
net/http
Why Guava? The goal is for you to write less code ...
Make code more readable, cleaner and simpler
Helps developers to focus on business logic rather than writing java utilities
Saves time, resources and improve productivity
Popular API and active development
Mainstream
Basically... a painkiller and natural extension for Java
I Could've Invented That
ref. Effective Java
Item 47, "Know and use the libraries“
Guava Releases About every 3 months, with significant new
functionality and fixes
Release 14.0.1 was released on March 15, 2013
All releases are either major or patch releases
Never minor
Let’s get some Guava!
@annotations
Guava Basic Utilities
String Utilities Preconditions
Objects Helper
Avoiding Nulls
StopWatch
String Utilities
Joiner
Splitter
CharMatcher
Joining Strings Who here has ever written this utility?
public class StringUtil { public static String join( String separator, Iterable<String> pieces) { // any of ~5 common implementations goes here } }
Joining Strings Converts collections into single String object
Joining an Iterable, Iterator, varargs/array
Return a String, or append to an Appendable
Throws a NPE on null objects, unless:
.skipNulls()
.useForNull(String)
It also works with Maps
We could be looking at 18 to 48 different methods
Joining Strings (cont.)
List<String> fruits = Arrays.asList( "apple", null, "orange", null, null, "guava"); String joined = Joiner.on(", ").skipNulls().join(fruits); >> "apple, orange, guava"
Joining Strings (cont.)
List<String> fruits = Arrays.asList( "apple", null, "orange", null, null, "guava"); String joined = Joiner.on(", ").skipNulls().join(fruits); >> "apple, orange, guava" String joined = Joiner.on(",").useForNull("banana").join(fruits); >> "apple, banana, orange, banana, banana, guava"
Splitting Strings Working in the opposite direction than Joiner
Allows to split String into collection of elements
String.split() on steroids
A better, more intuitive String.split()
Doesn't silently discard trailing separators
Handles empty pieces predictably
Splitter
String input = ",, ,apple, orange ,,, banana,, ,guava, ,,"; Iterable<String> split = Splitter.on(',') .omitEmptyStrings() .trimResults() .split(input);
>> [ "apple", "orange", "banana", "guava" ]
The default behavior is simplistic
If you want extra features, ask for them!
Splitter
String input = ",, ,apple, orange ,,, banana,, ,guava, ,,"; Iterable<String> split = Splitter.on(',') .omitEmptyStrings() .trimResults() .split(input);
>> [ "apple", "orange", "banana", "guava" ]
The default behavior is simplistic
If you want extra features, ask for them!
By default, assumes nothing about whitespace
These classes use what Googlers (tentatively) call the "Utility Object pattern."
Splitter more…
Splitter.onPattern("\\d+").split("Java3Scala4Haskell0Brainfuck5Kotlin"); >> [ "Java ", "Scala", "Haskell", "Brainfuck", "Kotlin" ] Splitter.on(CharMatcher.inRange('3','5')) .split("Java3Scala4Haskell0Brainfuck5Kotlin"); >> [ "Java", "Scala", "Haskell0Brainfuck", "Kotlin" ]
Split using regular expression
Split using CharMatcher
CharMatcher CharMatcher provides many text processing
methods based on “matching character” notation
Separates "configuration" from "processing"
CharMatcher represents two notions:
What constitutes a matching character?
What to do with those matching characters?
Can also be used to "filter" chars
CharMatcher (cont.) Allows to check if a sequence of characters satisfies
given condition:
WHITESPACE, ASCII, ANY, DIGIT (many pre-defined sets)
is('x')
isNot('_')
oneOf("aeiou")
inRange('a', 'z') .or (inRange('A', 'Z')).negate()
All that you can do... CharMatcher
Provides methods to modify char sequences:
boolean matchesAllOf(CharSequence)
boolean matchesAnyOf(CharSequence)
boolean matchesNoneOf(CharSequence)
int indexIn(CharSequence, int)
int lastIndexIn(CharSequence, int)
int countIn(CharSequence)
String removeFrom(CharSequence)
String retainFrom(CharSequence)
String trimFrom(CharSequence)
String trimLeadingFrom(CharSequence)
String trimTrailingFrom(CharSequence)
String collapseFrom(CharSequence, char)
String trimAndCollapseFrom(CharSequence, char)
String replaceFrom(CharSequence, char)
CharMatcher (example)
CharMatcher matcher = CharMatcher.DIGIT .or(CharMatcher.inRange('a', 'z') .or(CharMatcher.inRange('A', 'Z'))); if (matcher.matchesAllOf("this1will2match3")) { // ... }
CharMatcher (example)
// eliminate all characters that aren't digits or lowercase String lowerAndDigit = CharMatcher.DIGIT .or(CharMatcher.JAVA_LOWER_CASE) .retainFrom(input);
CharMatcher matcher = CharMatcher.DIGIT .or(CharMatcher.inRange('a', 'z') .or(CharMatcher.inRange('A', 'Z'))); if (matcher.matchesAllOf("this1will2match3")) { // ... }
CharMatcher (example)
String pass = “$$$ secret passcode $$$"; String result = CharMatcher.is(“$”).trimFrom(pass); >> “ secret password "
trimLeadingFrom(), trimTrailingFrom() or trimAndCollapseFrom()
Guava Basic Utilities String Utilities
Preconditions Objects Helper
Avoiding Nulls
StopWatch
checkState(boolean)
Throws IllegalStateException if false
Used to check object state
if (state != State.PLAYABLE) { throw new IllegalStateException( "Can't play movie; state is " + state); }
checkState(boolean)
Throws IllegalStateException if false
Used to check object state
… or…
if (state != State.PLAYABLE) { throw new IllegalStateException( "Can't play movie; state is " + state); }
Preconditions.checkState(state == State.PLAYABLE, "Can't play movie; state is %s", state);
(what's the difference? none!)
checkNotNull(T) Throws NullPointerException if null
Returns the value. Can be used inline.
public Car(Engine engine) { this.engine = Preconditions.checkNotNull(engine); }
checkNotNull(T) Throws NullPointerException if null
Returns the value. Can be used inline.
. . . with using static import . . .
public Car(Engine engine) { this.engine = Preconditions.checkNotNull(engine); }
public Car(Engine engine) { this.engine = checkNotNull(engine, “engine cannot be null”); }
checkArgument(boolean) Throws IllegalArgumentException if false
Used to validate method arguments
public void drive(double speed) { Preconditions.checkArgument(speed > 0.0, "Speed (%s) must be positive", speed); }
Why Preconditions?
Defensive coding
Useful for validation
Each method has three variants: No extra arguments
An extra object for error message
An extra String & Objects. String.format like but only allows %s
Recommended to be used as static imports
Guava Basic Utilities String Utilities
Preconditions
Objects Helper Avoiding Nulls
StopWatch
Object common methods
Objects.equal(Object, Object)
Objects.hashCode(Object...)
Objects.toStringHelper(Object)
Objects.firstNonNull(T, T)
equal(…) & hashCode(…)
public class Person { private final String name, nickname; private final Movie favoriteMovie;
@Override public boolean equals(Object object) { if (object instanceof Person) { Person that = (Person) object; return Objects.equal(this.name, that.name) && Objects.equal(this.nickname, that.nickname) && Objects.equal(this.favoriteMovie, that.favoriteMovie); } return false; }
@Override public int hashCode() { return Objects.hashCode(name, nickname, favoriteMovie);
}
toStringHelper(…) & firstNonNull(T, T)
@Override public String toString() { // speakers is @Nullable! return Objects.toStringHelper(this) .add("conference", name) .add(“location", location) .add("speakers", speakers) .omitNullValues().toString(); } >> "Person{name=JeeConf, location=Kiev}“ // w/o omitNullValues() >> "Person{name=JeeConf, location=Kiev, speakers=null}“
public String preferredLocation() { return Objects.firstNonNull(location, name); }
Guava Basic Utilities String Utilities
Preconditions
Objects Helper
Avoiding Nulls StopWatch
Null is ambiguous
if (x != null && x.someM() != null && ..) { // some code… }
Problem with Null
No entry? Or entry exists but the nickname is unlisted?
Person person = personService.findByNickname(“Andy"); if (person == null) { // what does this mean? }
Problem with Null
No entry? Or entry exists but the nickname is unlisted? The value in the map is null, or the value is not in the map. Null can mean failure, can mean success, can mean almost anything.
Person person = personService.findByNickname(“Andy"); if (person == null) { // what does this mean? }
Map.get(key)
Optional<T> vs. null null is "hidden", Optional is ”explicit” An immutable wrapper that is either:
present: contains a non-null reference absent: contains nothing Note that it never "contains null"
Possible uses: return type
“a T that must be present" "a T that might be absent"
distinguish between "unknown" (for example, not present in a map) "known to have no value" (present in the map, with value
Optional.absent())
wrap nullable references for storage in a collection that does not support null
Optional<T>
// Make optional of given type Optional<String> possible = Optional.of(“Ido”); Optional<String> value = Optional.fromNullable(str); if (value.isPresent()) { // ... } // returns true if nonNull possible.isPresent(); // returns this possible value or default possible.or(“Nick”); // returns Ido possible.get();
Making an Optional Optional.of(T) - make optional of given non-null
value or fail fast on null
Optional.absent() - return an absent optional of some type
Optional.fromNullable(T) - turn value in Optional and treat null as absent
For null-unfriendly collections Many collections, including the JDK's Queue and ConcurrentMap implementations, don't allow null elements.
Queue<Optional<Foo>> is a simple and natural solution!
Others… Strings Methods are primarily for interfacing with
unpleasant APIs that equate null strings and empty strings:
Strings.emptyToNull(String)
Strings.isNullOrEmpty(String)
Strings.nullToEmpty(String)
https://code.google.com/p/guava-libraries/wiki/UsingAndAvoidingNullExplained
Guava Basic Utilities String Utilities
Preconditions
Objects Helper
Avoiding Nulls
StopWatch
StopWatch Class for measuring elapsed time
Prefer StopWatch over System.nanoTime()
Don't use System.currentTimeMillis()!
Provides methods that automatically calculate time between start() and stop() execution
StopWatch
public void measureElapsedTime(Collection<String> input) { Stopwatch stopwatch = new Stopwatch().start(); doSomeOperation(input); long nanos = stopwatch.elapsed(TimeUnit.NANOSECONDS); }
StopWatch Pros StopWatch uses nanoTime() but exposes only relative
timings, a meaningless absolute value
Alternate time sources can be substituted using Ticker (read() returns nanoseconds)
Can be easily mocked with custom passing time provider
Returns counted time using different units
toString() gives human readable format
Functional Concepts brought to Java
Many things in Guava are inspired by functional concepts from other programming languages
In Java can only be approximated through awkward and verbose use of anonymous classes
Expected to change in Java 8
Guava is currently aimed at users of Java 5 and above
Core concepts Key functional concepts Guava uses:
Core concepts Key functional concepts Guava uses:
Function<F, T> == F => T
=> to transform a collection
public interface Function<F, T> { @Nullable T apply(@Nullable F input); }
Core concepts Key functional concepts Guava uses:
Function<F, T> == F => T
=> to transform a collection
Predicate<T> == T => Boolean
=> filter out a collection
public interface Function<F, T> { @Nullable T apply(@Nullable F input); }
public interface Predicate<T> { boolean apply(@Nullable T input); }
Function<F,T> usage
Iterables.transform()
FluentIterable.transform()
Iterators.transform()
Collections2.transform()
Lists.transform()
Maps, Multimaps … etc.
Main usage with transform()
Tools to manipulate collections using Function:
FluentIterable API Chaining methods (return FluentIterable<T>)
filter(Predicate)
transform(Function)
skip(int), limit(int)
cycle()
Query methods (return boolean) allMatch(Predicate), anyMatch(Predicate)
contains(Object)
isEmpty()
Extraction methods (return Optional<T>) first(), last(), firstMatch(Predicate), get(int)
Conversion methods (return a copied Collection<T>) toList(), toSet(), toSortedSet(), toArray()
Function <F,T>
Java 7 doesn't have lambda expressions, but Guava helps us out (a bit) with Function
public void demo(Collection<String> input) { Function<String, String> toUpperCase = new Function<String, String>() {
@Override public String apply(String string) { return string.toUpperCase(); } };
Collection<String> transformed = Collections2.transform(input, toUpperCase); }
Predicate<T> usage
Predicate checks if condition is met for passed object
Tools to manipulate collections using Predicate:
FluentIterables.filter()
Iterables.filter()
Iterators.filter()
Collections2.filter()
Sets.filter()
Maps, MultiMaps, … etc.
Predicate <T> Quite similar to Function but does NOT extend it
Predicate<User> onlyAwesome = new Predicate<User>() { @Override public boolean apply(User in) { return Optional.fromNullable(in) .or(User.NOT_AWESOME).isAwesome(); } };
Predicate <T> Let's use it on a collection:
Iterable<User> users = getMixedUsers(); // find all awesome users Iterable<User> onlyAwesomeUsers = Iterables.filter(users, onlyAwesome); // find one (first) awesome user User awesomeUser = Iterables.find(users, onlyAwesome); // or better Optional<User> awesomeOrAbsent = Iterables.tryFind(users, onlyAwesome);
Putting it together
private Iterable<Integer> puttingItTogether(Iterable<Integer> numbers) { FluentIterable<Integer> squaresOfEvens = FluentIterable.from(numbers) .filter(new Predicate<Integer>() { @Override public boolean apply(Integer input) { checkNotNull(input, "nulls are not allowed here!"); return input % 2 == 0; }}).transform(new Function<Integer, Integer>() { @Override public Integer apply(Integer input) { checkNotNull(input, "nulls are not allowed here!"); return input * input; } }); return squaresOfEvens; }
… Or
List<Integer> squaresOfEvens = Lists.newArrayList(); for (Integer number : givenNumbers) { if (number % 2 == 0) { squaresOfEvens.add(number * number); } } >> [ 4, 16, 36, 64, 100 ]
… Moral
List<Integer> squaresOfEvens = Lists.newArrayList(); for (Integer number : givenNumbers) { if (number % 2 == 0) { squaresOfEvens.add(number * number); } } >> [ 4, 16, 36, 64, 100 ]
Just be careful!!
Functional style can be great but it's not automatically the better way to go.
Java Caching
Java Caching with Guava Guava has a powerful on-heap key→value cache
Thread-safe implementation
More or less internally similar to ConcurrentMap + automatic eviction
No explicit support for distributed caching
Types of Caches Provides two types of caches:
LoadingCache - knows how to load entries when a cache miss occurs LoadingCache.get(key) returns the value associated with
key, loading it first if necessary
Cache - does not automatically load entries
We're going to focus on the loading case here; it's usually what you want
Caches (example)
CacheLoader<String, Graph> loader = new CacheLoader<String, Graph>() {
@Override public Graph load(String key) { return createExpensiveGraph(key); }
}; LoadingCache<String, Graph> cache = CacheBuilder.newBuilder().build(loader);
CacheBuilder The CacheBuilder has next properties:
Cache size
Time to expire entries after last access
Time based expiration of entries after being updated
Use of weak or soft references for keys/values
Setting RemovalListener that can receive events once an entry is removed fro the cache.
Concurrency level for update operations (defaults to 4)
Enable recording caching stats
CacheBuilder (example)
LoadingCache<String, String> cache = CacheBuilder.newBuilder() .maximumSize(1000) .expireAfterAccess(10, TimeUnit.SECONDS) .recordStats() .build(new CacheLoader<String, String>() { @Override public String load(String key) throws Exception { return key.toUpperCase(); } });
Concurrency Cache instances are internally implemented very
similar to ConcurrentHashMap (thus thread-safe)
CacheLoader.load will be invoked a single time for each key, regardless of the number of requesting threads
The result will be returned to all requesting threads and inserted into the cache using the equivalent of putIfAbsent
Cache Eviction By size
.maximumSize(long)
By custom weight:
.weigher(Weigher)
.maximumWeight(long)
By time:
.expireAfterAccess(long, TimeUnit)
.expireAfterWrite(long, TimeUnit)
Cache Eviction (cont.) Reference-based eviction:
.weakKeys()
.weakValues()
.softValues()
Explicit:
.invalidate(key)
.invalidateAll(keys)
.invalidateAll()
Checked Exceptions What if loading causes a checked exception?
CacheLoader<String, String> checkedLoader = new CacheLoader<String, String>() { @Override public String load(String key) throws IOException { return loadFromDisk(key); } };
Checked Exceptions (cont.)
LoadingCache<String, String> cache = CacheBuilder.newBuilder().build(checkedLoader); try { cache.get(key); } catch (ExecutionException e) { // ensure stack trace is for this thread throw new IOException(e.getCause()); }
Cache Stats hitCount – number of times Cache returned the
cached value
missCount – number of times Cache returned uncached value
loadSuccessCount – number of times Cache loaded new value successfully
Cache Stats (example)
LoadingCache<String, String> cache = CacheBuilder.newBuilder() .recordStats().build(checkedLoader); // cumulative stats since cache creation CacheStats stats = cache.stats(); CacheStats{ hitCount=4, missCount=3, loadSuccessCount=3, loadExceptionCount=0, totalLoadTime=676064, evictionCount=0 }
…Collections
MultiSet<E>
Implements Collection<E>
List: [a, c, b, b, c, a, a, b]
Set: [a, c, b]
Multiset: [a, a, a, c, c, b, b, b]
MultiSet<E>
Implements Collection<E>
List: [a, c, b, b, c, a, a, b]
Set: [a, c, b]
Multiset: [a, a, a, c, c, b, b, b]
So a Multiset<E> implementation only needs to store one occurrence of each element, plus a count!
[a x 3, c x 2, b x 3]
MultiSet<E>
Add multiple instances of a given element
Counts how many occurrences exist
Similar to a Map<E, Integer>, but...
only positive counts
size() returns total # of items, not # keys
count() for a non-existent key is 0
iterator() goes over each element
Usage: i.e. Track frequencies of elements, e.g. "word counting"
MultiSet<E> Implementations HashMultiset
TreeMultiset
LinkedHashMultiset
ConcurrentHashMultiset
ImmutableMultiset
Tired of this? Map<String, List<String>>
Tired of this? Map<String, List<String>> {a=1, a=2, b=3, c=4, c=5, c=6}
Try …
MultiMap<K, V> Like Map (key-value pairs), but may have duplicates
The values related to a single key can be viewed as a collection (set or list)
Similar to a Map<K, Collection<V>>, but...
get() never returns null (returns an empty collection)
containsKey() is true only if 1 or more values exist
entries() returns all entries for all keys
size() returns total number of entries, not keys
asMap() to view it as a Map<K, Collection<V>>
MultiMap<K, V>
Multimap<String, String> mm = ArrayListMultimap.create(); Collection<String> smiths = mm.get("Smith"); >> empty collection (never null) mm.put("Smith", "John"); mm.put("Smith", "Alice"); mm.put("Smith", "Diane"); smiths = mm.get("Smith"); >> [ "John", "Alice", "Diane" ]
MultiMap Implementations ArrayListMultimap
HashMultimap
LinkedListMultima
LinkedHashMultimap
TreeMultimap
ImmutableListMultimap
ImmutableSetMultimap
BiMap<K1, K2>
Bi-directional Map
Both keys and values are unique
Can view the inverse map with inverse()
Use instead of maintaining two separate maps: Map<K1, K2>
Map<K2, K1>
Static utilities In classes with name ending with an s Lists
Maps
Multimaps
Multisets
Sets
SortedMaps
Tables
Iterators
Iterables
Collections2
Static factories methods
Rather than typing
you type
Map<String, Class<? extends Handler>> m = new HashMap<String, Class<? extends Handler>>();
Map<String, Class<? extends Handler>> m2 = Maps.newHashMap();
Guava Alternatives
Should you use Guava or Apache Commons?
We may be biased, so consult this question on Stack Overflow:
http://tinyurl.com/guava-vs-apache
The large number of upvotes for the top answers shows a pretty strong community consensus
Need help with a problem? Post to Stack Overflow! Use the "guava" tag
Report a defect, request an enhancement?
http://code.google.com/p/guava-libraries/issues/list
Start an email discussion?
Send to [email protected]
General discussion takes place on
http://groups.google.com/group/guava-discuss
The Guava team is generally highly active in all of these areas
Time to Play
What to Remember Functional flavor of collection handling
CharMatcher / Splitter / Joiner
Avoid null where possible
Ease of Preconditions
Caching
Multimap / Multiset / Bimap
Q&A
http://www.flickr.com/photos/wwworks/4759535950/sizes/o/in/photostream/
References
http://code.google.com/p/guava-libraries/
http://code.google.com/p/guava-libraries/downloads/list