getting started with google guava 笔记

guava 包的一些常用集合操作

  1. List 转 Map
  2. Key 关联多个 Value 的 Map 结构
  3. Key-Value 互转
  4. 多线程并发阻塞
  5. 多线程异步回调 CompleteFuture vs Guava 异步回调

List 转 Map

        Book book1 = new Book("isbn-1", "深入理解jvm");
        Book book2 = new Book("isbn-2", "算法导论");

        List<Book> bookList = Lists.newArrayList(book1, book2);

        //方式一: java 8 lambda
//        Map<String, Book> bookMap = bookList.stream().collect(Collectors.toMap(Book::getIsbn, Function.identity()));

        //方式二: guava Maps 工具类
        Map<String,Book> bookMap1 = Maps.uniqueIndex(bookList.iterator(), new Function<Book, String>() {
            @Nullable
            @Override
            public String apply(@Nullable Book input) {
                return input.getIsbn();
            }
        });

key 关联多个 value。value之间去重/不去重

        //一个 key 关联多个value
        ArrayListMultimap<Integer, String> map = ArrayListMultimap.create();
        map.put(1, "a");
        map.put(1, "aa");
        map.put(1, "aa");
        //{1=[a, aa, aa]}
        System.out.println(map);

        //一个 key 关联多个value,value之间可去重
        HashMultimap<Integer, String> hashMultimap = HashMultimap.create();
        hashMultimap.put(1, "a");
        hashMultimap.put(1, "aa");
        hashMultimap.put(1, "aa");
        //{1=[aa, a]}
        System.out.println(hashMultimap);

键值相互映射

  1. inverse 方法将 key-->value 转换成 value-->key
  2. 当 put 的 value 相同时,forcePut 方法强制更新key
        //键值相互映射: key-->value && value-->key
        BiMap<Integer, String> biMap = HashBiMap.create();
        biMap.put(1, "a");
        biMap.put(2, "b");
        //"a"
        System.out.println(biMap.get(1));
        //"b"
        System.out.println(biMap.get(2));

        BiMap<String, Integer> inverseMap = biMap.inverse();
        //1
        System.out.println(inverseMap.get("a"));
        //2
        System.out.println(inverseMap.get("b"));

        BiMap<Integer, String> forceBiMap = HashBiMap.create();
        //强制覆盖value
        forceBiMap.put(1, "a");
        //抛出 IllegalArgumentException
//        forceBiMap.put(2, "a");
        //success, value 相同时, 将 key 从 1 更新为 2
        forceBiMap.forcePut(2, "a");
        //false
        System.out.println(forceBiMap.containsKey(1));
        //true
        System.out.println(forceBiMap.containsKey(2));

并发

阻塞获取结果

    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        Future<String> future = cachedThreadPool.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                //在 cachedThreadPool 中 '异步'执行
                return "result";
            }
        });
        //主线程阻塞获得结果
        future.get();
    }

CompletableFuture 阻塞获取结果

    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                return "result";//使用 forkjoin common pool 线程池执行
            }
        });
        future.get();
        //主线程继续执行其他逻辑...
    }

guava 异步回调

  1. 在 executorService 中提交 callable 任务,返回 listenableFuture 对象
  2. listenableFuture 对象添加监听器(回调逻辑),当 listenableFuture 执行完成时,触发回调逻辑的执行。
  3. 此回调逻辑是个 Runnable 任务,无法获取 callable 任务的执行结果(无法基于 callable 任务的执行结果做一些处理)
  4. 若需要基于 callable 任务的执行结果做一些处理,可使用:FutureCallback
public class CallBackTest {
    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        ListeningExecutorService executorService = MoreExecutors.listeningDecorator(cachedThreadPool);

        ListenableFuture<String> listenableFuture = executorService.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("start to execute in " + Thread.currentThread().getName());
                //模拟执行2秒钟
                sleep(2000);
                System.out.println("execute finished in " + Thread.currentThread().getName());
                return "result";//callable 任务的执行结果
            }
        });

        listenableFuture.addListener(new Runnable() {
            @Override
            public void run() {
                //
                System.out.println("listenableFuture 执行完成后, 执行此回调逻辑");
            }
        }, executorService);

        //主线程继续执行其他逻辑...
    }

    private static void sleep(long mills) {
        try {
            TimeUnit.MILLISECONDS.sleep(mills);
        } catch (Exception e) {

        }
    }
}

异步回调处理 callable 结果

基于 guava 的 FutureCallback 来处理 callable 任务的执行结果。

    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        ListeningExecutorService executorService = MoreExecutors.listeningDecorator(cachedThreadPool);

        ListenableFuture<String> listenableFuture = executorService.submit(new Callable<String>() {
            @Override
            public String call() throws Exception {
                System.out.println("start to execute in " + Thread.currentThread().getName());
                //模拟执行2秒钟
                sleep(2000);
                System.out.println("execute finished in " + Thread.currentThread().getName());
//                Integer.valueOf("模拟异常");
                return "result";//callable 任务的执行结果
            }
        });

        Futures.addCallback(listenableFuture, new FutureCallback<String>() {
            @Override
            public void onSuccess(@Nullable String result) {
                System.out.println("callable 任务执行成功, 执行结果是: " + result);
            }

            @Override
            public void onFailure(Throwable t) {
                System.out.println("callable 任务执行失败, 错误原因是: " + t.getMessage());
            }
        });

        //主线程继续执行其他逻辑...
    }

JDK 原生异步回调

  1. CompletableFuture.supplyAsync 执行一个异步任务(ForkJoinPool.commonPool线程池)
  2. future.thenApply 添加回调逻辑,当异步任务执行完成时,执行回调逻辑,可在回调逻辑中处理异步任务的执行结果
    public static void main(String[] args) throws Exception{
        CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
            @Override
            public String get() {
                System.out.println("start to run async task in " + Thread.currentThread().getName());
                sleep(2000);
                System.out.println("finished run async task in " + Thread.currentThread().getName());
                return "result";
            }
        });

        future.thenApply(result -> {
            String processCallableResult = "process " + result;
            System.out.println(processCallableResult);
            return processCallableResult;
        });

        //主线程继续执行其他逻辑...

CompletableFuture 的强大之处

  1. 多个异步任务之间可编排
posted @ 2022-04-25 17:42  大熊猫同学  阅读(65)  评论(0编辑  收藏  举报