Mmmm...
Google Guava guava

About me

about me

Guava is...

  • a fruit

Guava is...

  • a set of utility classes and methods
  • some quite neat collection implementations (AKA. google-collections)
  • comparable to Apache Commons
  • basically... a painkiller and natural extension for Java (stdlib)




Let's go!

Transform: GTUG -> GDG

Each
kraków gtug Member

is now a:
GDG Kraków Member

Vanilla Java


List<GTUGMember> gtugMembers = new ArrayList <GTUGMember>();
gtugMembers.add(GTUG.member("Konrad"));
gtugMembers.add(GTUG.member("Łukasz"));

List<GDGMember> gdgMembers = new ArrayList <>();

for(GTUGMember member: gtugMembers)
gdgMembers.add(GDGMember.from(member))

// done!

               

Transform

import com.google.common.collect.*;

List<GTUGMember> gtugMembers = Lists.newArrayList(GTUG.member("Konrad"), GTUG.member("Łukasz"));

Function<GTUGMember, GDGMember> toGDGMember = new Function<GTUGMember, GDGMember>() {
  @Override
  public Object apply(@Nullable String input) {
    return input.toUpperCase();
  }
};

List<GDGMember> gdgMembers = Lists.transform(gtugMembers, toGDGMember);

         

Transform

A small trick:
import com.google.common.collect.*;

class DGDMember {
  public static Function<GTUGMember, GDGMember> fromGTUGMember() { /* ... */ }
}

List<GTUGMember> gtugMembers = Lists.newArrayList(GTUG.member("Konrad"), GTUG.member("Łukasz"));

List<GDGMember> gdgMembers = Lists.transform(gtugMembers, GDGMember.fromGTUGMember());

               

Transform is a view

List<Integer> integers = newArrayList(1, 2, 3);
List<String> strings = Lists.transform(integers, Functions.toStringFunction());

integers.add(4);
integers.add(5);

assertThat(strings.size()).isEqualTo(5);

"This would be 1 line in _____"

Scala for example:

case class GTUGMember(val name: String)
case class GDGMember(val name: String)

val gtugMembers = List(GTUGMember("Konrad"))

// map all members to gdg Members
val gdgMembers = members map { GDGMember(_.name) }
            
So, yes - we're aware such things are Simple in other languages, but that's where Guava tries to help.

And anyway... LISP had those for years ;-)

FluentIterable

A nice new way (since Guava 12) to combine all these operations using a fluent interfaceL

  FluentIterable
    .from(database.getClientList())
    .filter(activeInLastMonth())
    .transform(Functions.toStringFunction())
    .limit(10)
    .toImmutableList();

Functional concepts brought to Java

Many things in Guava are inspired by functional concepts from other programming lanugages, just like the previous "map operation" (.transform())!

Core concepts

Some of the key functional concepts Guava uses are:
  • Function<A,B> == A => B
  • Predicate<T> == T => Boolean
  • Optional<T> == "Present" or "Absent"


Optional may seem similiar to a "Maybe Monad" :-)

Function <A,B>

Java7 doesn't have lambda expressions, but Guava helps us out (a bit) with Function. Composing functions:

Function <Integer, Integer> doubler = new Function <Integer, Integer>() {
  @Override
  public Integer apply(@Nullable Integer input) {
    return input * 2;
  }
};

Function<Integer, Integer> halfer = new Function<Integer, Integer>() {
  @Override
  public Integer apply(@Nullable Integer input) {
    return input / 2;
  }
};

Function<Integer, Integer> identity = Functions.compose(doubler, halfer);

Integer two = identity.apply(2);
assertThat(two).isEqualTo(2);
doubler(halfer(x))

Optional vs. null

Null Sucks. -- Doug Lea


null is "hidden",
Optional is explicit.

Optional

Ugly but null-safe:

