Guava
什么是Guava?
Guava是谷歌开源的工具库,里面包含了一些新的集合类型、并发工具类、I/O、缓存、字符串操作等等。
引入依赖:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
3.1 集合操作
- 不可变集合:用不可变的集合进行防御性编程
- 新集合类型:Multimap、SortedMultiset等
- 强大的集合工具类
- 扩展工具类:让实现和扩展集合类变得更容易,比如创建Collection的装饰器
使用示例:
public static void testCollection(){
//不能进行新增,会抛出UnsupportedOperationException
ImmutableSet<String> immutableSet = ImmutableSet.of("red", "orange", "yellow", "blue", "blue", "green");
System.out.println(immutableSet);
//同个key的值放入不会覆盖
ArrayListMultimap arrayListMultimap = ArrayListMultimap.create();
arrayListMultimap.put("a",1);
arrayListMultimap.put("a",2);
System.out.println(arrayListMultimap.get("a"));
//集合工具类
ArrayList<String> list = Lists.newArrayList("aa", "bb", "cc");
String aa = Iterables.find(list, x -> x.equals("aa"));
System.out.println(aa);
List<Integer> integers = Ints.asList(1, 2, 3, 4, 5, 6, 7, 8);
List<Integer> reverse = Lists.reverse(integers);
//分成3个一组
List<List<Integer>> partition = Lists.partition(integers, 3);
Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");
//获取两个set里共有的
Sets.SetView<String> intersection = Sets.intersection(primes, wordsWithPrimeLength); // contains "two", "three", "seven"
System.out.println(intersection);
//转list为map
User user = new User();
user.setName("liu");
user.setId(1);
User user2 = new User();
user2.setName("wang");
user2.setId(2);
ArrayList<User> users = Lists.newArrayList(user, user2);
ImmutableMap<Integer, User> integerUserImmutableMap = Maps.uniqueIndex(users, u -> u.getId());
System.out.println(integerUserImmutableMap);
//快速创建map
ImmutableMap.<String,Object>of("type","aa");
}
3.2 本地缓存
实现了JVM缓存,支持多种缓存过期策略
3.2.1 创建方式:
创建方式1:使用CacheLoader
public static void testCache() throws InterruptedException, ExecutionException {
CacheLoader<Integer,User> cacheLoader=new CacheLoader<Integer, User>() {
@Override
public User load(Integer key) throws Exception {
return new User(key,"王二");
}
};
LoadingCache<Integer, User> cache = CacheBuilder.newBuilder().maximumSize(1000)
.expireAfterWrite(30, TimeUnit.SECONDS)
.build(cacheLoader);
}
创建方式2:使用Callable
Cache<Integer,User> objectCache = CacheBuilder.newBuilder().maximumSize(1000)
.expireAfterWrite(30, TimeUnit.SECONDS)
.build();
User user = objectCache.get(1, () -> new User(1, "王二"));
3.2.2 缓存回收
- 指定大小回收
CacheLoader<Integer,User> cacheLoader=new CacheLoader<Integer, User>() {
@Override
public User load(Integer key) throws Exception {
return new User(key,"王二");
}
};
LoadingCache<Integer, User> cache = CacheBuilder.newBuilder().
//指定大小是3个
maximumSize(3)
.expireAfterWrite(30, TimeUnit.SECONDS)
.build(cacheLoader);
cache.put(1,new User(1,"a"));
cache.put(2,new User(2,"a"));
cache.put(3,new User(3,"a"));
cache.put(4,new User(4,"a"));
//getIfPresent方法不会重新加载创建cache
System.out.println(cache.getIfPresent( 1));
System.out.println(cache.getIfPresent(2));
System.out.println(cache.getIfPresent(3));
System.out.println(cache.getIfPresent(4));
打印结果:
null
User(id=2, name=a)
User(id=3, name=a)
User(id=4, name=a)
最早插入的会被回收
- 缓存时间回收
CacheLoader<Integer,User> cacheLoader=new CacheLoader<Integer, User>() {
@Override
public User load(Integer key) throws Exception {
return new User(key,"王二");
}
};
LoadingCache<Integer, User> cache = CacheBuilder.newBuilder().maximumSize(3)
.expireAfterWrite(3, TimeUnit.SECONDS)
.build(cacheLoader);
cache.put(1,new User(1,"a"));
Thread.sleep(2000);
System.out.println(cache.getIfPresent( 1));
Thread.sleep(2000);
System.out.println(cache.getIfPresent(1));
打印结果为空
- expireAfterWrite(time),上次写入多长时间后过期
- expireAfterAccess(time),上次写或读操作多长时间后过期
上面的示例中,用expireAfterWrite的话,第二次打印结果为null,用expireAfterAccess的话第二次的打印结果有值
3.2.3 显示的清除缓存
- Cache.invalidate(key) :清除指定单个key
- Cache.invalidateAll(keys):清除指定多个key
- Cache.invalidateAll() :清除所有
3.2.4 移除缓存监听器
CacheLoader<Integer,User> cacheLoader=new CacheLoader<Integer, User>() {
@Override
public User load(Integer key) throws Exception {
return new User(key,"王二");
}
};
RemovalListener<Integer, User> removalListener = new RemovalListener<Integer, User>() {
public void onRemoval(RemovalNotification<Integer, User> removal) {
System.out.println("移除值:"+removal);
}
};
LoadingCache<Integer, User> cache = CacheBuilder.newBuilder().maximumSize(3)
.expireAfterWrite(3, TimeUnit.SECONDS)
.removalListener(removalListener)
.build(cacheLoader);
cache.put(1,new User(1,"a"));
cache.invalidate(1);
3.2.5 刷新值
刷新值和清除值是不一样的,刷新可能是异步的,在刷新的时候,旧值还能返回给前端。而且还能覆写reload方法来自定义刷新值的逻辑
CacheLoader<Integer,User> cacheLoader=new CacheLoader<Integer, User>() {
@Override
public User load(Integer key) throws Exception {
return new User(key,"王二");
}
};
LoadingCache<Integer, User> cache = CacheBuilder.newBuilder().maximumSize(3)
.build(cacheLoader);
cache.put(1,new User(1,"a"));
Thread.sleep(4000);
@Nullable User u1 = cache.getIfPresent(1);
Thread.sleep(4000);
@Nullable User u2 = cache.getIfPresent(1);
Thread.sleep(4000);
@Nullable User u3 = cache.getIfPresent(1);
System.out.println(u1==u2);
System.out.println(u2==u3);
打印结果都为false,说明值被刷新了
覆写reload的例子:
static final ExecutorService executor = Executors.newFixedThreadPool(4);
public static void testRefresh() throws InterruptedException {
CacheLoader<Integer, User> cacheLoader=new CacheLoader<Integer, User>() {
@Override
public User load(Integer key) throws Exception {
return new User(key,"王二");
}
@Override
public ListenableFuture<User> reload(Integer key, User oldValue) throws Exception {
if(key<0){
return Futures.immediateFuture(oldValue);
}else {
ListenableFutureTask<User> task = ListenableFutureTask.create(()-> new User(key,"name"));
executor.execute(task);
return task;
}
}
};
LoadingCache<Integer, User> cache = CacheBuilder.newBuilder().maximumSize(3)
//3秒钟刷新一次
.refreshAfterWrite(3, TimeUnit.SECONDS)
.build(cacheLoader);
cache.put(1,new User(1,"a"));
cache.put(-1,new User(1,"a"));
@Nullable User u1 = cache.getIfPresent(1);
Thread.sleep(4000);
@Nullable User u2 = cache.getIfPresent(1);
System.out.println(u1==u2);
Thread.sleep(4000);
@Nullable User u3 = cache.getIfPresent(-1);
Thread.sleep(4000);
@Nullable User u4 = cache.getIfPresent(-1);
System.out.println(u3==u4);
}
3.2.6 其他特性
统计方法
cache.stats(),需要构建的时候加上recordStats()
CacheLoader<Integer,User> cacheLoader=new CacheLoader<Integer, User>() {
@Override
public User load(Integer key) throws Exception {
return new User(key,"王二");
}
};
LoadingCache<Integer, User> cache = CacheBuilder.newBuilder().recordStats().maximumSize(3)
.build(cacheLoader);
cache.put(1,new User(1,"aa"));
cache.getIfPresent(1);
cache.getIfPresent(1);
cache.getIfPresent(2);
//加载新值所用的平均时间,以纳秒为单位
System.out.println(cache.stats().averageLoadPenalty());
//命中次数
System.out.println(cache.stats().hitCount());
//load次数
System.out.println(cache.stats().loadCount());
3.3 Strings工具类
public static void testString(){
Joiner joiner = Joiner.on(";").skipNulls();;
String join = joiner.join("a", "b", null, "c");
System.out.println(join); //a;b;c
Iterable<String> split = Splitter.on(',')
.trimResults()
.omitEmptyStrings()
.split("foo,bar,, qux");
System.out.println(split); //[foo, bar, qux]
//是否能匹配
boolean b = CharMatcher.is('a').matchesAnyOf("abc");
System.out.println(b); //true
//出现的次数
int countIn = CharMatcher.is('a').countIn("abca");
System.out.println(countIn); //2
//匹配指定的值
String s = CharMatcher.is('a').retainFrom("bdaswa");
System.out.println(s); //aa
}
3.4 I/O处理类
CharSource charSource = Files.asCharSource(new File("d://1.txt"), Charset.forName("UTF-8"));
ImmutableList<String> strings = charSource.readLines();
3.5 并发工具类
public static void testFuture() throws ExecutionException, InterruptedException {
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture<User> explosion = service.submit(
new Callable<User>() {
public User call() throws InterruptedException {
Thread.sleep(2000);
return new User(1,"xxxx");
}
});
System.out.println("不阻塞,继续执行");
Futures.addCallback(
explosion,
new FutureCallback<User>() {
// we want this handler to run immediately after we push the big red button!
public void onSuccess(User explosion) {
System.out.println("success:"+explosion);
}
public void onFailure(Throwable thrown) {
System.out.println("failure:"+thrown);
}
},
service);
}
3.6 反射
public class LogHandler implements InvocationHandler {
Object target; // 被代理的对象,实际的方法执行者
public LogHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(target, args); // 调用 target 的 method 方法
after();
return result; // 返回方法的执行结果
}
// 调用invoke方法之前执行
private void before() {
System.out.println(String.format("log start time [%s] ", new Date()));
}
// 调用invoke方法之后执行
private void after() {
System.out.println(String.format("log end time [%s] ", new Date()));
}
}
public void testReflection(){
GoodsService goodsService = Reflection.newProxy(GoodsService.class,new LogHandler(new GoodsServiceImpl()));
goodsService.updatePrice(1,2.0);
}
3.7 事件总线 EventBus
发布-订阅模式的组件通信,进程内模块间解耦
@Data
@AllArgsConstructor
public class UserEvent {
private User user;
private String remark;
}
public class UserHandler {
@Subscribe
public void handle(UserEvent userEvent){
System.out.println("取到user:"+userEvent.getUser());
}
}
static EventBus eventBus=new EventBus();
//异步的
//static EventBus eventBus=new AsyncEventBus(Executors.newSingleThreadExecutor());
static {
//eventBus会去找注册进去的类 @Subscribe标记的方法
eventBus.register(new UserHandler());
}
public static void testEvent(){
eventBus.post(new UserEvent(new User(1,"ab"),"测试"));
}