Инструменты: представьте несколько полезных классов инструментов гуавы.

Java задняя часть
Инструменты: представьте несколько полезных классов инструментов гуавы.

предисловие

Обычно мы инкапсулируем некоторый кеш обработки или другие небольшие инструменты. Но каждый инкапсулирует его один раз и заново изобретает велосипед, что занимает немного времени. Есть ли хорошая библиотека инструментов, которую можно порекомендовать - guava. Guava — это библиотека с открытым исходным кодом, разработанная Google на основе Java. Ее производительность и практичность лучше, чем у наших собственных колес. В конце концов, она производится Google. Вот несколько часто используемых инструментов guava.

  • LoadingCache (локальный кеш)
  • Мультикарта и мультисет
  • BiMap
  • Стол
  • Наборы и карты (пересечение и различие)
  • EventBus (событие)
  • Секундомер
  • Файлы (файловые операции)
  • RateLimiter
  • Гуава Повторить

Следите за официальной учетной записью, общайтесь друг с другом и ищите в WeChat: Sneak forward

введена конфигурация maven гуавы

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>27.0-jre</version>
 </dependency>

LoadingCache

  • LoadingCache широко используется в практических сценариях.Обычно, если вы сталкиваетесь со сценарием, который требует много времени для вычисления или кэширования значений, вам следует сохранить значения в кэше. LoadingCache похож на ConcurrentMap, но не то же самое. Самая большая разница заключается в том, что ConcurrentMap будет постоянно хранить все значения элементов, пока они не будут явно удалены, а LoadingCache автоматически удалит просроченные значения в соответствии с конфигурацией, чтобы разумно использовать память.
  • Как правило, кэширование Guava подходит для следующих сценариев:
    • Потратьте немного памяти в обмен на скорость
    • Некоторые клавиши будут вызываться более одного раза
    • Кэшируемый контент ограничен и не будет превышать значение объема памяти. Кэши Guava не будут хранить контент в файлах или вне сервера. Если есть такая необходимость, рассмотрите возможность использования Memcached, Redis
  • LoadingCache не может кэшировать нулевые ключи
  • CacheBuilder конструирует введение параметра LoadingCache
Параметры метода CacheBuilder описывать
initialCapacity(int initialCapacity) Начальный размер буферного пула
concurrencyLevel(int concurrencyLevel) установить параллелизм
maximumSize(long maximumSize) Размер пула кеша, когда элементы кеша приближаются к этому размеру, Гуава начинает перерабатывать старые элементы кеша.
weakValues() Ссылка на хранилище для значения настройки является фантомной ссылкой
softValues() Установите ссылку на хранилище значения как мягкую ссылку
expireAfterWrite(long duration, TimeUnit unit) Если заданный объект времени не записан, объект будет удален из памяти (нерегулярно поддерживается в другом потоке)
expireAfterAccess(long duration, TimeUnit unit) Когда к заданному объекту времени нет доступа для чтения/записи, объект удаляется из памяти (поддерживается нерегулярно в другом потоке)
refreshAfterWrite(long duration, TimeUnit unit) Аналогичен expireAfterWrite, но вместо немедленного удаления ключа он будет обновлен при следующем обновлении, в течение которого может быть возвращено старое значение.
removalListener( RemovalListener<? super K1, ? super V1> listener) Прослушиватель, который срабатывает при удалении кэшированного элемента
build(CacheLoader<? super K1, V1> loader) Если данные не существуют, используйте загрузчик для загрузки данных
  • LoadingCache V get(K key), Получите кешированное значение, если ключ не имеет значения, он вызовет метод загрузки CacheLoader для загрузки нового значения в ключ
  • Пример
LoadingCache<Integer,Long> cacheMap = CacheBuilder.newBuilder().initialCapacity(10)
    .concurrencyLevel(10)
    .expireAfterAccess(Duration.ofSeconds(10))
    .weakValues()
    .recordStats()
    .removalListener(new RemovalListener<Integer,Long>(){
        @Override
        public void onRemoval(RemovalNotification<Integer, Long> notification) {
            System.out.println(notification.getValue());
        }
    })
    .build(new CacheLoader<Integer,Long>(){
        @Override
        public Long load(Integer key) throws Exception {
            return System.currentTimeMillis();
        }
    });
cacheMap.get(1);

Мультикарта и Мультисет

  • Особенность Multimap в том, что он может содержать несколько значений повторяющихся ключей, а также может помещать в несколько разных значений, но один и тот же ключ, но при этом не перезаписывать предыдущее содержимое.
  • Пример
