Go To My HomePage

Guava的使用

一、介绍

​ Guava工程包含了若干被Google的Java项目广泛依赖的核心库,例如:集合、缓存、原生类型支持、并发库、通用注解、字符串处理、I/O等等

二、工具类

校验参数合法性-Preconditions

/**
  * 判断参数是否为空,并给出异常信息
  */
@Test
public void testCheckNotNull() {
  Integer paramFlag = null;
  try {
    Preconditions.checkNotNull(null, "this param [%s] must be not null.", "paramFlag");
  } catch (Exception e) {
    assertThat(e, is(instanceOf(NullPointerException.class)));
    assertThat(e.getMessage(), equalTo("this param [paramFlag] must be not null."));
  }
}

/**
  * 参数校验
  */
@Test
public void testCheckArguments() {
  boolean flag = false;
  try {
    Preconditions.checkArgument(flag == true, "flag must be not true.");
  } catch (Exception e) {
    assertThat(e, is(instanceOf(IllegalArgumentException.class)));
    assertThat(e.getMessage(), equalTo("flag must be not true."));
  }
}

/**
  * 状态校验
  */
@Test
public void testCheckState() {
  String flag = "fail";
  try {
    Preconditions.checkState("success".equals(flag), "flag state is %s, not success.", flag);
  } catch (Exception e) {
    assertThat(e, is(instanceOf(IllegalStateException.class)));
    assertThat(e.getMessage(), equalTo("flag state is fail, not success."));
  }
}

/**
  * 越界检测
  */
@Test
public void testCheckIndex() {
  try {
    List<String> list = ImmutableList.of();
    Preconditions.checkElementIndex(3, list.size());
  } catch (Exception e) {
    assertThat(e, is(instanceOf(IndexOutOfBoundsException.class)));
  }
}

/**
  * JDK的Objects也可做null检测
  */
@Test(expected = NullPointerException.class)
public void testByObjects() {
  Objects.requireNonNull(null);
}

计算程序块时间-StopWatch

/**
  * 得到程序执行的耗时,自动根据耗时设置单位
  */
@Test
public void testStopWatch() throws InterruptedException {
  Stopwatch stopwatch = Stopwatch.createStarted();
  TimeUnit.NANOSECONDS.sleep(500L);
  log.info("The process successful and elapsed [{}]", stopwatch.stop().elapsed());
}

/**
  * 得到程序执行的耗时,根据指定的单位获得
  */
@Test
public void testStopWatchWithUtil() throws InterruptedException {
  Stopwatch stopwatch = Stopwatch.createStarted();
  TimeUnit.NANOSECONDS.sleep(500L);
  log.info("The process successful and elapsed [{}]", stopwatch.stop().elapsed(TimeUnit.SECONDS));
}

Base编码-BaseEncoding

@Test
public void testBase64Encode() {
  String encodeResult = BaseEncoding.base64().encode("Hello".getBytes());
  assertThat(encodeResult, equalTo("SGVsbG8="));
}

@Test
public void testBase64Decode() {
  byte[] decodeResult = BaseEncoding.base64().decode("SGVsbG8=");
  assertThat(new String(decodeResult), equalTo("Hello"));
}

统一资源关闭类-Closer

@Test
public void testCloser() throws IOException {
  String TARGET_FILE = "F:\\IDEAWorkerspace\\练习\\guava-lean\\target.txt";

  String content = "Give me the strength lightly to bear my joys and sorrows." + "\n"
    + "Give me the strength to make my love fruitful in service" + "\n"
    + "Give me the strength never to disown the poor or bend my knees before insolent might." + "\n"
    + "Give me the strength to raise my mind high above daily trifles." + "\n"
    + "And give me the strength to surrender my strength to thy will with love.";
  Closer closer = Closer.create();
  try {
    File file = new File(TARGET_FILE);
    FileOutputStream outputStream = new FileOutputStream(file);
    // 注册入closer
    closer.register(outputStream);
  } catch (IOException e) {
    // 重新包装异常进行抛出,目的是如果finally抛出异常,try里面的异常将被替换掉
    throw closer.rethrow(e);
  } finally {
    // 执行关闭close
    closer.close();
  }
}

限流器

public class RateLimiterTest {

  // 从速率限流,令牌产生速率是每秒两个许可
  private final static RateLimiter limiter = RateLimiter.create(2);

  // 同时只能工作线程数,来自JDK5,限制同时处理的线程个数来限流
  private final static Semaphore semaphore = new Semaphore(3);

  @Test
  public void testLimiter() {
    while (true) {
      // 每次消耗4个令牌,即当前为2秒执行一次
      System.out.println(currentThread() + " waiting " + limiter.acquire(4));
    }
  }

  @Test
  public void testSemaphore() throws InterruptedException {
    ExecutorService service = Executors.newFixedThreadPool(10);
    for (int i = 0; i < 10; i++) {
      service.submit(() -> {
        while (true) {
          try {
            semaphore.acquire();
            System.out.println(currentThread().getName() + " is doing work...");
            TimeUnit.MILLISECONDS.sleep(ThreadLocalRandom.current().nextInt(10));
          } catch (InterruptedException e) {
            e.printStackTrace();
          }finally {
            semaphore.release();
            System.out.println(currentThread().getName() + " release the semaphore");
          }

        }
      });
    }
    TimeUnit.SECONDS.sleep(100);
  }
}