public String fullName(String firstName,
                       Optional<String> maybeMiddleName,
                       String lastName) {

  String middleName = "";
  if(maybeMiddleName.isPresent()) {middleName = maybeMiddleName.get();}
  return firstName + " " + middleName + " " + lastName;
}
Nicer:

public String fullName(String firstName,
                       Optional<String> maybeMiddleName,
                       String lastName) {

  return firstName + " " + maybeMiddleName.or("") + " " + lastName;
}
Haven't seen a null-pointer in my code since a few months now! -- random Optional user

Predicate

Quite similar to Function but does NOT extend it.
Predicate<User> onlyAwesome = new Predicate<User>() {
  @Override
  public boolean apply(@Nullable User in) {
    return Optional.fromNullable(in).or(User.NOT_AWESOME).isAwesome();
  }
}
Let's use it on a collection:
List<User> users = getMixedUsers();
// find all awesome users
List<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);

Iterables.*

Iterables has a lot useful static methods:
  • <T> T get(Iterable<? extends T> iterable, int position, T defaultValue)
  • <T> Iterable <List<T>> partition(Iterable<T> iterable, int size)
  • <T> boolean all(Iterable<T> iterable, Predicate<? super T> predicate)
  • <T> boolean any(Iterable<T> iterable, Predicate<? super T> predicate)
  • <T> Iterable<T> cycle(<T>... elements)
  • and a lot more!

Pro Tip: Function.forMap()

In Scala for example, a Map behaves just like a Function:
val nicknameOf = Map("Konrad" -> "ktoso")
nicknameOf("Konrad") == "ktoso"
With Guava's help you can do the same:
ImmutableMap <String, String> nicknameMap = ImmutableMap.of("Konrad", "ktoso");
Function <String, String> nicknameOf = Functions.forMap(nicknameMap);

nicknameOf.apply("Konrad");
If you think about it, a Map is just a function with a LUT.

"Hey, what's this ImmutableMap?!"

Immutability

Is awesome because:
  • free thread safety
  • No more "will someone change this collection?" panic
  • sometimes -> performance

Vanilla JDK - constant set

public static final Set<Integer> NUMS = Collections.unmodifiableSet(
  new LinkedHashSet<>(
    Arrays.asList(1, 2, 3, 4, 5, 6)
  )
);
Problems here?
  • 3 external classes to build a Set?!
  • Not here but in general: Umodifiable != Immutable!

ImmutableSet

public static final Set<Integer> NUMS = ImmutableSet.of(1, 2, 3, 4, 5);
            
Better now?
  • Guaranteed immutability
  • FAST
  • SMALL
Highly recommended to check out it's sources - lot's of smart optimizations down there!

Defensive copying


public static final ImmutableSet <Color> GOOGLE_COLORS =
  ImmutableSet.<Color>builder()
    .addAll(WEBSAFE_COLORS)
    .add(new Color(0, 191, 255))
    .build();
            

More immutable collections

  • DescendingImmutableSortedMultiset
  • ForwardingImmutableList
  • ForwardingImmutableMap
  • ForwardingImmutableSet
  • ImmutableAsList
  • ImmutableBiMap
  • ImmutableClassToInstanceMap
  • ImmutableCollection
  • ImmutableEntry
  • ImmutableEnumSet
  • ImmutableList
  • ImmutableListMultimap
  • ImmutableMap
  • ImmutableMultimap
  • ImmutableMultiset
  • ImmutableSet
  • ImmutableSetMultimap
  • ImmutableSortedAsList
  • ImmutableSortedMap
  • ImmutableSortedMapFauxverideShim
  • ImmutableSortedMultiset
  • ImmutableSortedMultisetFauxverideShim
  • ImmutableSortedSet
  • ImmutableSortedSetFauxverideShim
  • ImmutableTable
  • SingletonImmutableTable
  • TransformedImmutableSet
  • ... and a lot more ;-)

More Collection utils

A pair of:
  • Joiner
  • Splitter

Joiner