//Multimap: key-value  key可以重复,value也可重复
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("csc","1");
multimap.put("lwl","1");
multimap.put("csc","1");
multimap.put("lwl","one");
System.out.println(multimap.get("csc"));
System.out.println(multimap.get("lwl"));
---------------------------
[1, 1]
[1, one]
  • Относительно полезным сценарием для MultiSet является отслеживание количества объектов каждого типа, поэтому его можно использовать для количественной статистики.
  • Пример
//MultiSet: 无序+可重复   count()方法获取单词的次数  增强了可读性+操作简单
Multiset<String> set = HashMultiset.create();
set.add("csc");
set.add("lwl");
set.add("csc");
System.out.println(set.size());
System.out.println(set.count("csc"));
---------------------------
3
2

BiMap

  • Ключ BiMap должен быть уникальным, и значение также должно быть уникальным, что может реализовать взаимное преобразование значения и ключа.
  • Пример
BiMap<Integer,String> biMap = HashBiMap.create();
biMap.put(1,"lwl");
biMap.put(2,"csc");
BiMap<String, Integer> map = biMap.inverse(); // value和key互转
map.forEach((v, k) -> System.out.println(v + "-" + k));

Table

  • Table<R,C,V> table = HashBasedTable.create();, как видно из обобщенного типа, таблица совместно определяется двойным первичным ключом R (строка) и C (столбец), а V — хранимое значение
  • Добавлены данные:table.put(R,C,V)
  • получить данные:V v = table.get(R,C)
  • Перебрать данные:Set<R> set = table.rowKeySet(); Set<C> set = table.columnKeySet();
  • Пример
// 双键的Map Map--> Table-->rowKey+columnKey+value  
Table<String, String, Integer> tables = HashBasedTable.create();
tables.put("csc", "lwl", 1);
//row+column对应的value
System.out.println(tables.get("csc","lwl"));

Наборы и карты

// 不可变集合的创建
ImmutableList<String> iList = ImmutableList.of("csc", "lwl");
ImmutableSet<String> iSet = ImmutableSet.of("csc", "lwl");
ImmutableMap<String, String> iMap = ImmutableMap.of("csc", "hello", "lwl", "world");

пересечение, объединение, разность множеств

HashSet setA = newHashSet(1, 2, 3, 4, 5);  
HashSet setB = newHashSet(4, 5, 6, 7, 8); 
//并集
SetView union = Sets.union(setA, setB);   
//差集 setA-setB
SetView difference = Sets.difference(setA, setB);  
//交集
SetView intersection = Sets.intersection(setA, setB);  

Пересечение, Союз, Разность карт

HashMap<String, Integer> mapA = Maps.newHashMap();
mapA.put("a", 1);mapA.put("b", 2);mapA.put("c", 3);
HashMap<String, Integer> mapB = Maps.newHashMap();
mapB.put("b", 20);mapB.put("c", 3);mapB.put("d", 4);
MapDifference<String, Integer> mapDifference = Maps.difference(mapA, mapB);
//mapA 和 mapB 相同的 entry
System.out.println(mapDifference.entriesInCommon());
//mapA 和 mapB key相同的value不同的 entry
System.out.println(mapDifference.entriesDiffering());
//只存在 mapA 的 entry
System.out.println(mapDifference.entriesOnlyOnLeft());
//只存在 mapB 的 entry
System.out.println(mapDifference.entriesOnlyOnRight());;
-------------结果-------------
{c=3}
{b=(2, 20)}
{a=1}
{d=4}

EventBus

  • EventBus — это механизм обработки событий Guava и элегантная реализация шаблона Observer (модель программирования производитель/потребитель) в шаблонах проектирования. Для прослушивания событий и режима публикации-подписки
  • Внутренний принцип реализации EventBus не сложен. EventBus будет поддерживать карту Multimap, Subscriber>. Ключ представляет класс, соответствующий сообщению (разные сообщения имеют разные классы, разные сообщения различаются), а значение является подписчиком, который на самом деле является подписчиком. Соответствует обработчику сообщений. Если есть сообщение для публикации, перейдите на эту карту, чтобы найти подписчика, соответствующего сообщению для выполнения.
  • Пример использования
@Data
@AllArgsConstructor
public class OrderMessage {
    String message;
}
//使用 @Subscribe 注解,表明使用dealWithEvent 方法处理 OrderMessage类型对应的消息
//可以注解多个方法,不同的方法 处理不同的对象消息
public class OrderEventListener {
    @Subscribe
    public void dealWithEvent(OrderMessage event) {
        System.out.println("内容:" + event.getMessage());
    }
}
-------------------------------------
// new AsyncEventBus(String identifier, Executor executor);
EventBus eventBus = new EventBus("lwl"); 
eventBus.register(new OrderEventListener());
// 发布消息
eventBus.post(new OrderMessage("csc"));

