Slide 1

Slide 1 text

Cleaner code with Guava @alexsimonescu

Slide 2

Slide 2 text

http://bit.ly/204MhVV

Slide 3

Slide 3 text

Alexandru Simonescu http://blog.alexsimo.com http://alexsimo.com @alexsimonescu [email protected] “Do what you love. Love what you do.” - Ray Bradbury

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Our mission - Write cleaner code - Be more productive - Open mind to new workflows - Discover new types

Slide 6

Slide 6 text

What is Guava?

Slide 7

Slide 7 text

What is Guava? - Google’s core Java library - Utilities classes and methods - Used in Google and Netflix

Slide 8

Slide 8 text

Guava components hashing event bus math reflection networking annotations basic utilities collections concurrency comparison strings primitives ranges functional I/O cache

Slide 9

Slide 9 text

Guava components hashing event bus math reflection networking annotations basic utilities collections concurrency ordering strings primitives ranges functional I/O cache

Slide 10

Slide 10 text

Basic

Slide 11

Slide 11 text

We all love null

Slide 12

Slide 12 text

But what “null” really means?

Slide 13

Slide 13 text

Failure? Success? Absence?

Slide 14

Slide 14 text

Domain problems in Domain Driven Design

Slide 15

Slide 15 text

Null use cases - None - Represent some sort of absence - Value not found - Something went wrong :(

Slide 16

Slide 16 text

Your task 2. Find better alternative 1. Identify what really means enums constants builders

Slide 17

Slide 17 text

Optional

Slide 18

Slide 18 text

Optional - may contain non null value (reference is present) - may contain nothing (reference is absent)

Slide 19

Slide 19 text

Optional name = Optional.of("Alex");
 Optional age = Optional.absent();
 Optional car = Optional.fromNullable(null);
 
 
 System.out.println(String.format("Name exists: %s", name.isPresent())); System.out.println(String.format("Age or default: %s", age.or(0))); 
 System.out.println(String.format("Car: %s", car.toString()));

Slide 20

Slide 20 text

Optional goodness - Increases readability - Makes you analyze absent case - Never forget if a value can be null - Forces you to unwrap Optional

Slide 21

Slide 21 text

Strings

Slide 22

Slide 22 text

Strings goodness - Join and split strings easily - Characters matching helpers - Safe charsets

Slide 23

Slide 23 text

List fruits = Arrays.asList(
 null, "banana", null, "blackberry", null, "guava");
 String joined = Joiner.on(", ").skipNulls().join(fruits);
 
 // banana, blackberry, guava String contacts = "alex:123;bob:321;ana:333;daniel:890;victor: 456";
 
 Splitter.MapSplitter mapSplitter = Splitter.on(";").withKeyValueSeparator(":");
 Map descompose = mapSplitter.split(contacts);
 for (Map.Entry f : descompose.entrySet()) {
 println(String.format("%s -> %s", f.getKey(), f.getValue()));
 } // alex -> 123 // bob -> 321 // ana -> 333

Slide 24

Slide 24 text

Person person = persons.get(ONE);
 StringBuffer sb = new StringBuffer();
 sb.append(person.getSuffix());
 sb.append(" --- ");
 sb.append(person.getName());
 sb.append(" --- ");
 sb.append(person.getPhoneNumber());
 String phone = CharMatcher.DIGIT.retainFrom(sb);


Slide 25

Slide 25 text

Objects

Slide 26

Slide 26 text

Objects goodness - Easy toString(), hashCode() and equals() - Cleaner compareTo() - Objects comparator

Slide 27

Slide 27 text

@Override
 public boolean equals(Object o) {
 if (this == o) return true;
 if (o == null || getClass() != o.getClass()) return false;
 
 Person person = (Person) o;
 
 if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) return false;
 if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) return false;
 if (name != null ? !name.equals(person.name) : person.name != null) return false;
 if (suffix != null ? !suffix.equals(person.suffix) : person.suffix != null) return false;
 if (phoneNumber != null ? !phoneNumber.equals(person.phoneNumber) : person.phoneNumber != null) return false;
 if (email != null ? !email.equals(person.email) : person.email != null) return false;
 if (website != null ? !website.equals(person.website) : person.website != null) return false;
 if (address != null ? !address.equals(person.address) : person.address != null) return false;
 return car != null ? car.equals(person.car) : person.car == null;
 
 }
 
 @Override
 public int hashCode() {
 int result = firstName != null ? firstName.hashCode() : 0;
 result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
 result = 31 * result + (name != null ? name.hashCode() : 0);
 result = 31 * result + (suffix != null ? suffix.hashCode() : 0);
 result = 31 * result + (phoneNumber != null ? phoneNumber.hashCode() : 0);
 result = 31 * result + (email != null ? email.hashCode() : 0);
 result = 31 * result + (website != null ? website.hashCode() : 0);
 result = 31 * result + (address != null ? address.hashCode() : 0);
 result = 31 * result + (car != null ? car.hashCode() : 0);
 return result;
 }

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

