Возможно, если вы пишете на Java, то у вас в проекте есть код похожий на этот:
Map<String, Integer> data = ...;
for (String s : strings) {
if (!data.containsKey(key))
data.put(key, 0);
data.put(key, data.get(key) + 1);
}
Суть проста. Есть отображение из строки в счетчик, сколько раз мы встретили эту строку. Надо только не забывать инициализировать позиции Map‘а нулем, а то виртуальная машина в вас NullPointerException кинет.
for (String s : strings)
data.merge(s, 1, (a, b) -> a + b);
Meтод merge принимает ключ, значение и функцию которая объединяет заданное значение и уже существующее в отображении, если таковое имеется. Если в отображении под заданным ключем значения нет, то кладет туда указанное значение.
•
computeIfAbsent() – возвращает или значение из отображения по ключу, или создает его, если его не было;•
cputIfAbsent() – добавляет значение в отображение, только если его там не было. Этот метод ранее имелся только у ConcurrentMap, теперь появился и у Map‘а;•
cgetOrDefault() – название довольно красноречиво. Возвращает значение из отображения или переданное значение по-умолчанию. На мой взгляд, метод довольно не идиоматичен. Для работы с отсутствующими значениями был добавлен тип Optional, его и следовало использовать. Поэтому, я бы добавил метод: Optional<V> getOptional(K key).Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤1
Тех, кто плотно работает с многопоточностью, ничем не пронять. Они как ветераны Вьетнама, и даже флешбеки по ночам так же мучают. И этой конструкцией их не напугаешь:
// Java 7 и ранее
ThreadLocal<ObjectMapper> mapper = new ThreadLocal<>() {
@Override
protected ObjectMapper initialValue() {
return new ObjectMapper();
}
};
// Java 8
ThreadLocal<ObjectMapper> mapper = withInitial(() -> new ObjectMapper());
Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
В Java 8 стало возможным гораздо проще выполнить такую простую задачу как прочитать построчно файл. Это ещё одна задача, которая раньше требовала довольно много кода.
BufferedReader, поэтому теперь Stream’ы доступны поверх любого InputStream‘а.Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Если вам нужно написать Comparator для сортировки объектов по возрастанию, обычно он выглядит так:
public class ByScoreComparator implements Comparator<User> {
@Override
public int compare(User u1, User u2) {
return (int) signum(u2.getAge() - u1.getAge());
}
}Теперь это не нужно. Можно использовать ссылки на методы:
Comparator<User> comparator = Comparator
.comparingDouble(User::getAge)
.thenComparing(User::getName);
List<User> hList = ...;
hList.sort(comparator);
Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22
Как вы генерируете тестовые данные в ваших модульных тестах? Instancio поможет нам в этом.
Ее цель — сократить время и количество строк кода, затрачиваемых на ручную настройку данных в модульных тестах. Она создает объекты и заполняет их случайными данными, делая наши тесты более динамичными.
Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7😢1
Datafaker создает фиктивные данные для ваших программ JVM за считанные минуты, используя широкий спектр из более чем 100 поставщиков данных.
Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤1
Два класса, которые представляют собой более производительные замены для
AtomicLong. Класс LongAdder позволяет выполнять атомарные арифметические операции над типом long. LongAccumulator принимает произвольную функцию аккумуляции результатов.accumulate() и возвращает результат логического объединения (accumulate) двух значений.При получении результата все элементы редуцируются в один общий результат. Вся эта кухня намекает нам, что функция аккумуляции должна быть коммутативна и ассоциативна. В противном случае результат будет зависеть от физического порядка выполнения операций, который данный класс не гарантирует.
Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Раньше я использовал keySet для итерации по HashMap, как показано ниже:
Set<Key> keySet = map.keySet();
for (Key k : keySet) {
Value v = map.get(k);
print(k, v);
}
Set<Map.Entry<Key, Value>> entrySet = map.entrySet();
for (Map.Entry<Key, Value> e : entrySet) {
Key k = e.getKey();
Value v = e.getValue();
}
Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤1
Жаль, что я не знал раньше, что можно написать Singleton в Java всего одной строкой:
public enum Singleton {
INSTANCE;
}• Потокобезопасность: Перечисления в Java создаются с использованием потокобезопасного механизма. Это означает, что вы не столкнетесь с проблемами, связанными с многопоточностью.• Гарантия единственности экземпляра: Java гарантирует, что в системе будет только один экземпляр перечисления, даже при использовании различных потоков или классов загрузчиков.• Сериализация и десериализация: При использовании enum Java автоматически обрабатывает сериализацию и десериализацию таким образом, чтобы сохранить единственность экземпляра. Это означает, что при десериализации вы не получите новый экземпляр, а вернется тот же самый экземпляр.Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17
Раньше, даже зная элементы заранее, я инициализировал коллекцию так:
List<String> listOfCurrencies = new ArrayList<>();
listOfCurrencies.add("USD/AUD");
listOfCurrencies.add("USD/JPY");
listOfCurrencies.add("USD/INR");
Arrays.asList() возвращает List, его нужно передать конструктору ArrayList, потому что возвращаемый список имеет фиксированную длину, и вы не можете добавлять или удалять элементы.List.of() и Set.of() для создания списка и множества с элементами. Это предпочтительнее, так как они возвращают неизменяемые списки и множества.Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17
Когда я только начинал писать код для межпоточной коммуникации с использованием методов
wait(), notify() и notifyAll(), я использовал if для проверки условия ожидания перед вызовом wait() и notify():synchronized(queue) {
if(queue.isFull()){
queue.wait();
}
}🗣️ К счастью, проблем не возникло, но я понял свою ошибку, прочитав раздел из книги Effective Java. Там сказано, что условие ожидания следует проверять в цикле, потому что потоки могут получать ложные уведомления, и до того, как вы что-то сделаете, условие может снова стать истинным. Поэтому правильный способ использования wait() и notify() выглядит так:
synchronized(queue) {
while(queue.isFull()){
queue.wait();
}
}Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14
Несмотря на критику функции клонирования объектов в Java, если вам нужно реализовать метод
clone(), вот несколько лучших практик для упрощения задачи:public Course clone() {
Course c = null;
try {
c = (Course)super.clone();
} catch (CloneNotSupportedException e) {} // Не произойдет
return c;
}clone() не вызовет CloneNotSupportedException, если класс реализует интерфейс Cloneable. Возврат подкласса называется ковариантным переопределением методов и доступен с Java 5, что позволяет избежать приведения типа на стороне клиента:Course javaBeginners = new Course("Java", 100, 10);
Course clone = javaBeginners.clone();Ранее, например, с классом Date, нужно было явно приводить результат метода
clone():Date d = new Date();
Date clone = (Date) d.clone();
Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Раньше я использовал конкретные классы, например
ArrayList, Vector, и HashMap для возвращаемых значений и аргументов методов.java.util.List, для неупорядоченного набора без дубликатов — java.util.Set, а для контейнера — Collection. Это позволит легко менять реализации.Можно ещё больше упростить с помощью обобщений и extends. Например, вы можете использовать List<? extends Number>, что позволит передавать List<Integer> или List<Short>.
Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤2
В Java есть несколько способов перебрать список: цикл
for с индексом, расширенный for и Iterator. Раньше я использовал цикл for с методом get(), как показано ниже:for (int i = 0; i < list.size(); i++) {
String name = list.get(i);
}🗣️ Этот метод работает для ArrayList, но если список — это LinkedList или другая реализация без поддержки случайного доступа, время выполнения увеличится до O(N^2), потому что get() для LinkedList имеет O(n) сложность.
Кроме того, при использовании циклов может возникнуть ошибка в многопоточном режиме, например, при работе с CopyOnWriteArrayList, когда один поток изменяет список, а другой пытается получить доступ к элементам, что может привести к IndexOutOfBoundsException.
Iterator<String> itr = list.iterator();
while (itr.hasNext()) {
String name = itr.next();
}
Это безопаснее и предотвращает непредсказуемое поведение.
Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16❤1
Ранее я писал код следующим образом:
public class Game {
private HighScoreService service = HighScoreService.getInstance();
public void showLeaderBoard() {
List listOfTopPlayers = service.getLeaderBoard();
System.out.println(listOfTopPlayers);
}
}• Класс Game жестко связан с классом HighScoreService, что усложняет тестирование Game в изоляции.• Даже при наличии класса HighScoreService сложно протестировать Game, если HighScoreService делает сетевые запросы или загружает данные с серверов. Мок-объекты здесь не подходят.Java Learning
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10