Solves the issue of nicely printing a list of something.
Sounds easy? Dig this:
List <String> l = newArrayList("a", "b", "c");

String separator = ", ";
StringBuilder sb = new StringBuilder();
String sep = "";
for (Object object : l) {
   sb.append(sep).append(object.toString());
   sep = separator;
}
assertThat(sb.toString()).isEqualTo("a,b,c");
Versus this:
String pretty = Joiner.on(", ").join(list);
assertThat(pretty).isEqualTo("a,b,c");

MapJoiner

This time without the "without libraries" example, guess why ;-)
Map names = ImmutableMap.of("Konrad", "ktoso", "Sebastian", "fridek");

String s = Joiner.on(";").withKeyValueSeparator(":").join(names);

assertThat(s).isEqualTo("Konrad:ktoso,Sebastian:fridek");

Splitter

The inverse of Joiner.

Map<String, String> vals = Splitter.on(';')
                                   .omitEmptyStrings()
                                   .trimResults()
                                   .withKeyValueSeparator(":")
                                   .split(s);

String nickname = vals.get("Konrad");
assertThat(nickname).isEqualTo("ktoso");
Yes, Joiner has those nice-to-have methods too.

BiMap

While we're on a roll here... Let's check out a new Collection class implemented in Guava!
Map<String, String> vals = Splitter.on(';')
                                   .omitEmptyStrings()
                                   .trimResults()
                                   .withKeyValueSeparator(":")
                                   .split(s);

BiMap<String, String> biMap = HashBiMap.create(vals);

String ktoso = biMap.get("Konrad");

String konrad = biMap.inverse().get("ktoso");
            

Notable collections

  • Multiset <String>
  • MultiMap <Integer, String>
  • Table <String, String, Integer>

Streams & Files

IO Operations are a bit bloated in java (6):
 try {
  FileWriter fstream = new FileWriter("out.txt");
  BufferedWriter out = new BufferedWriter(fstream);
  out.write("Hello Java");
  out.close();
} catch (Exception ex) {
  logger.error("Unable to hello world! AAAA!", ex);
} finally {
  try {
    if(out != null) out.close();
  } catch(Exception ex) {
    logger.error("Unable to close writer! AAAA!!", ex);
  }
}
It's gotten better with Java 7's try-with-resources:
try(BufferedWriter out = new BufferedWriter(new FileWriter("out.txt"))) {
  out.write("Hello Java 7!");
}

Files

Guava on the other hand contains such nice methods as:
Files.write("Hello Guava!", new File(""), Charsets.UTF_8);

Files.append("Hello Guava!", new File(""), Charsets.UTF_8);
            