@Override
 public boolean equals(Object o) {
 if (this == o) return true;
 if (o == null || getClass() != o.getClass()) return false;
 
 Person person = (Person) o;
 
 if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) return false;
 if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) return false;
 if (name != null ? !name.equals(person.name) : person.name != null) return false;
 if (suffix != null ? !suffix.equals(person.suffix) : person.suffix != null) return false;
 if (phoneNumber != null ? !phoneNumber.equals(person.phoneNumber) : person.phoneNumber != null) return false;
 if (email != null ? !email.equals(person.email) : person.email != null) return false;
 if (website != null ? !website.equals(person.website) : person.website != null) return false;
 if (address != null ? !address.equals(person.address) : person.address != null) return false;
 return car != null ? car.equals(person.car) : person.car == null;
 
 }
 
 @Override
 public int hashCode() {
 int result = firstName != null ? firstName.hashCode() : 0;
 result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
 result = 31 * result + (name != null ? name.hashCode() : 0);
 result = 31 * result + (suffix != null ? suffix.hashCode() : 0);
 result = 31 * result + (phoneNumber != null ? phoneNumber.hashCode() : 0);
 result = 31 * result + (email != null ? email.hashCode() : 0);
 result = 31 * result + (website != null ? website.hashCode() : 0);
 result = 31 * result + (address != null ? address.hashCode() : 0);
 result = 31 * result + (car != null ? car.hashCode() : 0);
 return result;
 }

Slide 30

Slide 30 text

@Override
 public String toString() {
 return MoreObjects.toStringHelper(this)
 .add("firstName", firstName)
 .add("lastName", lastName)
 .add("name", name)
 .add("suffix", suffix)
 .add("phoneNumber", phoneNumber)
 .add("email", email)
 .add("website", website)
 .add("address", address.toString())
 .toString();
 }

Slide 31

Slide 31 text

@Override
 public boolean equals(Object object) {
 
 if (object instanceof Person) {
 Person that = (Person) object;
 return Objects.equal(this.name, that.name)
 && Objects.equal(this.firstName, that.firstName)
 && Objects.equal(this.email, that.email);
 }
 return false;
 }
 
 @Override
 public int hashCode() {
 return Objects.hashCode(name, firstName, email);
 }

Slide 32

Slide 32 text

@Override
 public int compareTo(Person o) {
 return ComparisonChain.start()
 .compare(this.name, o.name)
 .compare(this.firstName, o.firstName)
 .compare(this.email, o.email)
 .result();
 }

Slide 33

Slide 33 text

Bonus!

Slide 34

Slide 34 text

public static void main(String[] args) {
 
 Stopwatch stopwatch = Stopwatch.createStarted();
 
 List pers = PersonRepository.getByLimit(50);
 
 Iterable dtos = from(pers).transform(personToDto);
 
 from(personDtos).forEach(printer);
 
 long nanos = stopwatch.elapsed(TimeUnit.NANOSECONDS);
 }

Slide 35

Slide 35 text

Preconditions

Slide 36

Slide 36 text

Preconditions goodness - Validate arguments - Check for null - Check elements in Lists, String or Array

Slide 37

Slide 37 text