三、字符串处理

连接器-Joiner

把其它集合的数据处理,拼接成为字符串

public class JoinerTest {

  private final List<String> stringList = Arrays.asList("Google", "Guava", "Java", "Scala", "Kafka");

  private final List<String> stringListWithNull = Arrays.asList("Google", "Guava", "Java", "Scala", null);

  /**
    * 使用指定符合连接数组或List形成字符串
    */
  @Test
  public void testJoinerOn() {
    String result = Joiner.on("#").join(stringList);
    assertThat(result, equalTo("Google#Guava#Java#Scala#Kafka"));
  }

  /**
    * 连接数组或List(包含null)会抛出NullPointerException异常
    */
  @Test(expected = NullPointerException.class)
  public void testJoinerOnContainsNull() {
    Joiner.on("#").join(stringListWithNull);
  }

  /**
    * 连接数组或List(包含null),设置跳过null
    */
  @Test
  public void testJoinOnContainsNullButSkip() {
    String result = Joiner.on("#").skipNulls().join(stringListWithNull);
    assertThat(result, equalTo("Google#Guava#Java#Scala"));
  }

  /**
    * 连接数组或List(包含null),使用默认值替换null
    */
  @Test
  public void testJoinOnContainsNullUseDefaultValue() {
    String result = Joiner.on("#").useForNull("DV").join(stringListWithNull);
    assertThat(result, equalTo("Google#Guava#Java#Scala#DV"));
  }

  /**
    * 连接数组或List,将结果追加到StringBuilder中
    */
  @Test
  public void testJoinOnAppendToStringBuilder() {
    StringBuilder sb = new StringBuilder("Mysql#");
    StringBuilder result = Joiner.on("#").appendTo(sb, stringList);
    assertThat(result, sameInstance(sb));
    assertThat(result.toString(), equalTo("Mysql#Google#Guava#Java#Scala#Kafka"));
  }

  /**
    * 连接数组或List,将结果追加到Writer中
    */
  @Test
  public void testJoinOnAppendToWriter() throws IOException {
    Writer writer = new FileWriter("F:\\IDEAWorkerspace\\练习\\guava-lean\\writer.txt");
    Joiner.on("#").appendTo(writer, stringList);
    writer.close();

    byte[] bytes = Files.readAllBytes(Paths.get("F:\\IDEAWorkerspace\\练习\\guava-lean\\writer.txt"));
    String content = new String(bytes);
    assertThat(content, equalTo("Google#Guava#Java#Scala#Kafka"));

    File file = new File("F:\\IDEAWorkerspace\\练习\\guava-lean\\writer.txt");
    file.deleteOnExit();
  }

  /**
    * 使用java8实现join效果,还可使用filter进行过滤,map实现值处理等
    */
  @Test
  public void testJoiningStream() {
    String result = stringList.stream().map(str -> "*" + str + "*").collect(Collectors.joining("#"));
    assertThat(result, equalTo("*Google*#*Guava*#*Java*#*Scala*#*Kafka*"));
  }

  /**
   * 拼接Map数据成为字符串
   */
  @Test
  public void testJoinOnWithMap() {
    Map<String, String> params = ImmutableMap.of("name", "kun", "age", "18");
    String result = Joiner.on(",").withKeyValueSeparator("=").join(params);
    assertThat(result, equalTo("name=kun,age=18"));
  }
}

拆分器-Splitter

使用各种方式将字符串拆分为不同的集合

/**
  * 使用指字符串拆分字符串为List
  */
@Test
public void testSplitOn() {
  List<String> result = Splitter.on("#").splitToList("Java#Mysql#Guava");
  assertThat(result, notNullValue());
  assertThat(result.size(), equalTo(3));
  assertThat(result.get(0), equalTo("Java"));
  assertThat(result.get(1), equalTo("Mysql"));
  assertThat(result.get(2), equalTo("Guava"));
}

/**
  * 使用指字符串拆分字符串为List,忽略字符串切分出的空值
  */
@Test
public void testSplitOmitEmpty() {
  List<String> result = Splitter.on("#").splitToList("Java##");
  assertThat(result, notNullValue());
  assertThat(result.size(), equalTo(3));
  assertThat(result.get(0), equalTo("Java"));
  assertThat(result.get(1), equalTo(""));
  assertThat(result.get(2), equalTo(""));

  result = Splitter.on("#").omitEmptyStrings().splitToList("Java##");
  assertThat(result, notNullValue());
  assertThat(result.size(), equalTo(1));
  assertThat(result.get(0), equalTo("Java"));
}

/**
  * 使用指字符串拆分字符串为List,对切分出的List每个元素进行trim操作
  */
@Test
public void testSplitTrimResult() {
  List<String> result = Splitter.on("#").trimResults().splitToList(" Java # Mysql #  Guava");
  assertThat(result, notNullValue());
  assertThat(result.size(), equalTo(3));
  assertThat(result.get(0), equalTo("Java"));
  assertThat(result.get(1), equalTo("Mysql"));
  assertThat(result.get(2), equalTo("Guava"));
}

/**
  * 已指定长度拆分字符串为List
  */
