Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Guava by Example

Avatar for eneveu eneveu
January 29, 2012

Guava by Example

Slides of a talk I gave at the Sfeir BoF on March 4, 2011. In this talk, I tried to show how Guava simplifies "standard" Java code, while demonstrating various Guava features.

You'll notice that I had the novel idea to use "ragefaces" to add some humor, and to illustrate good/bad code examples. Not sure if I should use these in future talks ;)

Avatar for eneveu

eneveu

January 29, 2012
Tweet

More Decks by eneveu

Other Decks in Programming

Transcript

  1. Base – Simple example bean public class Employee { private

    String name; private Integer age; private Job job; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Job getJob() { return job; } public void setJob(Job job) { this.job = job; } } public enum Job { CEO, DEVELOPER, DESIGNER }
  2. Base – Objects.equal() public class Employee { private String name;

    private Integer age; private Job job; } public boolean equals(Object object) { if (!(object instanceof Employee)) return false; Employee that = (Employee) object; return (name == that.name || (name != null && name.equals(that.name))) && (age == that.age || (age != null && age.equals(that.age))) && job == that.job; }
  3. Base – Objects.equal() public class Employee { private String name;

    private Integer age; private Job job; } public boolean equals(Object object) { if (!(object instanceof Employee)) return false; Employee that = (Employee) object; return (name == that.name || (name != null && name.equals(that.name))) && (age == that.age || (age != null && age.equals(that.age))) && job == that.job; } public boolean equals(Object object) { if (!(object instanceof Employee)) return false; Employee that = (Employee) object; return Objects.equal(name, that.name) && Objects.equal(age, that.age) && job == that.job; }
  4. Base – Objects.hashCode() public class Employee { private String name;

    private Integer age; private Job job; } public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (age != null ? age.hashCode() : 0); result = 31 * result + (job != null ? job.hashCode() : 0); return result; }
  5. Base – Objects.hashCode() public class Employee { private String name;

    private Integer age; private Job job; } public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + (age != null ? age.hashCode() : 0); result = 31 * result + (job != null ? job.hashCode() : 0); return result; } public int hashCode() { return Objects.hashCode(name, age, job); }
  6. Base – Objects.toStringHelper() public class Employee { private String name;

    private Integer age; private Job job; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append(Employee.class.getSimpleName()); sb.append("{name=").append(name); sb.append(", age=").append(age); sb.append(", job=").append(job); sb.append('}'); return sb.toString(); }
  7. Base – Objects.toStringHelper() public class Employee { private String name;

    private Integer age; private Job job; } public String toString() { StringBuilder sb = new StringBuilder(); sb.append(Employee.class.getSimpleName()); sb.append("{name=").append(name); sb.append(", age=").append(age); sb.append(", job=").append(job); sb.append('}'); return sb.toString(); } public String toString() { return Objects.toStringHelper(this) .add("name", name) .add("age", age) .add("job", job) .toString(); }
  8. Base – ComparisonChain public class Employee { private String name;

    private Integer age; private Job job; } public int compareTo(Employee other) { int result = name.compareTo(other.name); if (result != 0) return result; result = age.compareTo(other.age); if (result != 0) return result; return job.compareTo(other.job); }
  9. Base – ComparisonChain public class Employee { private String name;

    private Integer age; private Job job; } public int compareTo(Employee other) { int result = name.compareTo(other.name); if (result != 0) return result; result = age.compareTo(other.age); if (result != 0) return result; return job.compareTo(other.job); } public int compareTo(Employee other) { return ComparisonChain.start() .compare(name, other.name) .compare(age, other.age) .compare(job, other.job) .result(); }
  10. Base – ComparisonChain & Ordering public class Employee { private

    String name; private Integer age; private Job job; } public int compareTo(Employee other) { int result = name.compareTo(other.name); if (result != 0) return result; result = age.compareTo(other.age); if (result != 0) return result; return job.compareTo(other.job); } public int compareTo(Employee other) { return ComparisonChain.start() .compare(name, other.name, Ordering.natural().nullsLast()) .compare(age, other.age, Ordering.natural().reverse().nullsLast()) .compare(job, other.job, Ordering.natural().nullsLast()) .result(); }
  11. Base – Preconditions public class Money { private final BigDecimal

    amount; private final Currency currency; public Money(BigDecimal amount, Currency currency) { if (amount == null) { throw new NullPointerException("amount must not be null"); } if (currency == null) { throw new NullPointerException("currency must not be null"); } if (amount.signum() < 0) { throw new IllegalArgumentException("amount must be positive: " + amount); } this.amount = amount; this.currency = currency; } }
  12. Base – Preconditions import com.google.common.base.Preconditions; public class Money { private

    final BigDecimal amount; private final Currency currency; public Money(BigDecimal amount, Currency currency) { Preconditions.checkNotNull(amount, "amount must not be null"); Preconditions.checkNotNull(currency, "currency must not be null"); Preconditions.checkArgument(amount.signum() >= 0, "amount must be positive: %s", amount); this.amount = amount; this.currency = currency; } }
  13. Base – Preconditions import com.google.common.base.Preconditions; public class Money { private

    final BigDecimal amount; private final Currency currency; public Money(BigDecimal amount, Currency currency) { this.amount = Preconditions.checkNotNull(amount, "amount must not be null"); this.currency = Preconditions.checkNotNull(currency, "currency must not be null"); Preconditions.checkArgument(amount.signum() >= 0, "amount must be positive: %s", amount); } } public static <T> T checkNotNull(T reference) { if (reference == null) { throw new NullPointerException(); } return reference; }
  14. Base – Preconditions import static com.google.common.base.Preconditions.*; public class Money {

    private final BigDecimal amount; private final Currency currency; public Money(BigDecimal amount, Currency currency) { this.amount = checkNotNull(amount, "amount must not be null"); this.currency = checkNotNull(currency, "currency must not be null"); checkArgument(amount.signum() >= 0, "amount must be positive: %s", amount); } }
  15. Base – Preconditions import static com.google.common.base.Preconditions.*; public class Money {

    private final BigDecimal amount; private final Currency currency; public Money(BigDecimal amount, Currency currency) { this.amount = checkNotNull(amount, "amount must not be null"); this.currency = checkNotNull(currency, "currency must not be null"); checkArgument(amount.signum() >= 0, "amount must be positive: %s", amount); } } More information: http://stackoverflow.com/questions/3128120/what-is-the-proper-error-message-to-supply-to-google-guavas-preconditions http://piotrjagielski.com/blog/google-guava-vs-apache-commons-for-argument-validation/
  16. Base – Objects.firstNonNull() private static final String UNKNOWN_COORDINATES = "Unknown

    coordinates"; public String getCoordinatesAsText() { return getGpsCoordinates() != null ? getGpsCoordinates() : UNKNOWN_COORDINATES; } public String getGpsCoordinates() { // retrieve GPS coordinates from satellite }
  17. Base – Objects.firstNonNull() private static final String UNKNOWN_COORDINATES = "Unknown

    coordinates"; public String getCoordinatesAsText() { return getGpsCoordinates() != null ? getGpsCoordinates() : UNKNOWN_COORDINATES; } public String getGpsCoordinates() { // retrieve GPS coordinates from satellite → SLOW! }
  18. Base – Objects.firstNonNull() private static final String UNKNOWN_COORDINATES = "Unknown

    coordinates"; public String getCoordinatesAsText() { String gpsCoordinates = getGpsCoordinates(); return gpsCoordinates != null ? gpsCoordinates : UNKNOWN_COORDINATES; } public String getGpsCoordinates() { // retrieve GPS coordinates from satellite }
  19. Base – Objects.firstNonNull() private static final String UNKNOWN_COORDINATES = "Unknown

    coordinates"; public String getCoordinatesAsText() { return Objects.firstNonNull(getGpsCoordinates(), UNKNOWN_COORDINATES); } public String getGpsCoordinates() { // retrieve GPS coordinates from satellite }
  20. Base – Joiner List<String> heroes = Lists.newArrayList("Kick-Ass", "Iron Man", "Chuck

    Norris"); String names = Joiner.on(", ").join(heroes); // "Kick-Ass, Iron Man, Chuck Norris"
  21. Base – Joiner List<String> heroes = Lists.newArrayList("Kick-Ass", "Iron Man", "Chuck

    Norris"); String names = Joiner.on(", ").join(heroes); // "Kick-Ass, Iron Man, Chuck Norris" List<String> heroes = Lists.newArrayList("Kick-Ass", "Iron Man", null, "Chuck Norris"); String names = Joiner.on(", ").join(heroes); // throws NullPointerException
  22. Base – Joiner List<String> heroes = Lists.newArrayList("Kick-Ass", "Iron Man", "Chuck

    Norris"); String names = Joiner.on(", ").join(heroes); // "Kick-Ass, Iron Man, Chuck Norris" List<String> heroes = Lists.newArrayList("Kick-Ass", "Iron Man", null, "Chuck Norris"); String names = Joiner.on(", ").join(heroes); // throws NullPointerException List<String> heroes = Lists.newArrayList("Kick-Ass", "Iron Man", null, "Chuck Norris"); String names = Joiner.on(", ").skipNulls().join(heroes); // "Kick-Ass, Iron Man, Chuck Norris"
  23. Base – Joiner List<String> heroes = Lists.newArrayList("Kick-Ass", "Iron Man", "Chuck

    Norris"); String names = Joiner.on(", ").join(heroes); // "Kick-Ass, Iron Man, Chuck Norris" List<String> heroes = Lists.newArrayList("Kick-Ass", "Iron Man", null, "Chuck Norris"); String names = Joiner.on(", ").join(heroes); // throws NullPointerException List<String> heroes = Lists.newArrayList("Kick-Ass", "Iron Man", null, "Chuck Norris"); String names = Joiner.on(", ").skipNulls().join(heroes); // "Kick-Ass, Iron Man, Chuck Norris" List<String> heroes = Lists.newArrayList("Kick-Ass", "Iron Man", null, "Chuck Norris"); String names = Joiner.on(", ").useForNull("Invisible Man").join(heroes); // prints "Kick-Ass, Iron Man, Invisible Man, Chuck Norris"
  24. Base – Joiner (MapJoiner) Map<Integer, String> map = new HashMap<Integer,

    String>(); map.put(1, "Chuck Norris"); map.put(2, "Iron Man"); map.put(3, "Kick-Ass"); String ranks = Joiner.on('\n').withKeyValueSeparator(" -> ").join(map); System.out.println(ranks); Prints: 1 -> Chuck Norris 2 -> Iron Man 3 -> Kick-Ass
  25. Base – CharMatcher We want to accept: 0 1 2

    3 4 5 6 7 8 9 - _ private static final CharMatcher VALID_CHARS = CharMatcher.DIGIT.or(CharMatcher.anyOf(“-_”); String VALID_CHARS.retainFrom(input);
  26. Base – CharMatcher We want to accept: 0 1 2

    3 4 5 6 7 8 9 - _ private static final CharMatcher VALID_CHARS = CharMatcher.DIGIT.or(CharMatcher.anyOf(“-_”); String VALID_CHARS.retainFrom(input); Import static com.google.common.base.Preconditions.*; checkArgument(CharMatcher.WHITESPACE.matchesAllOf(input));
  27. Base – CharMatcher We want to accept: 0 1 2

    3 4 5 6 7 8 9 - _ private static final CharMatcher VALID_CHARS = CharMatcher.DIGIT.or(CharMatcher.anyOf(“-_”); String VALID_CHARS.retainFrom(input); Import static com.google.common.base.Preconditions.*; checkArgument(CharMatcher.WHITESPACE.matchesAllOf(input)); String decoded = decode(base64encodedString); --> problem: decoded String is padded with NULL control characters
  28. Base – CharMatcher We want to accept: 0 1 2

    3 4 5 6 7 8 9 - _ private static final CharMatcher VALID_CHARS = CharMatcher.DIGIT.or(CharMatcher.anyOf(“-_”); String VALID_CHARS.retainFrom(input); Import static com.google.common.base.Preconditions.*; checkArgument(!CharMatcher.WHITESPACE.matchesAllOf(input)); String decoded = decode(base64encodedString); --> problem: decoded String is padded with NULL control characters String result = CharMatcher.JAVA_CONTROL_CHAR.trimTrailingFrom(decoded);
  29. Base – Splitter Iterable<String> heroes = Splitter.on(“,”).split(“Iron Man, , Kick-Ass,Didier

    Girard”); // contains “Iron Man”, “ “, “ Kick-Ass”, “Didier Girard”
  30. Base – Splitter Iterable<String> heroes = Splitter.on(“,”).split(“Iron Man, , Kick-Ass,Didier

    Girard”); // contains “Iron Man”, “ “, “ Kick-Ass”, “Didier Girard” Iterable<String> heroes = Splitter.on(“,”).trimResults().split(“Iron Man, , Kick-Ass,Didier Girard”); // contains “Iron Man”, ““, “Kick-Ass”, “Didier Girard”
  31. Base – Splitter Iterable<String> heroes = Splitter.on(“,”).split(“Iron Man, , Kick-Ass,Didier

    Girard”); // contains “Iron Man”, “ “, “ Kick-Ass”, “Didier Girard” Iterable<String> heroes = Splitter.on(“,”).trimResults().split(“Iron Man, , Kick-Ass,Didier Girard”); // contains “Iron Man”, ““, “Kick-Ass”, “Didier Girard” Iterable<String> heroes = Splitter.on(“,”).trimResults().omitEmptyStrings() .split(“Iron Man, , Kick-Ass,Didier Girard”); // contains “Iron Man”, “Kick-Ass”, “Didier Girard”
  32. Collections – Static factories // standard ArrayList List<Map<String, Object>> maps

    = new ArrayList<Map<String, Object>>(); // type inference using Guava static factory List<Map<String, Object>> maps = Lists.newArrayList();
  33. Collections – Static factories // standard ArrayList List<Map<String, Object>> maps

    = new ArrayList<Map<String, Object>>(); // type inference using Guava static factory List<Map<String, Object>> maps = Lists.newArrayList(); // another static factory (good naming conventions) List<String> names = Lists.newArrayListWithExpectedSize(42); List<String> names = Lists.newArrayListWithCapacity(42);
  34. Collections – Static factories // standard ArrayList List<Map<String, Object>> maps

    = new ArrayList<Map<String, Object>>(); // type inference using Guava static factory List<Map<String, Object>> maps = Lists.newArrayList(); // another static factory (good naming conventions) List<String> names = Lists.newArrayListWithExpectedSize(42); List<String> names = Lists.newArrayListWithCapacity(42); // from var args List<String> names = Lists.newArrayList("Tony Stark", "James Rhodes");
  35. Collections – Static factories // standard ArrayList List<Map<String, Object>> maps

    = new ArrayList<Map<String, Object>>(); // type inference using Guava static factory List<Map<String, Object>> maps = Lists.newArrayList(); // another static factory (good naming conventions) List<String> names = Lists.newArrayListWithExpectedSize(42); List<String> names = Lists.newArrayListWithCapacity(42); // from var args List<String> names = Lists.newArrayList("Tony Stark", "James Rhodes"); // from Iterable Iterable<String> namesIterable = … List<String> names = Lists.newArrayList(namesIterable);
  36. Collections – Static factories // standard ArrayList List<Map<String, Object>> maps

    = new ArrayList<Map<String, Object>>(); // type inference using Guava static factory List<Map<String, Object>> maps = Lists.newArrayList(); // another static factory (good naming conventions) List<String> names = Lists.newArrayListWithExpectedSize(42); List<String> names = Lists.newArrayListWithCapacity(42); // from var args List<String> names = Lists.newArrayList("Tony Stark", "James Rhodes"); // from Iterable Iterable<String> namesIterable = … List<String> names = Lists.newArrayList(namesIterable); // Sets Set<Employee> employees = Sets.newHashSet(); // Maps Map<String, Employee> employeesById = Maps.newHashMapWithExpectedSize(5);
  37. Collections – Static factories import static com.google.common.collect.Lists.*; import static com.google.common.collect.Maps.newHashMapWithExpectedSize;

    import static com.google.common.collect.Sets.newHashSet; // type inference using Guava static factory List<Map<String, Object>> maps = newArrayList(); // another static factory (good naming conventions) List<String> names = newArrayListWithExpectedSize(42); List<String> names = newArrayListWithCapacity(42); // from var args List<String> names = newArrayList("Tony Stark", "James Rhodes"); // from Iterable Iterable<String> namesIterable = … List<String> names = newArrayList(namesIterable); // Sets Set<Employee> employees = newHashSet(); // Maps Map<String, Employee> employeesById = newHashMapWithExpectedSize(5);
  38. Collections – Immutable collections public static final Set<Locale> LOCALES =

    Collections.unmodifiableSet( new LinkedHashSet<Locale>( Arrays.asList(Locale.FRANCE, Locale.JAPAN, Locale.GERMAN) ) );
  39. Collections – Immutable collections public static final Set<Locale> LOCALES =

    Collections.unmodifiableSet( new LinkedHashSet<Locale>( Arrays.asList(Locale.FRANCE, Locale.JAPAN, Locale.GERMAN) ) ); public static final Set<Locale> LOCALES = ImmutableSet.of(Locale.FRANCE, Locale.JAPAN, Locale.GERMAN);
  40. Collections – Immutable collections public static final Map<Locale, Integer> LOCALE_RANKS;

    static { Map<Locale, Integer> ranks = new LinkedHashMap<Locale, Integer>(); ranks.put(Locale.GERMAN, 1); ranks.put(Locale.FRANCE, 2); ranks.put(Locale.JAPAN, 3); LOCALE_RANKS = Collections.unmodifiableMap(ranks); }
  41. Collections – Immutable collections public static final Map<Locale, Integer> LOCALE_RANKS;

    static { Map<Locale, Integer> ranks = new LinkedHashMap<Locale, Integer>(); ranks.put(Locale.GERMAN, 1); ranks.put(Locale.FRANCE, 2); ranks.put(Locale.JAPAN, 3); LOCALE_RANKS = Collections.unmodifiableMap(ranks); } public static final Map<Locale, Integer> LOCALE_RANKS; static { ImmutableMap.Builder<Locale, Integer> ranks = ImmutableMap.builder(); ranks.put(Locale.GERMAN, 1); ranks.put(Locale.FRANCE, 2); ranks.put(Locale.JAPAN, 3); LOCALE_RANKS = ranks.build(); }
  42. Collections – Immutable collections public static final Map<Locale, Integer> LOCALE_RANKS;

    static { Map<Locale, Integer> ranks = new LinkedHashMap<Locale, Integer>(); ranks.put(Locale.GERMAN, 1); ranks.put(Locale.FRANCE, 2); ranks.put(Locale.JAPAN, 3); LOCALE_RANKS = Collections.unmodifiableMap(ranks); } public static final Map<Locale, Integer> LOCALE_RANKS; static { ImmutableMap.Builder<Locale, Integer> ranks = ImmutableMap.builder(); ranks.put(Locale.GERMAN, 1); ranks.put(Locale.FRANCE, 2); ranks.put(Locale.JAPAN, 3); LOCALE_RANKS = ranks.build(); } public static final Map<Locale, Integer> LOCALE_RANKS = ImmutableMap.<Locale, Integer>builder() .put(Locale.GERMAN, 1) .put(Locale.FRANCE, 2) .put(Locale.JAPAN, 3) .build();
  43. Collections – Immutable collections public static final Map<Locale, Integer> LOCALE_RANKS;

    static { Map<Locale, Integer> ranks = new LinkedHashMap<Locale, Integer>(); ranks.put(Locale.GERMAN, 1); ranks.put(Locale.FRANCE, 2); ranks.put(Locale.JAPAN, 3); LOCALE_RANKS = Collections.unmodifiableMap(ranks); } public static final Map<Locale, Integer> LOCALE_RANKS = ImmutableMap.of(Locale.GERMAN, 1, Locale.FRANCE, 2, Locale.JAPAN, 3); public static <K, V> ImmutableMap<K, V> of() public static <K, V> ImmutableMap<K, V> of(K k1, V v1) public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2) public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) public static <K, V> ImmutableMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) public static <K, V> Builder<K, V> builder()
  44. Collections – Immutable collections  ImmutableCollection  ImmutableList  ImmutableSet

     ImmutableMap  ImmutableSortedSet  ...  ImmutableMultimap  ImmutableBiMap  ImmutableMultiset  ImmutableClassToInstanceMap  ...
  45. Collections – Immutable collections Avantages ✔ Concurrent programming ✔ Clarity

    / simplicity ✔ Performance ✔ Programming errors detected early (fail fast) ✔ Defensive copying is un-needed ✔ Null-hostile Caveats ✔ Not deeply deeply immutable if elements are mutable
  46. Collections – BiMap public enum MilitaryRank { GENERAL, SOLDIER, NINJA;

    } public interface RankConverter { MilitaryRank toMilitaryRank(Job job); Job toJob(MilitaryRank rank); }
  47. Collections – BiMap public class RankConverterUsingSwitches implements RankConverter { public

    MilitaryRank toMilitaryRank(Job job) { switch (job) { case CEO: return MilitaryRank.GENERAL; case DEVELOPER: return MilitaryRank.SOLDIER; case DESIGNER: return MilitaryRank.NINJA; default: return null; } } public Job toJob(MilitaryRank rank) { switch (rank) { case GENERAL: return Job.CEO; case SOLDIER: return Job.DEVELOPER; case NINJA: return Job.DESIGNER; default: return null; } } }
  48. Collections – BiMap public class RankConverterUsingTwoMaps implements RankConverter { private

    Map<Job, MilitaryRank> jobToRank = Maps.newHashMap(); private Map<MilitaryRank, Job> rankToJob = Maps.newHashMap(); { putInBothMaps(Job.CEO, MilitaryRank.GENERAL); putInBothMaps(Job.DEVELOPER, MilitaryRank.NINJA); putInBothMaps(Job.DESIGNER, MilitaryRank.NINJA); } private void putInBothMaps(Job job, MilitaryRank rank) { jobToRank.put(job, rank); rankToJob.put(rank, job); } public MilitaryRank toMilitaryRank(Job job) { return jobToRank.get(job); } public Job toJob(MilitaryRank rank) { return rankToJob.get(rank); } }
  49. Collections – BiMap public class RankConverterUsingTwoMaps implements RankConverter { private

    Map<Job, MilitaryRank> jobToRank = Maps.newHashMap(); private Map<MilitaryRank, Job> rankToJob = Maps.newHashMap(); { putInBothMaps(Job.CEO, MilitaryRank.GENERAL); putInBothMaps(Job.DEVELOPER, MilitaryRank.NINJA); putInBothMaps(Job.DESIGNER, MilitaryRank.NINJA); } private void putInBothMaps(Job job, MilitaryRank rank) { jobToRank.put(job, rank); rankToJob.put(rank, job); } public MilitaryRank toMilitaryRank(Job job) { return jobToRank.get(job); } public Job toJob(MilitaryRank rank) { return rankToJob.get(rank); } }
  50. Collections – BiMap public class RankConverterUsingBiMap implements RankConverter { private

    BiMap<Job, MilitaryRank> jobToRank = EnumBiMap.create(ImmutableMap.of( Job.CEO, MilitaryRank.GENERAL, Job.DEVELOPER, MilitaryRank.NINJA, Job.DESIGNER, MilitaryRank.NINJA )); @Override public MilitaryRank toMilitaryRank(Job job) { return jobToRank.get(job); } @Override public Job toJob(MilitaryRank rank) { return jobToRank.inverse().get(rank); } }
  51. Collections – BiMap public class RankConverterUsingBiMap implements RankConverter { private

    BiMap<Job, MilitaryRank> jobToRank = EnumBiMap.create(ImmutableMap.of( Job.CEO, MilitaryRank.GENERAL, Job.DEVELOPER, MilitaryRank.NINJA, Job.DESIGNER, MilitaryRank.NINJA )); @Override public MilitaryRank toMilitaryRank(Job job) { return jobToRank.get(job); } @Override public Job toJob(MilitaryRank rank) { return jobToRank.inverse().get(rank); } } java.lang.IllegalArgumentException: value already present: NINJA at com.google.common.base.Preconditions.checkArgument(Preconditions.java:115) at com.google.common.collect.AbstractBiMap.putInBothMaps(AbstractBiMap.java:111) at com.google.common.collect.AbstractBiMap.put(AbstractBiMap.java:96) at com.google.common.collect.AbstractBiMap.putAll(AbstractBiMap.java:144) at com.google.common.collect.EnumBiMap.putAll(EnumBiMap.java:38) at com.google.common.collect.EnumBiMap.create(EnumBiMap.java:69)
  52. Collections – BiMap public class RankConverterUsingBiMap implements RankConverter { private

    BiMap<Job, MilitaryRank> jobToRank = EnumBiMap.create(ImmutableMap.of( Job.CEO, MilitaryRank.GENERAL, Job.DEVELOPER, MilitaryRank.SOLDIER, Job.DESIGNER, MilitaryRank.NINJA )); @Override public MilitaryRank toMilitaryRank(Job job) { return jobToRank.get(job); } @Override public Job toJob(MilitaryRank rank) { return jobToRank.inverse().get(rank); } }
  53. Collections – Multimap Map<Job, Collection<Employee>> getEmployeesPerJob(List<Employee> employees) { Map<Job, Collection<Employee>>

    map = Maps.newHashMap(); for (Employee employee : employees) { addToMap(map, employee.getJob(), employee); } return map; } void addToMap(Map<Job, Collection<Employee>> map, Job job, Employee employee) { Collection<Employee> employeesForJob = map.get(job); if (employeesForJob == null) { employeesForJob = Lists.newArrayList(); map.put(job, employeesForJob); } employeesForJob.add(employee); }
  54. Collections – Multimap Map<Job, Collection<Employee>> getEmployeesPerJob(List<Employee> employees) { Map<Job, Collection<Employee>>

    map = Maps.newHashMap(); for (Employee employee : employees) { addToMap(map, employee.getJob(), employee); } return map; } void addToMap(Map<Job, Collection<Employee>> map, Job job, Employee employee) { Collection<Employee> employeesForJob = map.get(job); if (employeesForJob == null) { employeesForJob = Lists.newArrayList(); map.put(job, employeesForJob); } employeesForJob.add(employee); }
  55. Collections – Multimap Map<Job, Collection<Employee>> getEmployeesPerJob(List<Employee> employees) { Multimap<Job, Employee>

    multimap = ArrayListMultimap.create(); for (Employee employee : employees) { multimap.put(employee.getJob(), employee); } return multimap.asMap(); }
  56. Functional Programming – Interfaces public interface Function<F, T> { T

    apply(@Nullable F input); } public interface Predicate<T> { boolean apply(@Nullable T input); }
  57. Functional Programming – Interfaces public class EmployeeNameFunction implements Function<Employee, String>

    { @Override public String apply(Employee employee) { return employee.getName(); } } public class EmployeeJobPredicate implements Predicate<Employee> { private final Job job; public EmployeeJobPredicate(Job job) { this.job = job; } @Override public boolean apply(Employee employee) { return employee.getJob() == job; } }
  58. Functional Programming – filter() / transform() List<String> getDesignerNames(List<Employee> employees) {

    List<String> names = new ArrayList<String>(); for (Employee employee : employees) { if (employee.getJob() == Job.DESIGNER) { names.add(employee.getName()); } } return names; }
  59. Functional Programming – filter() / transform() List<String> getDesignerNames(List<Employee> employees) {

    Iterable<Employee> designers = Iterables.filter(employees, new Predicate<Employee>() { @Override public boolean apply(Employee employee) { return employee.getJob() == Job.DESIGNER; } } ); Iterable<String> names = Iterables.transform(designers, new Function<Employee, String>() { @Override public String apply(Employee employee) { return employee.getName(); } } ); return ImmutableList.copyOf(names); }
  60. Functional Programming – filter() / transform() List<String> getDesignerNames(List<Employee> employees) {

    Iterable<Employee> designers = Iterables.filter(employees, new EmployeeJobPredicate(Job.DESIGNER)); Iterable<String> names = Iterables.transform(designers, new EmployeeNameFunction()); return ImmutableList.copyOf(names); }
  61. Functional Programming – Best Practices public final class EmployeePredicates {

    private EmployeePredicates() {} public static Predicate<Employee> hasJob(Job job) { return new EmployeeJobPredicate(job); } private static class EmployeeJobPredicate implements Predicate<Employee> { final Job job; EmployeeJobPredicate(Job job) { this.job = job; } @Override public boolean apply(Employee employee) { return employee.getJob() == job; } } }
  62. Functional Programming – Best Practices public final class EmployeeFunctions {

    private EmployeeFunctions() {} public static Function<Employee, String> getName() { return EmployeeNameFunction.INSTANCE; } private static class EmployeeNameFunction implements Function<Employee, String> { static final EmployeeNameFunction INSTANCE = new EmployeeNameFunction(); @Override public String apply(Employee employee) { return employee.getName(); } } }
  63. Functional Programming – Best Practices public final class EmployeeFunctions {

    private EmployeeFunctions() {} public static Function<Employee, String> getName() { return EmployeeNameFunction.INSTANCE; } private enum EmployeeNameFunction implements Function<Employee, String> { INSTANCE; @Override public String apply(Employee employee) { return employee.getName(); } } }
  64. Functional Programming – Best Practices List<String> getDesignerNames(List<Employee> employees) { Iterable<Employee>

    designers = Iterables.filter(employees, EmployeePredicates.hasJob(Job.DESIGNER)); Iterable<String> names = Iterables.transform(designers, EmployeeFunctions.getName()); return ImmutableList.copyOf(names); }
  65. Functional Programming – Predicate composition List<String> getDesignerNames(List<Employee> employees) { List<String>

    designerNames = new ArrayList<String>(); for (Employee employee : employees) { if (employee != null && employee.getJob() == Job.DESIGNER) { designerNames.add(employee.getName()); } } return designerNames; }
  66. Functional Programming – Predicate composition List<String> getDesignerNames(List<Employee> employees) { Iterable<Employee>

    designers = Iterables.filter(employees, Predicates.and( Predicates.notNull(), EmployeePredicates.hasJob(Job.DESIGNER)) ); Iterable<String> names = Iterables.transform(designers, EmployeeFunctions.getName()); return ImmutableList.copyOf(names); }
  67. Functional Programming – Predicate composition public final class EmployeePredicates {

    private EmployeePredicates() {} public static Predicate<Employee> hasJob(Job job) { return Predicates.compose( Predicates.equalTo(job), EmployeeFunctions.getJob()); } } public final class EmployeeFunctions { [...] public static Function<Employee, Job> getJob() { return EmployeeJobFunction.INSTANCE; } private enum EmployeeJobFunction implements Function<Employee, Job> { INSTANCE; @Override public Job apply(Employee employee) { return employee.getJob(); } } }
  68. Functional Programming – Multimaps.index() Map<Job, Collection<Employee>> getEmployeesPerJob(List<Employee> employees) { Multimap<Job,

    Employee> multimap = ArrayListMultimap.create(); for (Employee employee : employees) { multimap.put(employee.getJob(), employee); } return multimap.asMap(); }
  69. Miscellaneous – Charsets byte[] bytes; try { bytes = string.getBytes("UTF-8");

    } catch (UnsupportedEncodingException e) { // how can this possibly happen? throw new AssertionError(e); }
  70. Miscellaneous – Charsets byte[] bytes; try { bytes = string.getBytes("UTF-8");

    } catch (UnsupportedEncodingException e) { // how can this possibly happen? throw new AssertionError(e); }
  71. Miscellaneous – Charsets byte[] bytes; try { bytes = string.getBytes("UTF-8");

    } catch (UnsupportedEncodingException e) { // how can this possibly package happen? throw new AssertionError(e); } import com.google.common.base.Charsets; [...] byte[] bytes = string.getBytes(Charsets.UTF_8); http://stackoverflow.com/questions/1684040/java-why-charset-names-are-not-constants
  72. Miscellaneous – I/O public List<String> readLines(File file) throws IOException {

    BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(file)); } catch (FileNotFoundException ex) { throw new RuntimeException(ex); } try { List<String> result = Lists.newArrayList(); while (true) { String line = reader.readLine(); if (line == null) { break; } result.add(line.trim()); } return result; } finally { reader.close(); } }
  73. Miscellaneous – I/O public List<String> readLines(File file) throws IOException {

    BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(file)); } catch (FileNotFoundException ex) { throw new RuntimeException(ex); } try { List<String> result = Lists.newArrayList(); while (true) { String line = reader.readLine(); if (line == null) { break; } result.add(line.trim()); } return result; } finally { reader.close(); } }
  74. Miscellaneous – I/O import com.google.common.io.Files; public List<String> readLines(File file) throws

    IOException { return Files.readLines(file, Charsets.UTF_8); } ✔ Files.move() ✔ Files.copy() ✔ Files.touch() ✔ Files.createTempDir() • ...
  75. Miscellaneous – @VisibleForTesting public List<Hero> getFemaleHeroes() { List<Hero> heroes =

    getAllHeroes(); return filterHeroesBySex(heroes, Sex.FEMALE); } private List<Hero> filterHeroesBySex(List<Hero> heroes, Sex sex) { return ImmutableList.copyOf(Iterables.filter(heroes, new SexPredicate(sex))); }
  76. Miscellaneous – @VisibleForTesting public List<Hero> getFemaleHeroes() { List<Hero> heroes =

    getAllHeroes(); return filterHeroesBySex(heroes, Sex.FEMALE); } private List<Hero> filterHeroesBySex(List<Hero> heroes, Sex sex) { return ImmutableList.copyOf(Iterables.filter(heroes, new SexPredicate(sex))); }
  77. Miscellaneous – @VisibleForTesting public List<Hero> getFemaleHeroes() { List<Hero> heroes =

    getAllHeroes(); return filterHeroesBySex(heroes, Sex.FEMALE); } private List<Hero> filterHeroesBySex(List<Hero> heroes, Sex sex) { return ImmutableList.copyOf(Iterables.filter(heroes, new SexPredicate(sex))); } public List<Hero> getFemaleHeroes() { List<Hero> heroes = getAllHeroes(); return filterHeroesBySex(heroes, Sex.FEMALE); } @VisibleForTesting List<Hero> filterHeroesBySex(List<Hero> heroes, Sex sex) { return ImmutableList.copyOf(Iterables.filter(heroes, new SexPredicate(sex))); }
  78. Miscellaneous – Ordering final Comparator<Marque> MARQUE_COMPARATOR = new Comparator<Marque> ()

    { static final Map<Marque, Integer> RANK = new HashMap<Marque, Integer>(); static { RANK.put(Marque.SAMSUNG, 1); RANK.put(Marque.HTC, 2); RANK.put(Marque.APPLE, 3); } @Override public int compare(Marque o1, Marque o2) { Integer i1 = RANK.get(o1); Integer i2 = RANK.get(o2); if (i1 == null) { i1 = Integer.MAX_VALUE; } if (i2 == null) { i2 = Integer.MAX_VALUE; } return i1.compareTo(i2); } };
  79. Miscellaneous – Ordering final Comparator<Marque> MARQUE_COMPARATOR = new Comparator<Marque> ()

    { static final Map<Marque, Integer> RANK = new HashMap<Marque, Integer>(); static { RANK.put(Marque.SAMSUNG, 1); RANK.put(Marque.HTC, 2); RANK.put(Marque.APPLE, 3); } @Override public int compare(Marque o1, Marque o2) { Integer i1 = RANK.get(o1); Integer i2 = RANK.get(o2); if (i1 == null) { i1 = Integer.MAX_VALUE; } if (i2 == null) { i2 = Integer.MAX_VALUE; } return i1.compareTo(i2); } }; final Ordering<Marque> MARQUE_ORDERING = Ordering.explicit(Marque.SAMSUNG, Marque.HTC, Marque.APPLE) .nullsLast();
  80. Miscellaneous – Throwables T doSomething() { try { return someMethodThatCouldThrowAnything();

    } catch (IKnowWhatToDoWithThisException e) { return handle(e); } catch (Throwable t) { throw Throwables.propagate(t); } }
  81. Miscellaneous – Resources Official Website http://code.google.com/p/guava-libraries/ StackOverflow http://stackoverflow.com/questions/tagged/guava Articles http://codemunchies.com/tag/google-collections/

    http://scaramoche.blogspot.com/search/label/guava http://jnb.ociweb.com/jnb/jnbApr2010.html Presentations at GTUG (August 2008 - some APIs may have changed) http://www.youtube.com/watch?v=ZeO_J2OcHYM http://www.youtube.com/watch?v=9ni_KEkHfto PDF of a presentation given by Kevin Bourrillion, Guava's lead developer http://guava-libraries.googlecode.com/files/Guava_for_Netflix_.pdf
  82. Recap ✔ Awesome library ✔ Very well maintained ✔ Supported

    on GWT / Android ✔ Performant ✔ Promotes good development practices Also see http://stackoverflow.com/questions/4542550/what-are-the-big-improvements-between-guava-and-apache-equivalent-libraries