import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Preconditions.checkState;
 
 public class PreconditionsSample { 
 public static void main(String[] args) { 
 checkState(args.length > 0, "Too less parameters”); 
 checkNotNull(args, "You have to pass some parameters");
 }
 }


Slide 38

Slide 38 text

Ordering

Slide 39

Slide 39 text

Ordering goodness - Ordering is a special Comparator instance - Guava’s fluent Comparator class - Chaining methods

Slide 40

Slide 40 text

Ordering bySuffix = new Ordering() {
 @Override
 public int compare(Person p1, Person p2) {
 return p1.getSuffix().compareTo(p2.getSuffix());
 }
 };
 Ordering byNameLength = new Ordering() {
 @Override
 public int compare(Person p1, Person p2) {
 return Ints.compare(p1.getName().length(), p2.getName().length());
 }
 };
 
 List persons = PersonRepository.instance().getByLimit(50);
 Collections.sort(persons, byNameLength.compound(bySuffix));

Slide 41

Slide 41 text

Collections

Slide 42

Slide 42 text

Collection goodness - New collections not included in JDK - Immutable collections

Slide 43

Slide 43 text

Why immutable? - Thread safe: no race conditions - More memory efficient that mutable alternative - Safe for use by untrusted libraries - Guava collection types doesn’t allow nulls

Slide 44

Slide 44 text

New collection types - Multiset - Multimap - BiMap - Table - ClassToInstanceMap - RangeSet

Slide 45

Slide 45 text

Multiset - Generalization of the notion of Set - Members allowed to appear more than once - Order is irrelevant

Slide 46

Slide 46 text

Multimap - Associates keys to arbitrary values - Alternative to Map> or Map> A -> 1 A -> 2 A -> 4 B -> 3 C -> 5 A -> [1, 2, 4] B -> 3 C -> 5

Slide 47

Slide 47 text

Bimap - Map values back to keys - Alternative to keep in sync two Map

Slide 48

Slide 48 text


 Person p1 = new Person("Alex", "Simonescu");
 Person p2 = new Person("Josh", "Block");
 
 BiMap emailPerson = HashBiMap.create();
 emailPerson.put("[email protected]", p1);
 emailPerson.put("[email protected]", p2);
 
 String p1Email = emailPerson.inverse().get(p1);


Slide 49

Slide 49 text

Table - Really a Table collection. Surprised? - Implementations as: • HashBasedTable, • TreeBasedTable, • ImmutableBasedTable • ArrayTable

Slide 50

Slide 50 text

String[] names = {"Bob", "Alice", "Andy", "Carol", "Ben"};
 
 // Table of names
 Table table = HashBasedTable.create();
 
 // First letter is a row key, length is a column key
 for (String name : names) {
 table.put(name.charAt(0), name.length(), name);
 }
 
 // Value corresponding to the given row and column keys
 table.get('A', 5); // -> Alice
 table.get('B', 3); // -> Ben
 
 // Set of column keys that have one or more values in the table
 table.columnKeySet(); // -> [4, 5, 3]
 
 // View of all mappings that have the given row key
 table.row('A'); // -> {4=Andy, 5=Alice}

Slide 51

Slide 51 text

ClassToInstance - Map types to values of that type - No need of getInstance(Class) and T putInstance(Class, T)

Slide 52

Slide 52 text

ClassToInstanceMap numbers = MutableClassToInstanceMap.create();
 
 numbers.putInstance(Integer.class, Integer.valueOf(0));
 numbers.putInstance(Double.class, Double.valueOf(1));
 numbers.putInstance(Float.class, Float.valueOf(3)); double myNum = numbers.getInstance(Double.class);

Slide 53

Slide 53 text

No content

Slide 54

Slide 54 text

Collection Utils

Slide 55

Slide 55 text

Collections hierarchy interface Iterable interface Collection interface Set interface List interface Queue

Slide 56

Slide 56 text

Static Constructors 
 List list = Lists.newArrayList();
 
 
 Map map = Maps.newLinkedHashMap();
 
 
 Set set = Sets.newHashSet(repo.getByLimit(50));
 
 
 List elements = Lists.newArrayList("alpha", "beta", "gamma");

Slide 57

Slide 57 text

Iterables 
 frequency(Iterable object)
 
 
 concat(Iterable)
 
 
 partition(Iterable)
 
 
 getFirst(Iterable, default)

Slide 58

Slide 58 text

Iterables Collections style 
 addAll(Collection addTo, Iterable toAdd)
 
 
 removeAll(Iterable removeFrom, Collection toRemove)
 
 
 contains(Iterable, Object) get(Iterable, int) 
 
 retainAll(Iterable removeFrom, Collection toRetain)

Slide 59

Slide 59 text

Sets 
 union(Set, Set) intersection(Set, Set) difference(Set, Set) symmetricDifference(Set, Set) cartesianProduct(List) powerSet()

Slide 60

Slide 60 text

Functional

Slide 61

Slide 61 text

Functional goodness - Kind of functional style on Java - Still not Scala - Handy filtering and transforming collections

Slide 62

Slide 62 text

Functional concepts - Function —> A => B - Predicate —> T => Boolean

Slide 63

Slide 63 text

Sometimes imperative version is more readable, concrete and efficient. Functional danger zone

Slide 64

Slide 64 text

List states = Lists.newArrayList(
 new State("MT", false),
 new State("ID", false),
 new State("WY", false),
 new State("SD", false),
 new State("NE", false),
 new State("WI", false),
 new State("IN", false),
 new State("TX", false),
 new State("CA", true),
 new State("AZ", true),
 new State("NM", true),
 new State("AR", true),
 new State("IL", true),
 new State("IA", true)); Predicate withI = state -> state.getAbbreviation().startsWith("I");
 Predicate isExpanded = state -> state.isExpanded();
 
 Collection filtered = filter(states, or(withI, not(isExpanded)));

Slide 65

Slide 65 text

Function emailToUpper = person -> {
 person.setEmail(person.getEmail().toUpperCase());
 return person;
 };
 
 Function toUsername = person -> {
 String[] chunks = person.getEmail().split("@");
 return chunks[0];
 };
 
 List people = getPeople();
 Collection usernames = transform(people, compose(toUsername, emailToUpper));

Slide 66

Slide 66 text

Predicate isNotNull = Predicates.notNull();
 Predicate isPerson = Predicates.instanceOf(Person.class);
 Predicate startsWithA = person -> person.getName().toLowerCase().startsWith("a");
 Predicate hasCar = person -> person.getCar().isPresent();
 
 Function toCarName = person -> person.getCar().get().getName();
 
 ImmutableList people = ImmutableList.copyOf(getPeople());
 
 List cars = FluentIterable
 .from(people)
 .filter(isNotNull)
 .filter(isPerson)
 .filter(startsWithA)
 .filter(hasCar)
 .transform(toCarName)
 .toList();

Slide 67

Slide 67 text

Concurrency

Slide 68

Slide 68 text

Concurrency goodness - Future on steroids - Allows registering callback when finished - Provides more executors

Slide 69

Slide 69 text

ExecutorService executorService = Executors.newFixedThreadPool(1);
 ListeningExecutorService executor = MoreExecutors.listeningDecorator(executorService);
 
 ListenableFuture future = executor.submit(() -> {
 Thread.sleep(1000);
 return "Task completed";
 });
 
 future.addListener(() -> runOnCompletion(), executor);


Slide 70

Slide 70 text

ExecutorService executorService = Executors.newCachedThreadPool();
 ListeningExecutorService executor = MoreExecutors.listeningDecorator(executorService);
 
 ListenableFuture future = executor.submit(() -> {
 Thread.sleep(1000);
 return "Task completed";
 });
 
 Futures.addCallback(future, new FutureCallback() {
 @Override
 public void onSuccess(String s) {
 System.out.println("Task succeed: " + s);
 }
 
 @Override
 public void onFailure(Throwable throwable) {
 System.out.println("Task failed");
 }
 }, executor);

Slide 71

Slide 71 text

Guava Darkside

Slide 72

Slide 72 text

Guava Darkside - Heavy library —> use Proguard or similar - Lot’s of utilities —> extract only needed

Slide 73

Slide 73 text

https://github.com/android10/arrow

Slide 74

Slide 74 text

https://github.com/alexsimo/toolbelt

Slide 75

Slide 75 text

Guava vs Java 8

Slide 76

Slide 76 text

Writing clean code is your responsibility

Slide 77

Slide 77 text

+ Inspiring people

Slide 78

Slide 78 text

Questions?

Slide 79

Slide 79 text

Sample project https://github.com/alexsimo/guava-demo

Slide 80

Slide 80 text

Links • http://www.tfnico.com/presentations/google-guava • http://gdg-krakow.github.io/google-io-ext-2012-guava/ • http://www.baeldung.com/category/guava/ • https://robinst.github.io/guava-java8-presentation/#/

Slide 81

Slide 81 text

Thanks! @alexsimonescu