@Test
public void testSplitFixLength() {
  List<String> result = Splitter.fixedLength(4).splitToList("AAAABBBBCCCC");
  assertThat(result, notNullValue());
  assertThat(result.size(), equalTo(3));
  assertThat(result.get(0), equalTo("AAAA"));
  assertThat(result.get(1), equalTo("BBBB"));
  assertThat(result.get(2), equalTo("CCCC"));
}

/**
  * 使用指字符串拆分字符串为List,且只切分出指定个数的元素
  */
@Test
public void testSplitLimit() {
  List<String> result = Splitter.on("#").limit(2).splitToList("Java#Mysql#Guava");
  assertThat(result, notNullValue());
  assertThat(result.size(), equalTo(2));
  assertThat(result.get(0), equalTo("Java"));
  assertThat(result.get(1), equalTo("Mysql#Guava"));
}

/**
  * 使用正则表达切分字符串
  */
@Test
public void testSplitPattern() {
  List<String> result = Splitter.onPattern("\\d+\\.")
    .omitEmptyStrings()
    .trimResults()
    .splitToList("1.Java 2.Mysql 3.Guava");
  assertThat(result, notNullValue());
  assertThat(result.size(), equalTo(3));
  assertThat(result.get(0), equalTo("Java"));
  assertThat(result.get(1), equalTo("Mysql"));
  assertThat(result.get(2), equalTo("Guava"));

  result = Splitter.on(Pattern.compile("\\d+\\."))
    .omitEmptyStrings()
    .trimResults()
    .splitToList("1.Java 2.Mysql 3.Guava");
  assertThat(result, notNullValue());
  assertThat(result.size(), equalTo(3));
  assertThat(result.get(0), equalTo("Java"));
  assertThat(result.get(1), equalTo("Mysql"));
  assertThat(result.get(2), equalTo("Guava"));
}

/**
  * 使用指定字符串为字符串切分符,使用指定分隔符为key-value,生成Map
  */
@Test
public void testSplitToMap() {
  Map<String, String> result = Splitter.on(",").withKeyValueSeparator("=").split("name=kun,age=18");
  assertThat(result, notNullValue());
  assertThat(result.get("name"), equalTo("kun"));
  assertThat(result.get("age"), equalTo("18"));
}

字符匹配器-CharMatcher

/**
  * 把每组连续的空白字符替换为特定字符
  */
@Test
public void testCharMatcherReplaceWhiteSpace() {
  String result = CharMatcher.whitespace().collapseFrom("1 2   3  4", '-');
  assertThat(result, equalTo("1-2-3-4"));
}

/**
  * 把字符串的匹配字符移除
  */
@Test
public void testCharMatcherAnyOperator() {
  String result = CharMatcher.anyOf("a").removeFrom("aHia");
  assertThat(result, equalTo("Hi"));
}

/**
  * 查看字符串是不是每个字符都在指定范围内
  */
@Test
public void testCharMatcherAny() {
  boolean result = CharMatcher.inRange('a', 'z').matchesAllOf("abc");
  assertThat(result, equalTo(true));
}

字符串简单处理-Strings

用于字符串的判空,填充,判断相同前后缀等操作

@Test
public void testStringsMethod() {
  // 如果字符串是空串"",则转换为null
  assertThat(Strings.emptyToNull(""), nullValue());

  // 如果字符串是null,则转化为空串""
  assertThat(Strings.nullToEmpty(null), equalTo(""));

  // 判断字符串是否为""或者null
  assertThat(Strings.isNullOrEmpty(""), equalTo(true));
  assertThat(Strings.isNullOrEmpty(null), equalTo(true));

  // 得到两个字符串的相同前缀
  assertThat(Strings.commonPrefix("Hello", "Her"), equalTo("He"));
  // 得到两个字符串的相同后缀
  assertThat(Strings.commonSuffix("goods", "books"), equalTo("s"));

  // 得到字符串重复三次的结果
  assertThat(Strings.repeat("Book", 3), equalTo("BookBookBook"));

  // 填充
  assertThat(Strings.padStart("kun", 5, '*'), equalTo("**kun"));
  assertThat(Strings.padEnd("kun", 5, '*'), equalTo("kun**"));
}

大小写格式-CaseFormat

/**
  * 格式	              范例
  * LOWER_CAMEL	        lowerCamel
  * LOWER_HYPHEN	      lower-hyphen
  * LOWER_UNDERSCORE	  lower_underscore
  * UPPER_CAMEL	        UpperCamel
  * UPPER_UNDERSCORE	  UPPER_UNDERSCORE
  */
@Test
public void testCaseFormat() {
  String result = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, "lowerCamel");
  assertThat(result,equalTo("LOWER_CAMEL"));
}

字符集-Charsets

直接创建了字符集对象,比JDK的Charset.forName更加便捷

/**
  * 比JDK的Charset.forName更加便捷
  */
@Test
public void testCharsets() {
  Charset charset = Charset.forName("UTF-8");
  assertThat(Charsets.UTF_8, equalTo(charset));
}

四、文件操作

向文件写入数据

