随笔分类
Guava
Google开源的 Guava框架,本身其实是对 JDK内部一些并发容器、工具的优化,源码方面也是比较值得去学习的
Google Guava的维护团队推崇敏捷开发,持续迭代以及版本的维护,主要维护者便是 《Effective Java》一书作者
Guava库其实是锦上添花的存在,正确使用 Guava可以使得我们代码开发更加简洁,但注意一点,不要为了使用 Guava而使用 Guava,适用前提仍是实用性为主
一开始此 Library并不叫 Guava来着,原名 Google-Collections
Utilities
Guava提供的工具集
Joiner
Concatenate strings together with a specified delimiter
针对字符串连接开发的工具
private List<String> lists1 = Arrays.asList(
"Google", "Guava", "Zookeeper", "Dubbo"
);
private List<String> lists2 = Arrays.asList(
"Google", "Guava", "Zookeeper", "Dubbo", null
);
private Map<String, String> map = Map.of(
"name", "yehen",
"age", "18"
);
private static final String FILE_NAME = "./joinAppendable.txt";
/**
* 常用姿势
*/
@Test
public void testJoinOnJoin() {
String res1 = Joiner.on("&")
.join(lists1);
System.out.println(res1);
Assert.assertEquals(res1, "Google&Guava&Zookeeper&Dubbo");
}
/**
* 空值引发的惨案
*/
@Test(expected = NullPointerException.class)
public void testJoinOnJoinWithinNull() {
String res1 = Joiner.on("&")
.join(lists2);
Assert.assertEquals(res1, "Google&Guava&Zookeeper&Dubbo");
}
/**
* 处理空值 - 其实 Stream也可以实现, Joiner无疑就是锦上添花
*/
@Test
public void testJoinOnJoinSkipAndInsteadNull() {
String res1 = Joiner.on("&")
.useForNull("Java")
//.skipNulls() // 单纯跳过 null以来避免空指针
.join(lists2);
Assert.assertEquals(res1, "Google&Guava&Zookeeper&Dubbo&Java");
}
/**
* 追加方式
*/
@Test
public void testJoinOnAppendable() {
StringBuilder builder = new StringBuilder("Apache&");
StringBuilder res1 = Joiner.on("&")
.skipNulls()
.appendTo(builder, lists2);
// 对象地址未发生变化, 内部容器追加操作
Assert.assertSame(builder, res1);
Assert.assertEquals(builder.toString(), "Apache&Google&Guava&Zookeeper&Dubbo");
}
/**
* 追加到文件中去
*/
@Test
public void testJoinOnAppendableFile() {
File file;
try (FileWriter fileWriter = new FileWriter(new File(FILE_NAME))) {
FileWriter writer = Joiner.on("&")
.skipNulls()
.appendTo(fileWriter, lists2);
Assert.assertTrue(Files.isFile().test(new File(FILE_NAME)));
} catch (IOException exp) {
Assert.fail(exp.getMessage());
}
}
/**
* 处理 Entry键值对
*/
@Test
public void testJoinWithKeyValueSeparator() {
String res1 = Joiner.on(" ")
.withKeyValueSeparator("=")
.join(map);
Assert.assertEquals(res1, "name=yehen age=18");
}
Splitter
produce substrings broken out by the provided delimiter
分割字符串的若干增强处理
/**
* 拆分成列表、迭代器
*/
@Test
public void testSplitterOnSplit() {
List<String> res1 = Splitter.on("|")
.splitToList("hello|world");
assertEquals(res1.size(), 2);
assertEquals(res1.get(0), "hello");
assertEquals(res1.get(1), "world");
}
/**
* 对字符串的若干处理:自定义分隔符、消除冗余元素
*/
@Test
public void testSplitterOnOmitNull() {
String strs = "hello | world |||";
List<String> res1 = Splitter.on("|")
.splitToList(strs);
assertEquals(res1.size(), 5);
// 忽略 null
List<String> res2 = Splitter.on("|")
.omitEmptyStrings()
.splitToList(strs);
assertEquals(res2.size(), 2);
// 消除空字符
List<String> res3 = Splitter.on("|")
.omitEmptyStrings()
.trimResults(CharMatcher.is(' '))
.splitToList(strs);
assertEquals(res3.size(), 2);
assertEquals(res3.get(0), "hello");
assertEquals(res3.get(1), "world");
}
/**
* 固定长度划分
* aaa
* bbb
* ccc
*/
@Test
public void testSplitterOnFixLength() {
Splitter.fixedLength(3)
.splitToStream("aaabbbccc")
.forEach(System.out::println);
}
/**
* limit限制最多可分割出来的字符串数量
*/
@Test
public void testSplitterOnLimit() {
List<String> res1 = Splitter.on("&")
.limit(3)
.splitToList("hello&world&Google&Guava&ZK&Dubbo");
assertEquals(res1.size(), 3);
assertEquals(res1.get(0), "hello");
assertEquals(res1.get(1), "world");
assertEquals(res1.get(2), "Google&Guava&ZK&Dubbo");
}
@Test
public void testSplitterOnWithKeyValueToMap() {
Map<String, String> map = Splitter.on("|")
.trimResults()
.withKeyValueSeparator("=")
.split("name=liangye | age=20");
assertEquals(map.size(), 2);
assertEquals(map.get("name"), "liangye");
assertEquals(map.get("age"), "20");
}
Preconditions
Methods for asserting certain conditions you expect variables
基于 Preconditions扩展实现一些断言判定
/**
* 校验空值
*
* @param list
*/
private void checkNotNull(final List<String> list) {
Preconditions.checkNotNull(list, "the list cannot be null!");
}
/**
* 自定义校验参数逻辑
*
* @param list
*/
private void checkArgument(final List<String> list) {
Preconditions.checkArgument(Objects.nonNull(list) && list.size() >= 2,
"the argument cannot be null and size must > 2");
}
/**
* 校验状态 - 关键在于我们对状态的定义
* 如:线程池关闭时不允许再去提交任务
* 互斥锁不允许同时持有等
*
* @param state
*/
private void checkState(Boolean state) {
Preconditions.checkState(state, "the state is illegal!");
}
@Test(expected = NullPointerException.class)
public void testForCheckNotNull() {
checkNotNull(null);
}
/**
* java.lang.IllegalArgumentException: the argument cannot be null and size must > 2
*/
@Test
public void testForCheckArgument() {
checkArgument(Arrays.asList("liangye"));
}
@Test
public void testForCheckState() {
try {
checkState(Boolean.FALSE);
} catch (Exception exp) {
Assert.assertEquals(exp.getClass(), IllegalStateException.class);
}
}
/**
* 校验边界
*/
@Test(expected = IndexOutOfBoundsException.class)
public void testForCheckIndex() {
final List list = Arrays.asList("liangye", "tiandankanfeng");
Preconditions.checkElementIndex(3, list.size());
}
/**
* Assert的语法糖
*/
@Test
public void testForAssertMessage() {
try {
final List<String> list = null;
assert list != null : "the list cannot be null!";
} catch (Error error) { // exception区别于 Error
Assert.assertEquals(error.getClass(), AssertionError.class);
Assert.assertEquals(error.getMessage(), "the list cannot be null!");
}
}
Objects&MoreObjects& Comparsion
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
static class Guava implements Comparable<Guava> {
private String version;
private String manufacture;
private String developer;
private Long years;
/**
* 使用 Guava的 toString()
* 只去 care有值的字段
*/
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.omitNullValues() // 忽略空值
.add("version", version)
.add("manufacture", manufacture)
.add("developer", developer)
.add("years", years)
.toString();
}
@Override
public int hashCode() {
// 这种是已经废弃的写法
//return Objects.hashCode(this.getVersion(), this.getDeveloper(),
// this.getManufacture(), this.getYears());
return Objects.hash(this.getVersion(), this.getDeveloper(),
this.getManufacture(), this.getYears());
}
public int originHashCode() {
return super.hashCode();
}
/**
* 基于语句比较链实现 compareTo()
* 坑:容易引发空指针异常
* @param o
* @return
*/
@Override
public int compareTo(Guava o) {
return ComparisonChain.start()
.compare(this.getVersion(), o.getVersion())
.compare(this.getDeveloper(), o.getDeveloper())
.compare(this.getManufacture(), o.getManufacture())
.compare(this.getYears(), o.getYears())
.result();
}
}
@Test
public void testObjectsOnToString() {
Guava guava = new Guava();
guava.setDeveloper("yehen");
guava.setVersion("1.0.0");
//guava.setManufacture("night");
guava.setYears(3L);
System.out.println(guava);
}
@Test
public void testObjectsOnCompareTo() {
Guava guava = Guava.builder()
.developer("yehen")
.version("1.0.0")
.manufacture("sky")
.years(1L)
.build();
Guava guava2 = Guava.builder()
.developer("yehen")
.version("1.0.0")
.manufacture("sky")
.years(3L)
.build();
System.out.println(guava.compareTo(guava2));
}
/**
* 由此可见, java.util.Objects.hash的hashCode相较之下还是比较高效的
*/
@Test
public void testObjectsOnHash() {
Guava guava = Guava.builder()
.developer("yehen")
.version("1.0.0")
.manufacture("sky")
.years(1L)
.build();
Stopwatch stopwatch = Stopwatch.createStarted();
// 65
int guavaHash = guava.hashCode();
Long first = stopwatch.elapsed(TimeUnit.MICROSECONDS);
int hashCode = guava.originHashCode();
// 277
Long second = stopwatch.elapsed(TimeUnit.MICROSECONDS);
System.out.println(first + " " + second);
}
Strings&Charsets&CharNatcher
@Test
public void testStringsOnCustomizedMethod() {
assertEquals(Strings.emptyToNull(""), null);
assertEquals(Strings.nullToEmpty(null), StrUtil.EMPTY);
assertEquals(Strings.nullToEmpty("yehen"), "yehen");
// 公共
assertEquals(Strings.commonPrefix("hello", "hallo"), "h");
assertEquals(Strings.commonSuffix("hello", "hallo"), "llo");
assertEquals(Strings.repeat("ha", 3), "hahaha");
assertEquals(Strings.isNullOrEmpty(""), Boolean.TRUE );
// padding
assertEquals(Strings.padStart("ha", 6, 'y'), "yyyyha");
assertEquals(Strings.padEnd("ha", 6, 'y'), "hayyyy");
}
@Test
public void testCharsets() {
// jdk其实就是参考 Guava的 - 很多设计理念都是
assertEquals(Charsets.UTF_8, StandardCharsets.UTF_8);
}
@Test
public void testCharMatcher() {
assertEquals(CharMatcher.ascii().matches('9'), Boolean.TRUE);
// 格式化字符串并进行转化
assertEquals(CharMatcher.breakingWhitespace().collapseFrom(" hello world ", '&'), "&hello&world&");
assertEquals(CharMatcher.is('h').countIn("hehaha"), 3);
// 移除指定字符:这在某些场景下比较适用
assertEquals(CharMatcher.breakingWhitespace().or(CharMatcher.javaDigit()).removeFrom(" hello World 123 "), "helloWorld");
}