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

Cleaner code with Guava

Cleaner code with Guava

Cleaner code with Guava:
Guava features that can make your code cleaner

Avatar for Alexandru Simonescu

Alexandru Simonescu

February 28, 2016
Tweet

More Decks by Alexandru Simonescu

Other Decks in Programming

Transcript

  1. but we use nulls.. why? _to represent some sort of

    absence _where there might have been a value _there is none _value can’t be found _something went wrong
  2. pros _increases readability _makes you analyze absent case _never forget

    if a value can be null _forces you to unwrap Optional
  3. where to use preconditions? validate arguments to methods checkArgument(boolean); IllegalArgumentException

    check for nulls checkNotNull(T); NullPointerException or <T> check valid elements in lists, string or array checkElementIndexI (int index, int size); IndexOutOfBoundsException check for valid positions in list, string or array (really usefull?) checkPositionIndex (int index, int size); IndexOutOfBoundsException
  4. some tips _can convert Comparator into Ordering with Ordering.from(Comparator) _skip

    Comparator in favor of extending Ordering abstract class _complex ordering by chaining Orderings List<Person> persons = PersonRepository.instance() .getByLimit(50); Ordering toString = Ordering.usingToString(); Collections.sort(persons, toString); Printer.print(persons);
  5. implement custom orderings Ordering<Person> orderBySuffix = new Ordering<Person>() { @Override

    public int compare(Person p1, Person p2) { return p1.getSuffix().compareTo(p2.getSuffix()); } }; List<Person> persons = PersonRepository.instance().getByLimit(50); Collections.sort(persons, orderBySuffix); Printer.print(persons);
  6. chain orderings Ordering<Person> bySuffix = new Ordering<Person>() { @Override public

    int compare(Person p1, Person p2) { return p1.getSuffix().compareTo(p2.getSuffix()); } }; Ordering<Person> byNameLength = new Ordering<Person>() { @Override public int compare(Person p1, Person p2) { return Ints.compare(p1.getName().length(), p2.getName().length()); } }; List<Person> persons = PersonRepository.instance().getByLimit(50); Collections.sort(persons, byNameLength.compound(bySuffix)); Printer.print(persons);
  7. equals() Objects.equal("a", "a"); Objects.equal(null, "a"); Objects.equal("a", null); Objects.equal(null, null); hashCode()

    Objects.hashCode(field1, field2, ..., fieldn) toString() MoreObjects.toStringHelper(this) .add("x", 1) .toString(); compareTo() public int compareTo(Foo that) { return ComparisonChain.start() .compare(this.aString, that.aString) .compare(this.anInt, that.anInt) .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast()) .result(); }
  8. joiner and splitter Joiner joiner = Joiner.on("; ").skipNulls(); return joiner.join("Harry",

    null, "Ron", "Hermione"); Splitter.on(',') .trimResults() .omitEmptyStrings() .split("foo,bar,, qux");
  9. char matchers _predicates for chars: retain(extract), remove, trim, matches ANY

    NONE WHITESPACE BREAKING_WHITESPACE DIGIT JAVA_LETTER JAVA_DIGIT JAVA_DIGIT_OR_LETTER JAVA_ISO_CONTROL JAVA_LOWER_CASE JAVA_UPPER_CASE ASCII
  10. formats and char sets try { bytes = string.getBytes("UTF-8"); }

    catch (UnsupportedEncodingException e) { throw new AssertionError(e); } // better do this bytes = string.getBytes(Charsets.UTF_8); CaseFormat.UPPER_UNDERSCORE .to(CaseFormat.LOWER_CAMEL, "CONSTANT_NAME")); // returns "constantName" /* LOWER_CAMEL, LOWER_HYPHEN, LOWER_UNDERSCORE, UPPER_CAMEL, UPPER_UNDERSCORE */
  11. why immutables? _thread safe, so no race conditions _more memory

    efficient than mutable alternatives _safe for use by untrusted libraries _guava collections types doesn’t allow nulls
  12. create immutable collections _all ImmutablesXXX (set/map) have following methods: _copyOf:

    (smart copy) avoids copying data when is safe to do _of _builder _asList: returns ImmutableList, constant-overhead view, rather than an explicit copy
  13. _generalization of the notion of set, in which members are

    allowed to appear more than once _the order is irrelevant: {x, y, y} == {y, x, y} _can be viewed as ArrayList<E> without ordering or Map<E, Integer> with elements and counts multiset count(Object): returns count associated with that element elementSet(): returns a Set<E> with the distinct elements of multiset entrySet(): returns Set<MultiSet. Entry<E>> which works as entry-set of Map<E>
  14. multimap _general way to associate keys to arbitrary values _alternative

    to Map<K, List<V>> or Map<K, Set<V>> _useful implementations _conceptually can think about multimap as: a collection of mappings from single keys to single values: a -> 1 a -> 2 a -> 4 b -> 3 c -> 5 or as a mapping from unique keys to collections of values: a -> [1, 2, 4] b -> 3 c -> 5
  15. bimap _better way to map values back to keys _values

    are unique, uses Set<E> _allows to view the inverse with BiMap<K, M>. inverse() _lots of implementations BiMap<String, Integer> userId = HashBiMap. create(); String userForId = userId.inverse().get(id); Map<String, Integer> nameToId = Maps. newHashMap(); Map<Integer, String> idToName = Maps. newHashMap(); nameToId.put("Bob", 42); idToName.put(42, "Bob");
  16. table Table<Vertex, Vertex, Double> weightedGraph = HashBasedTable.create(); weightedGraph.put(v1, v2, 4);

    weightedGraph.put(v1, v3, 20); weightedGraph.put(v2, v3, 5); weightedGraph.row(v1); weightedGraph.column(v3); _really a table like collection, surprise? _can access it as Map with rowMap() or as Set with rowKeySet() _implementations like HashBasedTable, TreeBasedTable, ImmutableBasedTable or ArrayTable
  17. class to instance map _used to map types to values

    of that type _eliminate need of casting with getInstance(Class<T>) and T putInstance(Class<T>, T) ClassToInstanceMap<Number> numbers = MutableClassToInstanceMap.create(); numbers.putInstance(Integer.class, Integer.valueOf(0)); numbers.putInstance(Double.class, Double.valueOf(1)); numbers.putInstance(Float.class, Float.valueOf(3));
  18. static constructors List<Type> list = Lists.newArrayList(); Map<KeyType, Type> map =

    Maps. newLinkedHashMap(); Set<Type> set = Sets.newHashSet(elements); List<String> elements = Lists.newArrayList("alpha", "beta", "gamma");
  19. iterables - collection like _addAll(Collection addTo, Iterable toAdd) _removeAll(Iterable removeFrom,

    Collection toRemove) _contains(Iterable, Object) _get(Iterable, int) _retainAll(Iterable removeFrom, Collection toRetain) collections operations on iterables
  20. functions and predicates Function<A, B> B apply(A input) Functions: _compose(Function<B,

    C>, Function<A, B>) Predicate<T> boolean apply(T input) Predicates: _isNull(), compose(Predicate, Function, and (Predicate), or(Predicate), not(Predicate), etc
  21. functional danger zone sometimes imperative version is more readable, concrete

    and efficient Multiset<Integer> lengths = HashMultiset.create( FluentIterable.from(strings) .filter(new Predicate<String>() { public boolean apply(String string) { return CharMatcher.JAVA_UPPER_CASE. matchesAllOf(string); } }) .transform(new Function<String, Integer>() { public Integer apply(String string) { return string.length(); } })); Multiset<Integer> lengths = HashMultiset. create(); for (String string : strings) { if (CharMatcher.JAVA_UPPER_CASE.matchesAllOf (string)) { lengths.add(string.length()); } }
  22. _allows us to register a callback to be executed when

    once task is completed _ussage: ListenableFuture.addCallback( Runnable, ExecutorService) listenable future ListneningExecutorService service = MoreExecutors.listeningDecorator (executorService); ListenableFuture<String> listenableFuture = executorService.submit(new Callable<String>()…); listenableFuture.addListener(new Runnable() { @Override public void run() { runOnFutureTaskCompletion(); } }, executorService);
  23. future callback ExecutorService executorService = Executors. newCachedThreadPool(); ListeningExecutorService executor =

    MoreExecutors. listeningDecorator(executorService); ListenableFuture<String> future = executor.submit(new Callable<String>() { @Override public String call() throws Exception { Thread.sleep(1000); return "Task completed"; }}); Futures.addCallback(future, new FutureCallback<String>() { @Override public void onSuccess(String s) { System.out.println("Task succeed: " + s); } @Override public void onFailure(Throwable throwable) { System.out.println("Task failed"); }}, executor);
  24. what you should learn _new collections types: really opens your

    mind to more problem solving alternatives _optional _try concurrency
  25. cleaner code? _it all depends on you _use statically imported

    functions to shorter lines _lambdas make code even cleaner (retrolambda)