StopWatch

Stopwatch stopwatch = Stopwatch.createStarted();
for(int i=0; i<100000; i++){
    // do some thing
}
long nanos = stopwatch.elapsed(TimeUnit.MILLISECONDS);
System.out.println("逻辑代码运行耗时:"+nanos);

Файлы файловые операции

  • запись данных
File newFile = new File("D:/text.txt");
Files.write("this is a test".getBytes(), newFile);
//再次写入会把之前的内容冲掉
Files.write("csc".getBytes(), newFile);
//追加写
Files.append("lwl", newFile, Charset.defaultCharset());
  • чтение текстовых данных
File newFile = new File("E:/text.txt");
List<String> lines = Files.readLines(newFile, Charset.defaultCharset());
  • другие операции
метод описывать
Files.copy(File from, File to) копировать файл
Files.deleteDirectoryContents(File directory) Удалить содержимое папки (включая файлы и подпапки)
Files.deleteRecursively(File file) удалить файл или папку
Files.move(File from, File to) переместить файлы
Files.touch(File file) Отметка времени создания или обновления файла
Files.getFileExtension(String file) получить расширение файла
Files.getNameWithoutExtension(String file) получить имя файла без расширения
Files.map(File file, MapMode mode) Получить отображенный в память буфер

RateLimiter

//RateLimiter 构造方法,每秒限流permitsPerSecond
public static RateLimiter create(double permitsPerSecond) 
//每秒限流 permitsPerSecond,warmupPeriod 则是数据初始预热时间,从第一次acquire 或 tryAcquire 执行开时计算
public static RateLimiter create(double permitsPerSecond, Duration warmupPeriod)
//获取一个令牌,阻塞,返回阻塞时间
public double acquire()
//获取 permits 个令牌,阻塞,返回阻塞时间
public double acquire(int permits)
//获取一个令牌,超时返回
public boolean tryAcquire(Duration timeout)
////获取 permits 个令牌,超时返回
public boolean tryAcquire(int permits, Duration timeout)
  • Пример использования
RateLimiter limiter = RateLimiter.create(2, 3, TimeUnit.SECONDS);
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
---------------  结果 -------------------------
get one permit cost time: 0.0s
get one permit cost time: 1.331672s
get one permit cost time: 0.998392s
get one permit cost time: 0.666014s
get one permit cost time: 0.498514s
get one permit cost time: 0.498918s
get one permit cost time: 0.499151s
get one permit cost time: 0.488548s
  • Поскольку RateLimiter обрабатывается с задержкой, первое время, независимо от того, сколько времени было принято, составляет ноль секунд.
  • Вы можете видеть, что в первых четырех сборах данных потребовалось три секунды, чтобы прогреть данные, а время между пятым и восьмым захватами имеет тенденцию быть гладким.

Guava Retry

  • импорт maven
<dependency>
  <groupId>com.github.rholder</groupId>
  <artifactId>guava-retrying</artifactId>
  <version>2.0.0</version>
</dependency>
  • Конструктор RetryerBuilder
Метод RetryerBuilder описывать
withRetryListener повторите прослушиватель
withWaitStrategy Интервал повтора после сбоя
withStopStrategy стоп стратегия
withBlockStrategy Стратегия блокировки BlockStrategy
withAttemptTimeLimiter Выполнить политику ограничения времени
retryIfException Если возникает исключение, попробуйте еще раз
retryIfRuntimeException Если возникает исключение RuntimeException, повторите попытку.
retryIfExceptionOfType(Class<? extends Throwable> ex) Если возникает исключение ex, попробуйте еще раз
retryIfException(Predicate<Throwable> exceptionPredicate) Следует ли повторить ненормальное суждение
retryIfResult(Predicate<V> resultPredicate) Судя по возвращаемому результату, следует ли повторить попытку
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
    .retryIfException()
    .retryIfResult(Predicates.equalTo(false))
    .withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(1, TimeUnit.SECONDS))
    .withStopStrategy(StopStrategies.stopAfterAttempt(5))
    .build();
//Retryer调用                
retryer.call(() -> true);

Приветствуется указание на ошибки в тексте (рассказ чисто вымышленный, любое сходство чисто случайное)

Справочная статья

Категории