@Test
public void testFileWrite() throws IOException {
  String content = "Give me the strength lightly to bear my joys and sorrows." + "\n"
    + "Give me the strength to make my love fruitful in service" + "\n"
    + "Give me the strength never to disown the poor or bend my knees before insolent might." + "\n"
    + "Give me the strength to raise my mind high above daily trifles." + "\n"
    + "And give me the strength to surrender my strength to thy will with love.";
  File file = new File(TARGET_FILE);
  file.deleteOnExit();
  Files.asCharSink(file, Charsets.UTF_8).write(content);

  String actually = Files.asCharSource(file, Charsets.UTF_8).read();
  assertThat(actually, equalTo(content));
}

向文件追加数据

@Test
public void testFileAppend() throws IOException {
  String contentFirst = "Give me the strength lightly to bear my joys and sorrows." + "\n"
    + "Give me the strength to make my love fruitful in service" + "\n";
  + "Give me the strength never to disown the poor or bend my knees before insolent might." + "\n";

  String contentSecond = "Give me the strength to raise my mind high above daily trifles." + "\n"
    + "And give me the strength to surrender my strength to thy will with love.";

  File file = new File(TARGET_FILE);
  file.deleteOnExit();
  Files.asCharSink(file, Charsets.UTF_8, FileWriteMode.APPEND).write(contentFirst);
  Files.asCharSink(file, Charsets.UTF_8, FileWriteMode.APPEND).write(contentSecond);

  String actually = Files.asCharSource(file, Charsets.UTF_8).read();
  assertThat(actually, equalTo(contentFirst + contentSecond));
}

创建空文件

@Test
public void testTouchFile() throws IOException {
  File file = new File(TARGET_FILE);
  file.deleteOnExit();
  Files.touch(file);
  assertThat(file.exists(), equalTo(true));
}

使用Guava拷贝文件

@Test
public void testCopyFileWithGuava() throws IOException {
  String content = "Give me the strength lightly to bear my joys and sorrows." + "\n"
    + "Give me the strength to make my love fruitful in service" + "\n"
    + "Give me the strength never to disown the poor or bend my knees before insolent might." + "\n"
    + "Give me the strength to raise my mind high above daily trifles." + "\n"
    + "And give me the strength to surrender my strength to thy will with love.";
  File sourceFile = new File(SOURCE_FILE);
  sourceFile.deleteOnExit();
  Files.asCharSink(sourceFile, Charsets.UTF_8).write(content);


  File targetFile = new File(TARGET_FILE);
  targetFile.deleteOnExit();
  Files.copy(sourceFile, targetFile);

  HashCode sourceHash = Files.asByteSource(sourceFile).hash(Hashing.sha256());
  HashCode targetHash = Files.asByteSource(targetFile).hash(Hashing.sha256());
  assertThat(targetHash.toString(), equalTo(sourceHash.toString()));
}

使用NIO拷贝文件

@Test
public void testCopyFileWithJDKNio() throws IOException {
  String content = "Give me the strength lightly to bear my joys and sorrows." + "\n"
    + "Give me the strength to make my love fruitful in service" + "\n"
    + "Give me the strength never to disown the poor or bend my knees before insolent might." + "\n"
    + "Give me the strength to raise my mind high above daily trifles." + "\n"
    + "And give me the strength to surrender my strength to thy will with love.";
  File sourceFile = new File(SOURCE_FILE);
  sourceFile.deleteOnExit();
  Files.asCharSink(sourceFile, Charsets.UTF_8).write(content);

  File targetFile = new File(TARGET_FILE);
  targetFile.deleteOnExit();
  java.nio.file.Files.copy(Paths.get(SOURCE_FILE), new FileOutputStream(targetFile));

  HashCode sourceHash = Files.asByteSource(sourceFile).hash(Hashing.sha256());
  HashCode targetHash = Files.asByteSource(targetFile).hash(Hashing.sha256());
  assertThat(targetHash.toString(), equalTo(sourceHash.toString()));
}

剪切文件

@Test
public void testMoveFile() throws IOException {
  String content = "Give me the strength lightly to bear my joys and sorrows." + "\n"
    + "Give me the strength to make my love fruitful in service" + "\n"
    + "Give me the strength never to disown the poor or bend my knees before insolent might." + "\n"
    + "Give me the strength to raise my mind high above daily trifles." + "\n"
    + "And give me the strength to surrender my strength to thy will with love.";
  File sourceFile = new File(SOURCE_FILE);
  Files.asCharSink(sourceFile, Charsets.UTF_8).write(content);

  File targetFile = new File(TARGET_FILE);
  targetFile.deleteOnExit();
  Files.move(sourceFile, targetFile);

  String actually = Files.asCharSource(targetFile, Charsets.UTF_8).read();
  assertThat(actually, equalTo(content));
}

读取文件

@Test
public void testRead() throws IOException {
  String content = "Give me the strength lightly to bear my joys and sorrows." + "\n"
    + "Give me the strength to make my love fruitful in service" + "\n"
    + "Give me the strength never to disown the poor or bend my knees before insolent might." + "\n"
    + "Give me the strength to raise my mind high above daily trifles." + "\n"
    + "And give me the strength to surrender my strength to thy will with love.";
  File sourceFile = new File(SOURCE_FILE);
  Files.asCharSink(sourceFile, Charsets.UTF_8).write(content);
  sourceFile.deleteOnExit();

  // 读取所有文件内容
  String actuallyAllContent = Files.asCharSource(sourceFile, Charsets.UTF_8).read();
  assertThat(actuallyAllContent, equalTo(content));

  // 按行读取文件内容
  ImmutableList<String> lines = Files.asCharSource(sourceFile, Charsets.UTF_8).readLines();
  assertThat(lines, notNullValue());
  assertThat(lines.size(), equalTo(5));
}