We also get some File operation utils (which are kind-of replaced by Java 7's Paths nowadays):
Files.move(fromFile, toFile);
Files.touch(new File("/tmp/it.txt"));

// and others:
Files.toString(file, Charsets.UTF_16);
Files.equal(someFile, anotherFile);
            

Closeables

Yet another way to close streams:
public void useStreamNicely() throws IOException {
  SomeStream stream = new SomeStream("foo");
  boolean threw = true;
  try {
    // Some code which does something with the Stream. May throw a
    // Throwable.
    threw = false; // No throwable thrown.
  } finally {
    // Close the stream.
    // If an exception occurs, only rethrow it if (threw==false).
    Closeables.close(stream, threw);
}
            

Others include...

  • CharStreams
  • ByteStreams
  • NullOutputStream
  • ...

Future

JDK future is quite ok, but...
Future <String> futureString = executor.submit(new Callable <String>() {
  public String call() { return searcher.search(target); }
});

futureString.get(); // only way to obtain the future!
There is FutureTask if you need more...
Idea: why not have add a listener?
final ListenableFuture <String> future = service.query(name);
future.addListener(new Runnable() {
  public void run() {
    logger.info("Yay! Got: " + future.get());
  }
}, executor);

Futures

Futures can also help out with centralizing exception handling:
Futures can help us out there:

ListenableFuture <QueryResult> future = ...;
 addCallback(future,
     new FutureCallback <QueryResult> {
       public void onSuccess(QueryResult result) {
         storeInCache(result);
       }
       public void onFailure(Throwable t) {
         reportError(t);
       }
     });
            

Treating Future as a Monad

Hard words, simple code:

ListenableFuture <QueryResult> future = ...;

Function <QueryResult, URI> mapToURI = ...;

ListenableFuture<URI> futureUri = Futures.transform(future, mapToURI);
            
See how this is "the same" operation as on a collection? It's map / flatMap all over again!

More Futures tools

Since we mentioned collections...
Transform a List of Futures into a Future List
List <Future <String>> futures = ImmutableList.of(future1, future2);

Future <List <String>> oneFuture = Futures.allAsList(futures);
//                        ^ succeeds if ALL succeed
            
Or just successful futures:
Future <List <String>> oneFuture = Futures.successfulAsList(futures);

SettableFuture

A very easy to complete Future implementation:
final SettableFuture<String> future = SettableFuture.create();

future.addListener(new Runnable() {
  @Override
  public void run() {
    try {
      String value = future.get();
      System.out.println("value = " + value);

    } catch (Exception e) {
      Throwables.propagate(e);
    }
 }
}, Executors.newSingleThreadExecutor());
new Thread(){
  @Override
  public void run() {
    try {
      Thread.sleep(1000);
      future.set("Hello!");
    } catch (InterruptedException ignored) {  }
  }
}.start();

Stuff we didn't cover
in our 30 minutes

  • @VisibleForTesting
  • TypeToken
  • ForwardingList
  • Hashing
  • UnsignedLong
  • Objects
  • Preconditions
  • MapMaker
  • Stopwatch
  • Limiters
  • ... and More!

@VisibleForTesting

A small, nothing-doing annotation.
@VisibleForTesting
List<Stuff> findStuff(String name) {
  //...
}
It explains why this method is package private. May be "nothing", but is still nice.

TypeToken

Awesomely retain generics information in runtime:
 new TypeToken<List<String>>() {}
Without a TypeToken, information about <String> would be lost.
TypeToken leverages the fact that the generics information here MUST be kept in order to create a class instance of such type.

UnsignedLong

uint in Java!?


               

Hashing

Multiple populat hash functions are implemented in it (sha, md5, others...):

Hashing.md5().newHasher()
       .putString(name)
       .putInt(age)
       .hash().asLong();

Objects::equals

@Override
public boolean equals(Object o) {
  Person that = (Person) o;

  if (age != null ? !age.equals(person.age) : person.age != null) return false;
  if (name != null ? !name.equals(person.name) : person.name != null) return false;

  return true;
}
Vs.
@Override
public boolean equals(Object o) {
  Person that = (Person) o;

  return Objects.equal(that.name, this.name) && Objects.equal(that.age, this.age);
}
Pro Tip: A similar implementation is present in JDK7! :-)

Objects::hashCode

@Override
public int hashCode() {
  int result = name != null ? name.hashCode() : 0;
  result = 31 * result + (surname != null ? surname.hashCode() : 0);
  result = 31 * result + (age != null ? age.hashCode() : 0);
  return result;
}
Vs.
@Override
public int hashCode() {
  return  Objects.hashCode(name, surname, age);
}
Pro Tip: java.util.Objects::hash(Object... objects) has also been implemented in JDK7!

Itermission: Why "::"?

As JDK 8 is comming nearer... let's get confortable with the Class::method notation.
As of JDK 8, this syntax will be used to obtain Method references:
class Person {
  public String get() { return "" }
}

String::toString;
// or
Person p = new Person();
p::get;
               
...java.net/~briangoetz/lambda/lambda-state-4.html

Intermission: Why "::"?

Why should you care?

// bellow code is valid (JDK 8) Java
Collections.sort(people, comparing(p -> p.getLastName()));

people.sort(comparing(Person::getLastName));
               
The Guava equivalent (a bit more powerfull):

List <Foo> foos = newArrayList(new Foo("z"), new Foo("a"));

Function <Foo, Comparable> getName = new Function <Foo, Comparable>() {
            public Comparable apply(@Nullable Foo input) {
                assert input != null;
                return input.name;
            }
        };

Collections.sort(foos, Ordering.natural().onResultOf(getName));
               
Mini Scala trolling:

                     foos.sortBy(_.name)
                  

MapMaker


ConcurrentMap<Key, Graph> graphs = new MapMaker()
   .concurrencyLevel(4)
   .makeComputingMap(
       new Function<Key, Graph>() {
         public Graph apply(Key key) {
           return createExpensiveGraph(key);
         }
       });
            

MapMaker


ConcurrentMap<Key, Graph> graphs = new MapMaker()
   .concurrencyLevel(4)
   .maximumSize(10000)
   .expireAfterWrite(10, TimeUnit.MINUTES)
   .makeComputingMap(
       new Function<Key, Graph>() {
         public Graph apply(Key key) {
           return createExpensiveGraph(key);
         }
       });
            

MapMaker


ConcurrentMap<Key, Graph> graphs = new MapMaker()
   .concurrencyLevel(4)
   .weakKeys()
   .maximumSize(10000)
   .expireAfterWrite(10, TimeUnit.MINUTES)
   .makeComputingMap(
       new Function<Key, Graph>() {
         public Graph apply(Key key) {
           return createExpensiveGraph(key);
         }
       });
            

Stopwatch

A simple tool for simple time measurement:
Stopwatch watch = new Stopwatch().start();
Thread.sleep(100);

System.out.println("Code took: " + watch.stop());

CaseFormat

Utility to convert between snake_case or camelCase or CamelCase:
String upperCamel = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, "myName");
assertThat(upperCamel).isEqualTo("MyName");

