Guava - open-source библиотека, разработанная в основном инженерами компании Google, в которой есть множество полезных утилит для написания эффективного и красивого кода. В Guava решено множество типичных задач, которые часто возникают при работе с примитивами, строками, коллекциями, параллельными вычислениями, кэшированием данных и многим другим. В докладе поговорим о возможностях, которые предоставляет Guava, рассмотрим примеры использования утилит библиотеки.
2. Вместо эпиграфа
Не изобретайте колесо. Если вам нужно сделать нечто, что кажется
вполне обычным, в библиотеках уже может быть класс, который делает
это. Вообще говоря, программный код в библиотеке наверняка окажется
лучше кода, который вы напишете сами, а со временем он может стать
еще лучше. Мы не ставим под сомнение ваши способности как
программиста, однако библиотечному коду уделяется гораздо больше
внимания, чем может позволить себе средний разработчик при
реализации тех же функций.
Джошуа Блох.
Эффективное программирование на Java.
2 Статья 47 “Изучите библиотеки и пользуйтесь ими”
3. Философия библиотеки
● Тщательно разработана
● Протестирована
● Оптимизирована
● Только повсеместно используемые
функции попадают в библиотеку
3
4. Зачем использовать GUAVA
● Сэкономить значительное количество
написанного кода
● Избежать написания кода, который
трудно отлаживать и в котором легко
ошибиться
● Улучшить читабельность
● Улучшить скорость работы программы. 4
5. Особенность удаления фич
● В отличие от JDK удаляют
нежелательное поведение через
некоторое время
● @Beta API
● @Deprecated non @Beta компоненты
удаляются через 18 месяцев
5
6. Базовые утилиты
● Работа с null. Optional
● Preconditions
● Objects, toString, equals,
hashCode
● Компараторы с Ordering
6
7. Использование и избежание работы с
null
● null - источник множества ошибок.
● null быстр и нужно научится его правильно
использовать, где это необходимо, и избегать во
всех остальных случаях.
● Многие утилиты GUAVA где недопустимы null’ы
бросают ошибку.
7
8. Optional<T>
Not null reference of T Present Optional<T>
null reference of T
Absent Optional<T>
8
15. Preconditions
int positive = 1;
checkArgument(positive > 0, "Number %s must be a positive", positive); // IllegalArgumentException:
//Number 1 must be a negative
checkArgument(positive < 0, "Number %s must be a negative", positive); // IllegalArgumentException:
//Number 1 must be a negative
Object nullValue = null;
checkNotNull(nullValue, "Value mast be not null"); // NullPointerException: Value mast be not null
checkState(positive < 0); // IllegalStateException
checkElementIndex(5, 6);
checkElementIndex(6, 6); // IndexOutOfBoundsException: index (6) must be less than size (6)
checkPositionIndex(6, 6);
checkPositionIndexes(3, 4, 4);
15
23. Ordering
● Ordering<T> - наследник
Comparator<T>
● В Ordering реализованы методы
использующие порядок: min, max, sort и
т.д.
23
24. Ordering<T>. Создание
● Ordering.natural() - естественный порядок,
основанный на функции compare(T,T)
● Ordering.usingToString() - лексикографический
порядок, строковых представлений (toString)
● Ordering.from(Comparator)
● Наследник Ordering
24
25. Ordering<T>. Использование
greatestOf(Iterable iterable, int k)
See also: leastOf
isOrdered(Iterable)
See also: isStricklyOrdered
sortedCopy(Iterable)
See also: immutableSortedCopy
min(E, E)
See also: max(E, E)
min(E, E, E, E...)
See also: max(E, E, E, E...)
min(Iterable)
See also: max(Iterable), min(Iterator), max(Iterator)
25
28. Список Person
private static List<Person> createPersonList()
{
return Lists.newArrayList(
new Person("Egor", "Chernyshev", 24),
new Person("Anton", "Borisov", 36),
new Person("Elena", "Petrova", 18),
new Person("Maxim", "Lobanov", 65),
new Person(null, "Alexandrova", 24));
}
28
31. GUAVA Collections
● ImmutableCollections
● Новые коллекции в Guava
● Утилитарные классы Sets, Lists, Maps…
● Утилиты для расширения java коллекций
31
33. Чем хороши Immutable objects?
● Безопасное использование в untrusted
библиотеках.
● Потоко безопасны.
● Хороши для хранения констант, так как
есть гарантия неизменяемости.
33
34. Interface JDK или Guava Immutable version
Collection JDK ImmutableCollection
List JDK ImmutableList
Set JDK ImmutableSet
SortedSet /
NavigableSet
JDK ImmutableSortedSet
Map JDK ImmutableMap
SortedMap JDK ImmutableSortedMap
34 Multiset Guava ImmutableMultiset
35. Interface JDK или Guava Immutable version
SortedMultiset Guava ImmutableSortedMultiset
Multimap Guava ImmutableMultimap
ListMultimap Guava ImmutableListMultimap
SetMultimap Guava ImmutableSetMultimap
BiMap Guava ImmutableSetMultimap
ClassToInstanceM
ap
Guava ImmutableClassToInstanceMap
35 Table Guava ImmutableTable
39. copyOf умнее, чем вы думаете
● copyOf пытается избежать полного
копирования объектов.
● В общем случае ImmutableXXX.copyOf
(ImmutableXXX) пытается выполнится
за O(1), за исключением некоторых
случаев
39
43. Multiset. Пример
Подсчет количества каждого символа в тексте:
Multiset<Character> toCharsMultiset(String text)
{
return HashMultiset.create(Chars.asList(text.toCharArray()));
}
43
44. Multiset. Реализации
Map Соответствующий Multiset Допускает null?
HashMap HashMultiset Да
TreeMap TreeMultiset Да (если компаратор
поддерживает)
LinkedHashMap LinkedHashMultiset Да
ConcurrentHashMap ConcurrentHashMultiset Нет
ImmutableMap ImmutableMultiset Нет
44
48. Multimap<K,V>. Реализации
Реализация Ключи ведут себя как... Значения ведут себя как...
ArrayListMultimap HashMap ArrayList
HashMultiMap HasMap HashSet
LinkedListMultimap LinkedHashMap LinkedList
LinkedHashMultiMap LinkedHashMap LinkedHashSet
TreeMultimap TreeMap TreeSet
ImmutableListMultimap ImmutableMap ImmutableList
ImmutableSetMultimap ImmutableMap ImmutableSet
48
49. Multimap. Пример
private static Function<Person, String> FIRST_NAME_EXTRACTOR = new
Function<Person, String>()
{
@Override
public String apply(Person input)
{
return input.getFirstName();
}
};
49
50. Multimap. Пример
List<Person> PERSONS = Lists.newArrayList(
new Person("Egor", "Chernyshev", 24),
new Person("Anton", "Borisov", 36),
new Person("Elena", "Petrova", 18),
new Person("Elena", "Birkova", 11),
new Person("Maxim", "Lobanov", 65));
Multimap<String, Person> index = Multimaps.index(PERSONS, FIRST_NAME_EXTRACTOR);
50
52. BiMap<K,V>
BiMap<V, K> - это Map<K, V>, в которой
● Добавлен метод BiMap<V, K> inverse().
● Есть проверка на уникальность значений.
● values() возвращает Set<V>.
52
55. Table<R, C, V>
● Table - это способ хранения индекса
объекта по двум ключам R и C.
● Table<R,C,V> заменяет неуклюжую
реализацию структуры
Map<R, Map<C, V>>
55
56. Table<R, C, V>. Представления
Table<R,C,V>.rowMap() Map<R, Map<C,V>>
Table<R,C,V>.rowKeySet() Set<R>
Table<R,C,V>.row(r) Map<C,V>
columnMap(),
columnKeySet(), column(c)
Аналогично, row. Column access по
производительности работает медленнее, чем row
access из за структуры данных.
Table<R,C,V>.cellSet() Set<Table.Cell<R,C,V>>
56
57. Table<R, C, V>. Реализации
Реализация На основе структуры
HashBasedTable HashMap<R, HashMap<C, V>>
TreeBasedTable TreeMap<R, TreeMap<C, V>>
ImmutableTable ImmutableMap<R, ImmutableMap<C, V>>
ArrayTable Двумерный массив. Хорошо подходит для
задач, с сильно заполненными таблицами.
57
60. public interface MegaService {}
public class SuperMegaService implements MegaService{}
public class SuperMegaBupperService implements MegaService{}
…
private static final ClassToInstanceMap<MegaService> REGISTRY = MutableClassToInstanceMap.create();
…
REGISTRY.putInstance(SuperMegaService.class, new SuperMegaService());// OK
REGISTRY.putInstance(SuperMegaBupperService.class, new SuperMegaBupperService());// OK
REGISTRY.putInstance(MegaService.class, new SuperMegaBupperService());// OK
REGISTRY.putInstance(SuperMegaService.class, new SuperMegaBupperService()); // Ошибка компиляции
REGISTRY.putInstance(String.class, "qqqq"); // Ошибка компиляции
REGISTRY.put(String.class, "qqqq"); // Ошибка компиляции
REGISTRY.getInstance(MegaService.class);// OK
REGISTRY.getInstance(String.class);// Ошибка компиляции
60
69. Iterables
● Guava предпочитает Iterable вместо
Collection
● Многие Iterable являются Lazy
● Утилита FluentItrable, оборачивает
Iterable и предоставляет набор
методов для работы в функцинальном
стиле. 69
70. Lists
Метод Описание
partiton(List, int) List<List> - разбиение списка на подсписки
определенной длины.
reverse(List) Развернутое представление списка
70
71. Sets
Метод Описание
union(Set, Set) Объединение множеств
intersection(Set, Set) Пересечение
difference(Set, Set) Разность
symmetricDifference(Set, Set) симметричная разность
powerSet(Set) Множество всех подмножеств
71
73. Maps.uniqueIndex()
Maps.uniqueIndex(Lists.newArrayList("dddd", "ddddd", "qwcccccde"), new Function<String, Integer>()
{
@Override
public Integer apply(String input)
{
return input.length();
}
});
//{4=dddd, 5=ddddd, 9=qwcccccde}
● Выбросится ошибка, если Function
73 вернет неуникальное значение
74. MapDifference d = Maps.difference()
entriesOnlyOnLeft() entriesInCommon() entriesOnlyOnRight()
entriesDiffering()
74
75. Multimaps
Метод Описание
index(Iterable, Function) Построение индекса коллекции по ключевой
функции
invertFrom(Multimap, Multimap) Разворот Map’ы (<K,V> -> <V,K>)
forMap(Map) Преобразвание Map<K,V> в Multimap<K,V>
75
76. Tables
Метод Описание
transpose(Table<R,C,V>) Транспонирование таблицы Table<R,C,V> ->
Table<C,R,V>
76
81. PeekingIterator
List<String> result = Lists.newArrayList();
PeekingIterator<String> iter = Iterators.peekingIterator(source.iterator());
while (iter.hasNext()) {
String current = iter.next();
while (iter.hasNext() && iter.peek().equals(current)) {
// skip this duplicate element
iter.next();
}
result.add(current);
}
81
82. AbstractIterator
public static Iterator<String> skipNulls(final Iterator<String> in) {
return new AbstractIterator<String>() {
protected String computeNext() {
while (in.hasNext()) {
String s = in.next();
if (s != null) {
return s;
}
}
return endOfData();
}
};
}
82
86. Cache. Добавление значения
CacheLoader
/**
* Медленная операция получения человека по Web сервису
* из внешней системы
*/
private Person loadPersonByWebService(String key)
{
return new Person("Anton", "Borisow", 88);
}
86
95. Cache. Когда происходит eviction
● В момент записи нового значения
● Иногда (если записей в кэш мало) при
получении значения по ключу
● Кэш не обслуживается отдельным
95 потоком!
96. Cache. Прочие возможности
● Statistic:
Включение: CacheBuilder.recordStats();
Получение: CacheStats stats = Cache.stats();
Использование:
● stats.hitRate() - количество попаданий
● stats.averageLoadPenalty() - среднее время на загрузку
новых значений
● stats.evictionCount() - количество eviction’ов
● asMap
96
98. ListenableFuture
● Расширяет Future - позволяет
регистрировать Callback на момент
выполнения операции.
● Callback будет вызван один раз.
● Callback обрабатывает ошибки с
помщью onFaiture() метода.
98
102. Service
● Интерфейс Service - это объект с рабочим
состоянием и методами остановки и запуска.
● Service имеет ряд предопределенных
состояний.
● Существуют базовые абстрактные
реализации, которые необходимо
переопределять для написания собственных
102 служб и сервисов.
103. Использование Service
NEW STARTING RUNNING STOPPING TERMINATED
Метод Описание
startAsync() Запуск
stopAsync() Остановка
state() Статус
103
105. ServiceManger
Метод Описание
startAsync() Стартует все службы
stopAsync() Останавливает все службы
addListener Добавление листенеров на смены статусов
awaitHealthy() дождаться пока все службы не станут RUNNING
awaitStopped() дождаться пока все службы не будут остановлены
isHealthy() true, если все службы RUNNING
servicesByState() ultimap сервисов сгрупированных по состояниям
105 startupTimes() Map сервисов с временами старта. Отсортированная
110. Strings
Метод Описание
isNullOrEmpty(str) true,если str == null или str.length() == 0
nullToEmpty(str) Преобразуется null в “”
emptyToNull(str) Преобразует “” в null
repeat(str, int) Повторяет str строку int раз
110