递归获取文件列表

/**
  * 递归获取文件列表(包含文件夹),可将结果使用Lists.newArrayList(breadthFirstFiles).stream()来进行处理
  *   breadthFirst          横向有限,先读取第一层目录,再读取第二层,广度优先
  *   depthFirstPreOrder    第一次访问到节点的顺序
  *   depthFirstPostOrder   先访问到最后一层,然后回退访问节点的顺序
  */
@Test
public void testRecursive() {
  File file = new File("F:\\IDEAWorkerspace\\练习\\guava-lean");
  Iterable<File> breadthFirstFiles = Files.fileTraverser().breadthFirst(file);
  breadthFirstFiles.forEach(System.out::println);

  Iterable<File> depthFirstPostOrderFiles = Files.fileTraverser().depthFirstPostOrder(file);
  depthFirstPostOrderFiles.forEach(System.out::println);

  Iterable<File> depthFirstPreOrderFiles = Files.fileTraverser().depthFirstPreOrder(file);
  depthFirstPreOrderFiles.forEach(System.out::println);
}

五、集合

Lists工具集

/**
  * 两个集合做笛卡尔积
  * cartesian 笛卡尔积
  */
@Test
public void testCartesianProduct() {
  // [[A, C], [A, D], [B, C], [B, D]]
  List<List<String>> cartesianProduct = Lists.cartesianProduct(
    Lists.newArrayList("A", "B"),
    Lists.newArrayList("C", "D"));
  assertThat(cartesianProduct.size(), equalTo(4));
}

/**
  * 处理加工原有的List产生新的List
  */
@Test
public void testTransform() {
  ArrayList<String> sourceList = Lists.newArrayList("Scala", "Guava", "Lists");
  List<String> result = Lists.transform(sourceList, String::toUpperCase);
  assertThat(result.size(), equalTo(3));
  assertThat(result.get(0), equalTo("SCALA"));
  assertThat(result.get(1), equalTo("GUAVA"));
  assertThat(result.get(2), equalTo("LISTS"));
}

/**
  * 将List内元素反转返回新的List
  */
@Test
public void testReverse() {
  ArrayList<String> sourceList = Lists.newArrayList("Scala", "Guava", "Lists");
  List<String> result = Lists.reverse(sourceList);
  assertThat(result.size(), equalTo(3));
  assertThat(result.get(0), equalTo("Lists"));
  assertThat(result.get(1), equalTo("Guava"));
  assertThat(result.get(2), equalTo("Scala"));
}

/**
  * 将List内数据进行分区
  */
@Test
public void testPartition(){
  // [[Scala, Guava], [Lists]]
  ArrayList<String> sourceList = Lists.newArrayList("Scala", "Guava", "Lists");
  List<List<String>> result = Lists.partition(sourceList, 2);
}

Sets工具集

/**
  * 创建Set
  */
@Test
public void testCreate() {
  HashSet<String> sourceSet = Sets.newHashSet("A", "B", "C", "A");
  assertThat(sourceSet.size(), equalTo(3));
}

/**
  * 生成笛卡尔积
  */
@Test
public void testCartesianProduct() {
  HashSet<String> sourceSetFirst = Sets.newHashSet("A", "B", "C");
  HashSet<String> sourceSetSecond = Sets.newHashSet("A", "D", "E");
  // [[A, A], [A, D], [A, E], [B, A], [B, D], [B, E], [C, A], [C, D], [C, E]]
  Set<List<String>> result = Sets.cartesianProduct(sourceSetFirst, sourceSetSecond);
  System.out.println(result);
}

/**
  * 产生所有规定个数的子集
  */
@Test
public void testCombinations() {
  HashSet<String> sourceSet = Sets.newHashSet("A", "B", "C");
  Set<Set<String>> result = Sets.combinations(sourceSet, 2);
  result.forEach(System.out::println);
}

/**
  * 取差集
  */
@Test
public void testDiff() {
  HashSet<String> sourceSetFirst = Sets.newHashSet("A", "B", "C", "F");
  HashSet<String> sourceSetSecond = Sets.newHashSet("A", "D", "E");
  Sets.SetView<String> diffView = Sets.difference(sourceSetFirst, sourceSetSecond);
  //[B, C, F]
  System.out.println(diffView);
}

/**
  * 取交集
  */
@Test
public void testIntersection() {
  HashSet<String> sourceSetFirst = Sets.newHashSet("A", "B", "C", "F");
  HashSet<String> sourceSetSecond = Sets.newHashSet("A", "D", "E");
  Sets.SetView<String> interView = Sets.intersection(sourceSetFirst, sourceSetSecond);
  //[A]
  System.out.println(interView);
}

/**
  * 取并集
  */
@Test
public void testUnionSection() {
  HashSet<String> sourceSetFirst = Sets.newHashSet("A", "B", "C");
  HashSet<String> sourceSetSecond = Sets.newHashSet("A", "D", "E");
  Sets.SetView<String> unionView = Sets.union(sourceSetFirst, sourceSetSecond);
  // [A, B, C, D, E]
  System.out.println(unionView);
}