String lowerHypen = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, "myName")
assertThat(lowerHypen).isEqualTo("my-name");
Format Example
LOWER_CAMEL lowerCamel
LOWER_HYPHEN lower-hyphen
LOWER_UNDERSCORE lower_underscore
UPPER_CAMEL UpperCamel
UPPER_UNDERSCORE UPPER_UNDERSCORE

RateLimiter


final RateLimiter rateLimiter = RateLimiter.create(2.0); // rate is "2 permits per second"
void submitTasks(List <Runnable> tasks, Executor executor) {
  for (Runnable task : tasks) {
    rateLimiter.acquire(); // may wait
    executor.execute(task);
  }
}

TimeLimiter


TimeLimiter limiter = ...;
TargetType proxy = limiter.newProxy(target, TargetType.class, 50, TimeUnit.MILLISECONDS);
try {
  return proxy.someMethod();
} catch (UncheckedTimeoutException e) {
  return DEFAULT_VALUE;
}

How is Guava tested?

Obviously Guava code has to be valid,
but it also has to be performant.
Google Caliper
code.google.com/p/caliper
Simple / Small microbenchmarking
caliper

Google Caliper

public static void main(String[] args) {
   Runner.main(UnsignedLongsBenchmark.class, args);
}
public class UnsignedLongsBenchmark extends SimpleBenchmark {

   @Override
   protected void setUp() {
    for (int i = 0; i < ARRAY_SIZE; i++) {
      longs[i] = random();
      divisors[i] = randomDivisor(longs[i]);
    }
   }

   // it's a TIME test
   public long timeDivide(int reps) {
    long tmp = 0;
    for (int i = 0; i < reps; i++) {
      int j = i & ARRAY_MASK;
      tmp += UnsignedLongs.divide(longs[j], divisors[j]);
    }
    return tmp;
   }

   // ...
            

I want moar!

Sources:

Presentations:

Videos:

ありがとう!

Dzięki!

slides are googlable
or @ blog.project13.pl