Slide 1

Slide 1 text

Guava by Example (Google's Core Libraries for Java) Etienne Neveu 04/03/2011

Slide 2

Slide 2 text

Base com.google.common.base Collections com.google.common.collect Functional programming Miscellaneous

Slide 3

Slide 3 text

Base com.google.common.base Collections com.google.common.collect Functional programming Miscellaneous

Slide 4

Slide 4 text

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 }

Slide 5

Slide 5 text

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; }

Slide 6

Slide 6 text

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; }

Slide 7

Slide 7 text

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; }

Slide 8

Slide 8 text

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); }

Slide 9

Slide 9 text

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(); }

Slide 10

Slide 10 text

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(); }

Slide 11

Slide 11 text

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); }

Slide 12

Slide 12 text

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(); }

Slide 13

Slide 13 text

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(); }

Slide 14

Slide 14 text

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; } }

Slide 15

Slide 15 text

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; } }

Slide 16

Slide 16 text

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 checkNotNull(T reference) { if (reference == null) { throw new NullPointerException(); } return reference; }

Slide 17

Slide 17 text

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); } }

Slide 18

Slide 18 text

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/

Slide 19

Slide 19 text

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 }

Slide 20

Slide 20 text

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! }

Slide 21

Slide 21 text

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 }

Slide 22

Slide 22 text

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 }

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

Base – Joiner (MapJoiner) Map map = new HashMap(); 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

Slide 28

Slide 28 text

Base – CharMatcher We want to accept: 0 1 2 3 4 5 6 7 8 9 - _

Slide 29

Slide 29 text

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);

Slide 30

Slide 30 text

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));

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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);

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

Base com.google.common.base Collections com.google.common.collect Functional programming Miscellaneous

Slide 37

Slide 37 text

Collections – Static factories // standard ArrayList List> maps = new ArrayList>();

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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> maps = newArrayList(); // another static factory (good naming conventions) List names = newArrayListWithExpectedSize(42); List names = newArrayListWithCapacity(42); // from var args List names = newArrayList("Tony Stark", "James Rhodes"); // from Iterable Iterable namesIterable = … List names = newArrayList(namesIterable); // Sets Set employees = newHashSet(); // Maps Map employeesById = newHashMapWithExpectedSize(5);

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

Collections – Immutable collections public static final Map LOCALE_RANKS; static { Map ranks = new LinkedHashMap(); 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_RANKS; static { ImmutableMap.Builder ranks = ImmutableMap.builder(); ranks.put(Locale.GERMAN, 1); ranks.put(Locale.FRANCE, 2); ranks.put(Locale.JAPAN, 3); LOCALE_RANKS = ranks.build(); }

Slide 48

Slide 48 text

Collections – Immutable collections public static final Map LOCALE_RANKS; static { Map ranks = new LinkedHashMap(); 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_RANKS; static { ImmutableMap.Builder 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_RANKS = ImmutableMap.builder() .put(Locale.GERMAN, 1) .put(Locale.FRANCE, 2) .put(Locale.JAPAN, 3) .build();

Slide 49

Slide 49 text

Collections – Immutable collections public static final Map LOCALE_RANKS; static { Map ranks = new LinkedHashMap(); 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_RANKS = ImmutableMap.of(Locale.GERMAN, 1, Locale.FRANCE, 2, Locale.JAPAN, 3); public static ImmutableMap of() public static ImmutableMap of(K k1, V v1) public static ImmutableMap of(K k1, V v1, K k2, V v2) public static ImmutableMap of(K k1, V v1, K k2, V v2, K k3, V v3) public static ImmutableMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) public static ImmutableMap of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) public static Builder builder()

Slide 50

Slide 50 text

Collections – Immutable collections  ImmutableCollection  ImmutableList  ImmutableSet  ImmutableMap  ImmutableSortedSet  ...  ImmutableMultimap  ImmutableBiMap  ImmutableMultiset  ImmutableClassToInstanceMap  ...

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

Collections – BiMap public enum MilitaryRank { GENERAL, SOLDIER, NINJA; } public interface RankConverter { MilitaryRank toMilitaryRank(Job job); Job toJob(MilitaryRank rank); }

Slide 53

Slide 53 text

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; } } }

Slide 54

Slide 54 text

Collections – BiMap public class RankConverterUsingTwoMaps implements RankConverter { private Map jobToRank = Maps.newHashMap(); private Map 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); } }

Slide 55

Slide 55 text

Collections – BiMap public class RankConverterUsingTwoMaps implements RankConverter { private Map jobToRank = Maps.newHashMap(); private Map 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); } }

Slide 56