Maps工具集

/**
  * 将一个Map进行处理生成另一个Map
  */
@Test
public void testMapTransform() {
  HashMap<Integer, String> sourceMap = Maps.newHashMap();
  sourceMap.put(1, "Java");
  sourceMap.put(2, "Guava");

  Map<Integer, String> newMap = Maps.transformEntries(sourceMap, (key, value) -> {
    return "#" + value + "#";
  });

  assertThat(newMap.get(1), equalTo("#Java#"));
  assertThat(newMap.get(2), equalTo("#Guava#"));
}

/**
  * 过滤Map生成另一个Map
  */
@Test
public void testMapFilter() {
  HashMap<Integer, String> sourceMap = Maps.newHashMap();
  sourceMap.put(1, "Java");
  sourceMap.put(2, "Guava");

  Map<Integer, String> filterMap = Maps.filterEntries(sourceMap, entry -> entry.getKey() != 1);

  assertThat(filterMap.get(1), nullValue());
  assertThat(filterMap.get(2), equalTo("Guava"));
}

/**
  * 可以用一个key对应多个value的Map
  */
@Test
public void testMultiMapBasic() {
  LinkedListMultimap<Integer, String> multimap = LinkedListMultimap.create();
  multimap.put(1, "Java");
  multimap.put(1, "Guava");

  assertThat(multimap.size(), equalTo(2));
  assertThat(multimap.get(1).get(0), equalTo("Java"));
  assertThat(multimap.get(1).get(1), equalTo("Guava"));
}

/**
  * Value不能重复的Map
  */
@Test
public void testBiMapCreate() {
  HashBiMap<Integer, String> biMap = HashBiMap.create();
  biMap.put(1, "Java");
  biMap.put(1, "Guava");
  assertThat(biMap.containsKey(1), equalTo(true));
  assertThat(biMap.size(), equalTo(1));
  assertThat(biMap.get(1), equalTo("Guava"));

  try {
    biMap.put(2, "Guava");
    fail();
  } catch (Exception e) {
    assertThat(e, is(instanceOf(IllegalArgumentException.class)));
  }
}

/**
  * BiMap的Key-Value进行反转
  */
@Test
public void testBiMapInverse() {
  HashBiMap<Integer, String> biMap = HashBiMap.create();
  biMap.put(1, "Java");
  biMap.put(2, "Guava");
  biMap.put(3, "Mysql");

  BiMap<String, Integer> inverseResult = biMap.inverse();
  assertThat(inverseResult.size(), equalTo(3));
  assertThat(inverseResult.get("Java"), equalTo(1));
  assertThat(inverseResult.get("Guava"), equalTo(2));
  assertThat(inverseResult.get("Mysql"), equalTo(3));

}

/**
  * BiMap强制放入数据,会删除原有value相同的key
  */
@Test
public void testBiForcePut() {
  HashBiMap<Integer, String> biMap = HashBiMap.create();
  biMap.put(1, "Java");
  biMap.forcePut(2, "Java");
  assertThat(biMap.size(), equalTo(1));
  assertThat(biMap.get(1), nullValue());
  assertThat(biMap.get(2), equalTo("Java"));
}

Table工具

生成类似Excel的内存表格,实现有:ArrayTableTreeBaseTableHashBaseTableImmutableTable

@Test
public void testTable() {
  Table<String, String, String> table = HashBasedTable.create();
  table.put("Language", "Java", "1.8");
  table.put("Language", "Scala", "2.3");
  table.put("Database", "Oracle", "12C");
  table.put("Database", "Mysql", "8.0");

  Map<String, String> language = table.row("Language");
  assertThat(language.containsKey("Java"), is(true));
  assertThat(language.get("Java"), equalTo("1.8"));
  assertThat(language.get("Scala"), equalTo("2.3"));

  // [(Language,Java)=1.8, (Language,Scala)=2.3, (Database,Oracle)=12C, (Database,Mysql)=8.0]
  Set<Table.Cell<String, String, String>> cells = table.cellSet();
  System.out.println(cells);
}

创建不可变集合

public class ImmutableCollectionsTest {

  @Test(expected = UnsupportedOperationException.class)
  public void testImmutableOf() {
    ImmutableList<String> list = ImmutableList.of("A", "B", "C", "D");
    assertThat(list, notNullValue());
    list.add("E");
  }

  @Test(expected = UnsupportedOperationException.class)
  public void testImmutableCopy() {
    Integer[] array = {1, 2, 3, 4, 5};
    ImmutableList<Integer> list = ImmutableList.copyOf(array);
    list.add(6);
  }

  @Test(expected = UnsupportedOperationException.class)
  public void testImmutableBuild() {
    ImmutableList<Integer> list = ImmutableList.<Integer>builder().add(1).add(2).add(3).build();
    list.add(4);
  }

  @Test(expected = UnsupportedOperationException.class)
  public void testImmutableMap() {
    ImmutableMap<Integer, String> map = ImmutableMap.<Integer, String>builder()
      .put(1, "Java").put(2, "Guava").build();
    map.put(3, "Mysql");
  }
}

六、缓存

