Guava

工具

Joiner 字符拼接

1、Joiner | JDK8 Stream 字符拼接常见操作:

  • 不带空元素的拼接
  • 对空元素使用默认值拼接
  • 写入文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
String result=Joiner.on("#").join(stringList);
String result =Joiner.on("#").userorNull("DEAULT").join(stringListwithNull);

final StringBuilder builder=new StringBuilder();
StringBuilder resultBuilder=Joiner.on("#")
.useForNull("DEFAULT")
.appendTo(builder, stringListwithNullval);

// Writer
try (Filewriter writer = new Filewriter(new File(targetFileName))) {
Joiner.on("#")
.useForNull("DEFAULT")
.appendTo(writer, stringListwithNullValue);
} catch (IOException e) {
fail("append to the writer occur fetal error.");
}

JDK8 中的 Join 中的 Stream:跳过 Null 值

1
2
3
4
5
6
7
8
9
10
String result=stringListwithNullValue.stream()
.filter(item->item!=null && !item.isEmpty()).collect(joining("#"));
// null to defalut
String result=stringListwithNullValue.stream()
.map(item->item==null || item.isEmpty()?"DEFAULT":item).collect(joining("#"));
// function infer
public void testJoiningByStreamwithDefaultyalue(){
string result =stringListwithNullValue.stream()
.map(this::defaultValue)
.collect(joining("#"));

2、Map 拼接 将 Map 的键值按照特定分隔符进行拼接 默认 key 和 val 通过 = 进行拼接

1
2
3
4
5
6
7
8
9
10
// join map
private final Map<String,string> stringMap = of("Hello","Guaga","Java","Scala");
assertThat(Joiner.on('#").withKeyValueSeparator("=").join(stringMap), equalTo("Hello=Guava#Java=Scala"));

try(FileWriter writer=new Filewriter(new File(targetFileNameToMap))){
Joiner.on("#").withKeyValueSeparator("=").appendTo(writer, stringMap);
assertThat(Files.isFile().test(new File(targetFileNameToMap)), equalTo(true));
} catch (IOException e){
fail("append to the writer occur fetal error.");
}

Splitter 字符分隔

剔除一些无用的 按照特定分隔符分隔并转化成 List 剔除掉空的字符并转化成 List

指定分隔符 剔除 Blank 字符 剔除剔除 Empty 字符 收集结果成为 List 1、分隔与忽略

1
2
3
4
5
6
7
8
// 1.1 普通分隔
List<String>result=Splitter.on("|").splitToList("hellolworld");

// 1.2 忽略空串
List<string>result=Splitter.on("|").omitEmptystrings().splitroList("hellolworldlll");

// 1.3 忽略空格并忽略空串
result=Splitter.on("I").trimResults().omitEmptystrings().splitroList("hel1o I worldlll");

2、正则分隔 使用 onPattern 替代 on, 参数即为正则

1
2
3
4
5
// 3.1 传入正则表达式进行分隔
List<String>result=Splitter.onPattern("\\\\\\\\l").trimResults().omitEmptystrings().splitTorist("hello | worldl");

// 3.2 传入正则Pattern
List<string>result =Splitter.on(Pattern.compile("\\\\l")).trimResults(). omitEmptystrings().splitToList("");

3、结果分隔 通过字符长度截取字符串 截取结果中固定的个数,最后的保存剩余所有的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 2.1 分隔固定长度,报文的固定长度截取 aaabbbccc
List<string> result = Splitter.fixedtength(4).splitToList("aaaabbbbccccdddd");

// 2.2 限制返回的结果数,多余的放在最后一个结果中
List<String>result=Splitter.on("#")
.limit(3)
.splitToList("hello# world# java# google# scala");

// 3.3 传入正则Pattern, 返回 Map
Map<String, String> result = Splitter.on(Pattern.compile("\\\\\\\\l"))
.trimResults()
.omitEmptystrings()
.withKeyValueSeparator("=")
.split("hello=HELLOl|world=WORLD|||");

String 其他工具

1、Strings 填充字符串 获取公共前缀|后缀 重复指定次数的字符串: 和 python 进行重复类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
assertlhat(strings.emptytovull("") rnullvalue())
assertThat(Strings.nullToEmpty(null), equalro(""));
assertThat(strings.nullToEmpty("hello"), equalTo("hello"));

assertThat(Strings.commonPrefix("Hello","Hit"), equalTo("H"));
assertThat(Strings.commonPrefix("Hello","Xit"), equalro(""));
assertThat(Strings.commonSuffix("Hello","Echo"), equalTo("o"));

assertThat(Strings.repeat("Alex",3), equalTo("AlexAlexAlex"));

assertlhat(btrings.1sNullormpty(nulL), equallo(true))
assertThat(Strings.isNullOrEmpty(""), equalTo(true));
assertThat(Strings.padstart("Alex",3,'H'), equalTo("Alex"));
assertThat(strings.padstart("Alex",5,'H'), equalTo("HAlex"));
assertThat(Strings.padEnd("Alex",5,'H'), equalTo("AlexH"));

2、CharSet

3、CharMatcher

1
2
3
4
5
6
assertThat(CharMatcher. javaDigit(). matches('A'), equalTo(true));
assertThat(CharMatcher. javaDigit(). matches('x'), equalTo(false));
assertrhat(CharMatcher. is('A').countIn("Alex sharing the Google Guava to Us"), equalTo(1));
assertThat(CharMatcher. breakingwhitespace().collapseFrom("hello Guava ",'*"), equalro("* hello Guaval");
assertThat(CharMatcher. javaDigit(). or(CharMatcher. whitespace()). removeFrom("hello 234 world"), equalTo("helloworld");
asserThat(CharMatcher. javaDigit(). or(CharMatcher. whitespace()). retainFrom("hello 234 world"), equalro("234"));

类通用工具

1、MoreObjects 1、实战 toString 辅助编写: 支持忽略空值

1
2
3
4
5
6
public string tostring(){
return Moreobjects.tostringHelper(this).omitNullValues()
.add("manufacturer", this.manufacturer)
.add("version", this.version)
.add("releaseDate", this.releaseDate).tostring();
}

2、源码 链表结构

1
2
3
4
5
6
7
8
9
10
11
12
13
private ToStringHelper(String className) {
this.holderHead = new MoreObjects.ToStringHelper.ValueHolder();
this.holderTail = this.holderHead;
this.omitNullValues = false;
// check and get
this.className = (String)Preconditions.checkNotNull(className);
}

private MoreObjects.ToStringHelper.ValueHolder addHolder() {
MoreObjects.ToStringHelper.ValueHolder valueHolder = new MoreObjects.ToStringHelper.ValueHolder();
this.holderTail = this.holderTail.next = valueHolder;
return valueHolder;
}

2、Objects 深度比较 deepEquals hash: compare(a,b, cmp); requireNonNull template = String.valueOf(template); // null -> “null”

在 JDK7+ 使用 JDK 提供的 Objects 方法替代

3、ComparisonChain 链式的比较规则 JDK8 添加类似的实现在 Comparator 上

1
2
3
4
5
6
7
@Override
public int compareTo(Guava this, Guava o) {
return Comparisonchain.start()
.compare(this.manufacturer,o.manufacturer)
.compare(this.version,o.version)
.compare(this.releasepate,o.releaseDate).result();
}

2、源码 本身为抽象类 类中持有一个实例化的对象 提供该抽象类的一个继承实现类 针对 float,double,int,long,Object 提供比较,针对 Object 提供 classis 和基于 Comparator 的比较

StopWatch

工厂方式获取,createStarted() 省去创建之后开启的步骤 可控制返回的时间单位 对象可以来回复用记录

1
2
3
4
LOGGER.info("start process the order [{}]", orderNo);
Stopwatch stopwatch = Stopwatch.createStarted();
TimeUnit.MILLISECONDS.sleep(100);
LOGGER.info("The orderNo [{}] process successful and elapsed [{}] min.", orderNo, stopwatch.stop().elapsed(TimeUnit.MINUTES));

PreConditons

运行时空判断 判断并可给出 message,默认通过 String 自带的格式化字符串实现 通过方法名空值语义: checkState: 判断状态 checkElementIndex: 判断容器的索引

1
2
3
4
Preconditions.checkNotNull(list,"The list should not be null and the size must be %s",2);
Preconditions.checkArgument(type.equals("B"));
Preconditions.checkState(state.equals("B"), "The state is illegal.");
Preconditions.checkElementIndex(10, list.size());

Collections

FluentIterable

类似网络中的数据流处理

1、将其当做链表操作: 链表的头结点、尾节点获取 两条链表的合并 链表中是否含有满足特定条件的值 链表中是否全部满足特定条件 链表中满足特定条件的第一个值 将链表按照特定的长度进行分割

从数组中构建链表 从迭代器中构建链表

链表的循环读取,先连接成环,之后扫描限定个数的节点

链表元素的转换(transform),通过 Function 接口实现 链表元素进行转换,单个元素转化后是一个 迭代器,重新进行连接

1
2
3
4
FluentIterable<String> fit = build();
boolean result = fit.allMatch(e -> e != null && e.length() >= 4);
result = fit.anyMatch(e -> e != null && e.length() == 5);
Optional<String> optional = fit.firstMatch(e -> e != null && e.length() == 5);

Lists | Sets

List 构造

通过工厂提供方便的构造方式, 同时语义明确

主要提供三种 List 的构造:

ArrayList 原始方式 提供根据迭代器构造 提供根据可变数组构造 提供容量构造,包含限定长度、给出期望长度

LinkedList 构造仅提供两种方式: 底层链表无法指定大小 原始方式 迭代器构造

CopyOnWriteArrayList: 构造方式同 LinkedList

Set 构造

HashSet: 方式和 ArrayList 方式类似

LinkedHashSet: 方式与 LinkedList 类似 增加限定容量,底层基于数组。。。

TreeSet: 普通构建,(), (comparator) 传入迭代器

EnumSet:

Set 集合性质(&)

笛卡尔积 组合选取 两个集合不同的部分, difference(set1, set2) 返回在 set1 中的元素而不再 set2 中的元组 交集、并集

MultiSet

记录重复元素的个数

Maps | BiMap | MultiMap

构造方式

转换成不可变Map 根据 Set 转变成可变 Map 根据 Map 转换对应的值

BiMap

严格的一对一映射,通过接口声明通用的操作

Table | Range

ArrayTable TreeBaseTable HashBaseTable ImmutableTable

表名、列明、列值

Range

提供实现了自然排序类的范围: >= <=, [)

范围映射,Key 为一个给定的范围,放入的为泛型 K 的一个 Range,支持按照某个具体的值获取到对应范围端的一个值

Range | RangeMap | Ording

Sorted 判断是否已经按照自然排序完成

给出相反的比较。。。

Getting Started with Google Guava.pdf

不可变设计: 提供工厂方式, of 提供构建器方式 CacheBuilder.newBuilder().build() 提供原型方式构建 copyOf

Range

存放在其中的元素必须是 Comparable 的

提供多种符合语义的工厂构造: 根据枚举值确定两端的开闭

RangeMap

另一种存在有序性的 Map

Ording

支持对 null 的特殊处理,将其放在第一位或者最后一位

与当前 JDK8 中 Comparator 中的 nullFirst 一致,配合 thenXXX 进行控制比较规则

Guava 缓存

原始缓存实现

1、LinkedHashMap 通过 JDK 自带的实现

2、LinkedList 借助 LinkedList 实现

3、通过 SoftReference 实现 容量: 初始容量、最大容量 过期策略: 设置的大小、按照权重、访问、写入、更新、GC 并发等级: 并发使用 KV收集机制: 软引用、弱引用进行 GC

过期策略(5)

1、大小 限定缓存的个数,内存大小

2、LRU 限定大小的情况下,模式通过 LRU 算法进行淘汰

3、Time(W,R) 在访问命中某个元素多长时间后过期; 在更新某个元素多长时间后过期;

4、引用生命周期控制(GC) .softValues() .softKeys() 借助 GC 控制何时回收,何时保留

5、权重 通过为每个缓存的数据设定一定的权重进行控制是否过期 通过实体,给出计算规则: 入参为 key, values,返回的值为对应的权重

其他特性(4)

1、不存在的默认值(LoadingCache) 在获取不到的情况下给出的值 类似缓存雪崩情况下的熔断 通过 CacheLoader 抽象类实现: 给类提供根据 Function,Supplier 进行创建的工厂 是 LoadingCache 实现必须要指定的参数

1
2
CacheLoader<K, V> from(Function<K, V> function)
CacheLoader<Object, V> from(Supplier<V> supplier)

2、统计功能 .recordStats() 记录缓存的命中率,执行情况

3、监听缓存移除事件 可设置缓存移除监听器,监听到删除事件进行处理 封装成通知实体控制移除策略

1
void onRemoval(RemovalNotification<K, V> notification);

4、灵活的构造方式

  • 支持根据特定的字符串构造 CacheBuilder: 类似读取配置文件实现缓存
  • 根据函数式接口构造 CacheLoader
1
2
3
4
String spec = "maximumSize=5,recordStats";
CacheBuilderSpec builderSpec = CacheBuilderSpec.parse(spec);
CacheLoader<String, String> loader = CacheLoader.from(String::toUpperCase);
LoadingCache<String, String> cache = CacheBuilder.from(builderSpec).build(loader);

源码分析

通过 ConcurrentHashMap 实现

Entry 中各种引用的获得: 有限的几个 每个实现都不同 有一定的规律(存在是否) ⇒ 定义Enum, 将所有Enum放入数组中,定义工厂获取方法,按照将boolean作为参数进行掩码控制获得

EventBus

消息的 pull 和 push

进程级别,内部

Listener 对其进行 subscribe 只能有一个参数:

实战

1、多种类型 同种类型的多个订阅方法会被调用

2、Listener 继承特性 都会被调用

3、Event继承 都会被调用

4、异步总线

设计

自己实现一个消息总线,实现与 Guava 中 EventBus 类似的功能

并发

Monitor

LockCondition 的一个封装 可替换 synchronized 的实现,语义更加明确,同时更加方便编程

1、阻塞队列设计 (1) synchronized 方式设计

(2) Reentrant + Condition 方式设计

(3) Monitor 方式设计

限流

rateLimiter

Semaphore 通过 Semaphore 进行获取并释放令牌的方式进行控制访问的速率

令牌桶

Ref

https://github.com/google/guava/wiki

Github Guava Wiki