Slide 56 text

Collections – BiMap public class RankConverterUsingBiMap implements RankConverter { private BiMap 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); } }

Slide 57

Slide 57 text

Collections – BiMap public class RankConverterUsingBiMap implements RankConverter { private BiMap 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)

Slide 58

Slide 58 text

Collections – BiMap public class RankConverterUsingBiMap implements RankConverter { private BiMap 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); } }

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

Collections – Multimap Map> getEmployeesPerJob(List employees) { Multimap multimap = ArrayListMultimap.create(); for (Employee employee : employees) { multimap.put(employee.getJob(), employee); } return multimap.asMap(); }

Slide 62

Slide 62 text

Base com.google.common.base Collections com.google.common.collect Functional programming Miscellaneous

Slide 63

Slide 63 text

Functional Programming – Interfaces public interface Function { T apply(@Nullable F input); } public interface Predicate { boolean apply(@Nullable T input); }

Slide 64

Slide 64 text

Functional Programming – Interfaces public class EmployeeNameFunction implements Function { @Override public String apply(Employee employee) { return employee.getName(); } } public class EmployeeJobPredicate implements Predicate { private final Job job; public EmployeeJobPredicate(Job job) { this.job = job; } @Override public boolean apply(Employee employee) { return employee.getJob() == job; } }

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

Functional Programming – filter() / transform() List getDesignerNames(List employees) { Iterable designers = Iterables.filter(employees, new EmployeeJobPredicate(Job.DESIGNER)); Iterable names = Iterables.transform(designers, new EmployeeNameFunction()); return ImmutableList.copyOf(names); }

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

Functional Programming – Best Practices List getDesignerNames(List employees) { Iterable designers = Iterables.filter(employees, EmployeePredicates.hasJob(Job.DESIGNER)); Iterable names = Iterables.transform(designers, EmployeeFunctions.getName()); return ImmutableList.copyOf(names); }

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

Functional Programming – Predicate composition List getDesignerNames(List employees) { Iterable designers = Iterables.filter(employees, Predicates.and( Predicates.notNull(), EmployeePredicates.hasJob(Job.DESIGNER)) ); Iterable names = Iterables.transform(designers, EmployeeFunctions.getName()); return ImmutableList.copyOf(names); }

Slide 74

Slide 74 text

Functional Programming – Predicate composition public final class EmployeePredicates { private EmployeePredicates() {} public static Predicate hasJob(Job job) { return Predicates.compose( Predicates.equalTo(job), EmployeeFunctions.getJob()); } } public final class EmployeeFunctions { [...] public static Function getJob() { return EmployeeJobFunction.INSTANCE; } private enum EmployeeJobFunction implements Function { INSTANCE; @Override public Job apply(Employee employee) { return employee.getJob(); } } }

Slide 75

Slide 75 text

Functional Programming – Multimaps.index() Map> getEmployeesPerJob(List employees) { Multimap multimap = ArrayListMultimap.create(); for (Employee employee : employees) { multimap.put(employee.getJob(), employee); } return multimap.asMap(); }

Slide 76

Slide 76 text

Functional Programming – Multimaps.index() Map> getEmployeesPerJob(List employees) { ImmutableListMultimap multimap = Multimaps.index(employees, EmployeeFunctions.getJob()); return multimap.asMap(); }

Slide 77

Slide 77 text

Base com.google.common.base Collections com.google.common.collect Functional programming Miscellaneous

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

Miscellaneous – I/O import com.google.common.io.Files; public List readLines(File file) throws IOException { return Files.readLines(file, Charsets.UTF_8); }

Slide 84

Slide 84 text

Miscellaneous – I/O import com.google.common.io.Files; public List readLines(File file) throws IOException { return Files.readLines(file, Charsets.UTF_8); } ✔ Files.move() ✔ Files.copy() ✔ Files.touch() ✔ Files.createTempDir() ● ...

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

Miscellaneous – Ordering final Comparator MARQUE_COMPARATOR = new Comparator () { static final Map RANK = new HashMap(); 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); } };

Slide 89

Slide 89 text

Miscellaneous – Ordering final Comparator MARQUE_COMPARATOR = new Comparator () { static final Map RANK = new HashMap(); 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_ORDERING = Ordering.explicit(Marque.SAMSUNG, Marque.HTC, Marque.APPLE) .nullsLast();

Slide 90

Slide 90 text

Miscellaneous – Throwables T doSomething() { try { return someMethodThatCouldThrowAnything(); } catch (IKnowWhatToDoWithThisException e) { return handle(e); } catch (Throwable t) { throw Throwables.propagate(t); } }

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

Thanks!