创建基本缓存对象

@Test
public void testBasic() {
  Cache<Integer, String> cache = CacheBuilder.newBuilder().maximumSize(3).build();
  cache.put(1, "Java");
  cache.put(2, "MySql");
  cache.put(3, "Guava");

  String cacheValue = cache.getIfPresent(1);
  assertThat(cacheValue, equalTo("Java"));

  cache.put(4, "Redis");

  cacheValue = cache.getIfPresent(2);
  assertThat(cacheValue, nullValue());
}

通过CacheLoader创建缓存对象

@Test
public void testCacheLoader() {
  CacheLoader<Integer, String> cacheLoader = new CacheLoader<Integer, String>() {
    @Override
    public String load(Integer key) throws Exception {
      return "#" + key + "#";
    }
  };

  LoadingCache<Integer, String> cache = CacheBuilder.newBuilder().maximumSize(3).build(cacheLoader);

  String cacheValue = cache.getUnchecked(1);
  assertThat(cacheValue, equalTo("#1#"));

  cacheValue = cache.getUnchecked(2);
  assertThat(cacheValue, equalTo("#2#"));

  cacheValue = cache.getUnchecked(3);
  assertThat(cacheValue, equalTo("#3#"));

  cacheValue = cache.getUnchecked(4);
  assertThat(cacheValue, equalTo("#4#"));

  assertThat(cache.getIfPresent(1), nullValue());
  assertThat(cache.getIfPresent(4), notNullValue());
}

通过Weigher权重设置数量

@Test
public void testCacheWeight() {
  CacheLoader<Integer, String> cacheLoader = new CacheLoader<Integer, String>() {
    @Override
    public String load(Integer key) throws Exception {
      return "#" + key + "#";
    }
  };

  Weigher<Integer, String> weigher = (key, value) -> key;

  LoadingCache<Integer, String> cache = CacheBuilder.newBuilder()
    .maximumWeight(10).weigher(weigher).build(cacheLoader);

  cache.getUnchecked(1);
  cache.getUnchecked(2);
  cache.getUnchecked(3);
  cache.getUnchecked(4);
  cache.getUnchecked(5);

  assertThat(cache.getIfPresent(1), nullValue());
  assertThat(cache.getIfPresent(2), nullValue());
  assertThat(cache.getIfPresent(3), nullValue());
  assertThat(cache.getIfPresent(4), equalTo("#4#"));
  assertThat(cache.getIfPresent(5), equalTo("#5#"));
}

设置存活时间

/**
  * 创建一个缓存对象,通过以访问的最后时间为锚点,设置存活时间
  */
@Test
public void testAccessTTL() throws InterruptedException {
  Cache<Integer, String> cache = CacheBuilder.newBuilder()
    .expireAfterAccess(1, TimeUnit.SECONDS).build();
  cache.put(1, "Java");
  String cacheValue = cache.getIfPresent(1);
  assertThat(cacheValue, equalTo("Java"));

  TimeUnit.MILLISECONDS.sleep(700L);
  cacheValue = cache.getIfPresent(1);
  assertThat(cacheValue, equalTo("Java"));

  TimeUnit.MILLISECONDS.sleep(700L);
  cacheValue = cache.getIfPresent(1);
  assertThat(cacheValue, equalTo("Java"));

  TimeUnit.MILLISECONDS.sleep(1200L);
  cacheValue = cache.getIfPresent(1);
  assertThat(cacheValue, nullValue());
}

/**
  * 创建一个缓存对象,通过以写入时间为锚点,设置存活时间
  */
@Test
public void testWriteTTL() throws InterruptedException {
  Cache<Integer, String> cache = CacheBuilder.newBuilder()
    .expireAfterWrite(1, TimeUnit.SECONDS).build();
  cache.put(1, "Java");
  String cacheValue = cache.getIfPresent(1);
  assertThat(cacheValue, equalTo("Java"));

  TimeUnit.SECONDS.sleep(2L);

  cacheValue = cache.getIfPresent(1);
  assertThat(cacheValue, nullValue());
}

弱、虚、幻引用

/**
  * JVM argument: -Xms64m -Xmx64m -XX:+PrintGCDetails
  * 设置强引用(默认)、软引用(Safe)、弱引用(weak)、虚引用(Phantom)
  * 软引用:当JVM内存紧缺时GC开始回收
  * 弱引用:当执行GC时开始回收
  * 虚引用:主要用来跟踪对象被垃圾回收器回收的活动,虚引用必须和引用队列 (ReferenceQueue)联合使用。
  * 当GC准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列
  */
@Test
public void testRefType() throws InterruptedException {
  Cache<Integer, Byte[]> cache = CacheBuilder.newBuilder().softValues().build();
  int i = 0;
  while (true) {
    cache.put(++i, new Byte[1024 * 1024]);
    System.out.println("The [" + i + "] element is store into cache.");
    TimeUnit.MILLISECONDS.sleep(500);
  }
}

/**
  * 虚引用使用示例
  */
@Test
public void testPhantomReference() throws Exception {
  byte[] values = new byte[1024 * 1024 * 6];
  ReferenceQueue<byte[]> referenceQueue = new ReferenceQueue<>();
  PhantomReference<byte[]> phantomReference = new PhantomReference<>(values, referenceQueue);
  // 第一次未执行时,ReferenceQueue为空
  Reference<? extends byte[]> ref = referenceQueue.remove(100L);
  assertThat(ref, nullValue());
  values = null;
  System.gc();

  // 执行完GC时,values被释放,加入到ReferenceQueue
  TimeUnit.SECONDS.sleep(1L);
  ref = referenceQueue.remove(100L);
  Field referentField = Reference.class.getDeclaredField("referent");
  referentField.setAccessible(true);
  values = (byte[]) referentField.get(ref);
  assertThat(values, notNullValue());
}

获取Value为null处理

/**
  * 直接通过缓存的Key获取对象为null时会抛出InvalidCacheLoadException异常
  */
@Test
public void testLoadNullWithException() {
  CacheLoader<Integer, String> cacheLoader = new CacheLoader<Integer, String>() {
    @Override
    public String load(Integer key) throws Exception {
      return null;
    }
  };

  LoadingCache<Integer, String> cache = CacheBuilder.newBuilder().build(cacheLoader);

  try {
    cache.getUnchecked(1);
    fail();
  } catch (Exception e) {
    assertThat(e, is(instanceOf(CacheLoader.InvalidCacheLoadException.class)));
  }
}

/**
  * 直接通过缓存的Key获取对象为Optional时可根据情况获取null值
  */
@Test
public void testLoadNullWihOptional() {
  CacheLoader<Integer, Optional<String>> cacheLoader = new CacheLoader<Integer, Optional<String>>() {
    @Override
    public Optional<String> load(Integer key) throws Exception {
      return Optional.ofNullable(null);
    }
  };

  LoadingCache<Integer, Optional<String>> cache = CacheBuilder.newBuilder().build(cacheLoader);

  Optional<String> value = cache.getUnchecked(1);
  assertThat(value.isPresent(), equalTo(false));
}

设置缓存初始化值

@Test
public void testCachePreLoad() {
  CacheLoader<String, String> loader = CacheLoader.from(String::toUpperCase);
  LoadingCache<String, String> cache = CacheBuilder.newBuilder().build(loader);
  Map<String, String> preData = ImmutableMap.of("kun", "kun", "tbb", "tbb");
  cache.putAll(preData);

  assertThat(cache.getUnchecked("kun"), equalTo("kun"));
  assertThat(cache.getUnchecked("tbb"), equalTo("tbb"));
  assertThat(cache.getUnchecked("jack"), equalTo("JACK"));
}

刷新缓存

@Test
public void testCacheRefresh() throws InterruptedException {
  AtomicInteger count = new AtomicInteger(0);
  CacheLoader<String, Integer> loader = CacheLoader.from(key -> count.getAndIncrement());
  LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
    .refreshAfterWrite(1, TimeUnit.SECONDS).build(loader);

  Integer key = cache.getUnchecked("key");
  assertThat(key, equalTo(0));
  key = cache.getUnchecked("key");
  assertThat(key, equalTo(0));

  TimeUnit.SECONDS.sleep(1L);
  key = cache.getUnchecked("key");
  assertThat(key, equalTo(1));
}

缓存移除通知

@Test
public void testCacheRemovedNotification() {
  RemovalListener<String, String> listener = notification -> {
    // 状态时被移除
    if (notification.wasEvicted()) {
      RemovalCause cause = notification.getCause();
      /**
          * 被移除的原因
          *   RemovalCause.EXPLICIT    显示的使缓存失效,invalidate,invalidateAll
          *   RemovalCause.REPLACED    值被另一个值替代
          *   RemovalCause.COLLECTED   软引用、弱引用被垃圾回收器回收
          *   RemovalCause.EXPIRED     超过TTL时间
          *   RemovalCause.SIZE        超过缓存大小
          */
      assertThat(cause, is(RemovalCause.SIZE));
      assertThat(notification.getKey(), equalTo("Tom"));
    }
  };

  CacheLoader<String, String> loader = CacheLoader.from(String::toUpperCase);
  LoadingCache<String, String> cache = CacheBuilder.newBuilder()
    .maximumSize(3).removalListener(listener).build(loader);
  cache.getUnchecked("Tom");
  cache.getUnchecked("Jack");
  cache.getUnchecked("Jane");
  cache.getUnchecked("Rose");
}

获取缓存状态

@Test
public void testCacheStatInfo() {
  CacheLoader<String, String> loader = CacheLoader.from(String::toUpperCase);
  LoadingCache<String, String> cache = CacheBuilder.newBuilder()
    .maximumSize(3).recordStats().build(loader);

  assertThat(cache.getUnchecked("Kun"), equalTo("KUN"));
  CacheStats stats = cache.stats();
  assertThat(stats.hitCount(), equalTo(0L));
  assertThat(stats.missCount(), equalTo(1L));

  assertThat(cache.getUnchecked("Kun"), equalTo("KUN"));
  stats = cache.stats();
  assertThat(stats.hitCount(), equalTo(1L));
  assertThat(stats.missCount(), equalTo(1L));

  assertThat(BigDecimal.valueOf(stats.missRate()), equalTo(BigDecimal.valueOf(0.5)));
  assertThat(BigDecimal.valueOf(stats.hitRate()), equalTo(BigDecimal.valueOf(0.5)));
}