项目中经常用的一些guava的工具方法,抽了一些时间整体看了一下文档,全面的了解了一下guava的工具支持,这里记录一下
概览
- 检查:Preconditions中的checkArgument,checkNotNull(一般在入参赋值的时候会包一下)
- 避免null返回:现已使用1.8的Optional类了,所有公开可能返回null的方法都应当使用Optional对象包装返回
- 比较:ComparisonChain和Ordering两种排序方式都可以使用,简化的流式api很好用
- 异常:都是历史遗留问题了,异常支持了”|"这个表达式之后基本上不再推荐使用Throwables中的工具类
- 内容不可变集合:如果集合内容不会变化,那么尽量使用不可变集合ImmutableList,ImmutableSet,ImmutableCollection
- 新的集合类型:Multiset(带统计的set),Multimap(一键多值的map),BiMap(双向映射的map)
- 常用容器的工具方法:Sets,Lists,Maps,MultiMaps
- 容器类型的拓展:Forwarding,PeekingIterator,AbstractIterator
- 缓存:LoadingCache(多种维度的维护,很实用)
- Future的进一步封装:ListenableFuture可回调通知的支持
- 字符串工具类:Strings
- 原生类型工具支持:Primitives
- IO工具支持:ByteStreams,CharStreams,Files
- 区间概念:Range
- 散列封装:对原有的不好用的jdk散列api封装了新的类型Hashing,HashFunction,HashCode
- 事件总线:EventBus(同步异步继承触发等特点)
- 反射工具:TypeToken,Invokable,Reflection
下面详细列出这些简单使用与体会
Preconditions
对参数/状态的预先检查,它的核心思想是预先检查出不合格的参数,抛出合理的异常提示
举例:
1检查状态,抛异常
checkState(ex,message)
checkArgument(ex,message)
2一边检查,一边使用(这个挺有意思哦)
String a = checkNotNull(b)+"sub",如果b为null就抛异常,否则返回那么可以直接使用啦,这个在传入参数初始化时经常用
public class PreconditionsTest{
private String a;
private Integer b;
public PreconditionsTest(String a, Integer b){
// 这样用的比较多
this.a = checkNotNull(a);
this.b = checkNotNull(b);
}
}
Optional
这是一种防御式编程思想.Java1.8也支持了Optional这种封装对象处理null的方法.如果返回的值存在null的可能尽量用Optional,这样使用方就必须检查
举例:
1为可能为null的对象设置默认值
String value = Optional.ofNullable(a).orElse("b”);
2一行代码做非空检查
Optional.ofNullable(a).orElseThrow(() -> new RuntimeException("not null!"));
public class OptionalTest{
public static void main(String[] args){
String a = null;
String c = Optional.ofNullable(a).orElse("b");
System.out.println(c);
String d = Optional.ofNullable(a).orElseThrow(() -> new RuntimeException("not null!"));
System.out.println(d);
String ccc = checkNotNull(a)+"fake";
}
}
Objects与MoreObjects
不得不说guava的一些工具类确实是基础常用的,这个Objects类已经到JDK里面了..
主要提供了一些对象的基础方法,比如equals,isNull,nonNull,requireNonNull这样的基础判断
感觉一些这些基本的api是供给jdk基本参数判断与1.8lambda的api使用的…
MoreObjects提供了toStringHelper以方便我们对一些关心对象值信息获取…
这对于一些没有toString方法的bean对象调试是很方便的.
MoreObjects另一个常用的api是为空时的赋值firstNonNull方法
public class ObjectsTest{
private String name;
private Integer age;
public static void main(String[] args) throws Exception{
ObjectsTest objectsTest = new ObjectsTest();
objectsTest.age=1;
objectsTest.name="aaa";
// ObjectsTest并没有重写toString方法哦
System.out.println(objectsTest.toString());
// 想要调试一个对象属性信息,自定义toString信息可以这么来弄
System.out.println(MoreObjects.toStringHelper(objectsTest)
.add("age",objectsTest.age)
.add("name",objectsTest.name)
.toString());
// 一般的非空赋值
String value = MoreObjects.firstNonNull("first param maybe is null","first param is null,second param will be return");
}
}
ComparisonChain
基于Comparable接口做的链式api封装提供
方便的实现比较方法,很优雅,实现的也很简单有效,通过状态连续判断.Fluent接口的风格更不容易出错,读起来也更舒服.很推荐!
@Override
public int compareTo(ComparisonChainTest o){
// 这是一样的写法
// return this.age.compareTo(o.age) ==0?this.age2.compareTo(o.age2):this.age.compareTo(o.age);
// 这是新的写法,比以前的写法更简单明了
return ComparisonChain.start().compare(this.age,o.age).compare(this.age2,o.age2).result();
}
Ordering
对Comparator的排序接口做的封装
看来链式api是以后的方向啊,能向这个方向做的api都改为链式调用了
public class OrderingTest{
private Integer age;
private Integer age2;
public OrderingTest(Integer age, Integer age2){
this.age = age;
this.age2 = age2;
}
public static void main(String[] args){
// 从后向前看.compound除外,它只表示组合,但是顺序是从前向后看...
Ordering ordering = Ordering.natural().nullsFirst().onResultOf((Function) input -> input.age)
.compound(Ordering.natural().nullsFirst().onResultOf((Function) input -> input.age2));
List list = Lists.newArrayList(
new OrderingTest(1,1),
new OrderingTest(1,1),
new OrderingTest(null,1),
new OrderingTest(5,1),
new OrderingTest(5,null),
new OrderingTest(3,2),
new OrderingTest(3,1),
new OrderingTest(1,2)
);
System.out.println(list);
// list.removeIf(o->o.age==null || o.age2==null);
list.sort(ordering);
System.out.println(list);
}
@Override
public String toString(){
return "o{"+
"age="+age+
", age2="+age2+
'}';
}
}
result
[o{age=1, age2=1}, o{age=1, age2=1}, o{age=null, age2=1}, o{age=5, age2=1}, o{age=5, age2=null}, o{age=3, age2=2}, o{age=3, age2=1}, o{age=1, age2=2}]
[o{age=null, age2=1}, o{age=1, age2=1}, o{age=1, age2=1}, o{age=1, age2=2}, o{age=3, age2=1}, o{age=3, age2=2}, o{age=5, age2=null}, o{age=5, age2=1}]
ImmutableList,ImmutableSet,ImmutableCollection
guava中不可变集合的api,对jdk中Collections.unmodifiableXXX的api做增强
适当在框架层使用一些不可变集合做初始化,增强稳定性
常用的api有
ImmutableSet.of(“a”,”b”,”c”)
ImmutableList.copyOf(other collection)
ImmutableList.
public class ImmutableSetTest{
public static void main(String[] args){
Set immutableSet = ImmutableSet.of("a","b","c");
Set set = new HashSet(){
{
add("1");
add("2");
add("3");
}
};
set.add("4");
// 不可变对象不能含有null
// set.add(null);
Set builderSet = ImmutableSet.builder().add(1).add(2).add(3).build();
Set iSet = ImmutableSet.copyOf(set);
System.out.println(iSet);
System.out.println(immutableSet);
System.out.println(builderSet);
}
}
Multiset,Multimap,BiMap
提供了新的集合操作对象,这里列出比较常用的对象特点和api
Multiset-特点:可计数的Set
一般实现用HashMultiset
count(“key")返回计数值,elementSet()转到Set接口(Multiset操作有重复对象,转到Set去重)
Multimap-特点:一键多值
SetMultiMap:值行为类似于Set,不允许相同值
ListMultiMap:值行为类似于List,允许有相同值
通过get()方法可以看到返回的是value就是Set或者List
BiMap-特点:双向映射绑定,便捷双向操作
一般实现用HashBiMap
inverse()方法可以返回看k,v翻转的map,和原map操作同一份底层数据
public class MultiCollectionTest{
public static void main(String[] args){
multiset();
multiMap();
biMap();
}
/**
* 特点:可计数的Set
*/
private static void multiset(){
System.out.println("HashMultiset.create() 和Set很像,但是可以统计多少重复的-------------------------------------------------------");
Multiset multiset = HashMultiset.create();
multiset.add("aaa");
multiset.add("aaa");
multiset.add("aaa");
multiset.add("bbb");
multiset.add("bbb");
multiset.add("ccc");
// 感觉就是计数用的...
System.out.println("aaa count:"+multiset.count("aaa"));
System.out.println("total size:"+multiset.size());
// 转到set接口,elementSet()
System.out.println("set size:"+multiset.elementSet().size());
}
/**
* 特点:允许一键多值Map
*/
private static void multiMap(){
System.out.println("HashMultimap.create() 值行为类似HashSet-------------------------------------------------------");
SetMultimap valueSimilarHashSet = HashMultimap.create();
valueSimilarHashSet.put("a",1);
// 重复的值不会产生多个
valueSimilarHashSet.put("a",1);
valueSimilarHashSet.put("b",2);
// 允许null
valueSimilarHashSet.put("b",null);
System.out.println(valueSimilarHashSet);
System.out.println(valueSimilarHashSet.get("a"));
System.out.println(valueSimilarHashSet.get("c"));
System.out.println("ArrayListMultimap.create() 值行为类似ArrayList--------------------------------------------------------");
ListMultimap valueSimilarArrayList = ArrayListMultimap.create();
valueSimilarArrayList.put("a",1);
valueSimilarArrayList.put("a",1);
valueSimilarArrayList.put("a",1);
valueSimilarArrayList.put("b",2);
valueSimilarArrayList.put("b",3);
valueSimilarArrayList.put("b",4);
valueSimilarArrayList.put("c",10);
// 允许null
valueSimilarArrayList.put("c",null);
System.out.println(valueSimilarArrayList);
// 不会返回null,最起码都是个空集合
System.out.println(valueSimilarArrayList.get("d"));
}
/**
* 特点:双向映射,可以翻转
*/
private static void biMap(){
System.out.println("HashBiMap.create() k,v可以翻转的Map,值不可重复-------------------------------------------------------");
HashBiMap biMap = HashBiMap.create();
biMap.put("a",1);
biMap.put("b",2);
biMap.put("c",3);
System.out.println(biMap);
Map inverseMap = biMap.inverse();
System.out.println(inverseMap);
// 同一个kv不同的展示方式而已,修改原map还是inverseMap都可以修改原有的值
biMap.put("d",4);
inverseMap.put(5,"e");
System.out.println(biMap);
System.out.println(inverseMap);
}
}
Sets,Lists,Maps,MultiMaps
Sets和Maps有很多比较的方法
比如:取交集,取并集,进行元素差异化比较等,后面再使用时可以多从这种角度操作容器
public class CollectionsTest{
public static void main(String[] args){
lists();
sets();
maps();
multiMaps();
}
private static void lists(){
System.out.println("Lists ----------------------------------------------------------------------");
// 一般没有参数的情况我是不会用这个方法的
Lists.newArrayList();
// 用的较多
List lists = Lists.newArrayList(1,2,3,4);
// 反转
System.out.println(Lists.reverse(lists));
// 指定初始化大小的list
Lists.newArrayListWithCapacity(3);
}
private static void sets(){
System.out.println("Sets ----------------------------------------------------------------------");
// 和Lists一样的构造方法
Sets.newHashSet("","");
// 偶尔会用到,比较引用
Sets.newIdentityHashSet();
Set a = ImmutableSet.of("a","b","c","d");
Set b = ImmutableSet.of("a","b","e","f");
TreeSet treeSet = new TreeSet<>(Ordering.natural());
// 方便的对set进行比较
System.out.println("union:"+Sets.union(a,b));
System.out.println("intersection:"+Sets.intersection(a,b));
System.out.println("difference:"+Sets.difference(a,b));
System.out.println("symmetricDifference:"+Sets.symmetricDifference(a,b));
}
private static void maps(){
System.out.println("Maps ----------------------------------------------------------------------");
Maps.newHashMap();
// 分组
Map uniqueIndexMap = Maps.uniqueIndex(ImmutableList.copyOf(new String[]{"a","ab","abc"}),String::length);
System.out.println(uniqueIndexMap);
Map map1 = ImmutableMap.of("a",1,"b",2,"c",3,"e",5);
Map map2 = ImmutableMap.of("a",1,"b",2,"c",4,"d",4);
// 2个map进行比较
MapDifference mapDifference = Maps.difference(map1,map2);
System.out.println("entriesInCommon:"+mapDifference.entriesInCommon());
System.out.println("entriesDiffering:"+mapDifference.entriesDiffering());
System.out.println("entriesOnlyOnLeft:"+mapDifference.entriesOnlyOnLeft());
System.out.println("entriesOnlyOnRight:"+mapDifference.entriesOnlyOnRight());
}
private static void multiMaps(){
System.out.println("multiMaps ----------------------------------------------------------------------");
Set set = ImmutableSet.of("a","b","ab","abc","add");
System.out.println(Multimaps.index(set, String::length));
ArrayListMultimap arrayListMultimap = ArrayListMultimap.create();
arrayListMultimap.putAll("a", Ints.asList(1,2,3));
arrayListMultimap.putAll("b", Ints.asList(4,5,3));
arrayListMultimap.putAll("a", Ints.asList(5,6,7));
TreeMultimap treeMultimap = Multimaps.invertFrom(arrayListMultimap, TreeMultimap.create());
System.out.println(treeMultimap);
}
}
Forwarding,PeekingIterator,AbstractIterator
对集合类做的拓展封装,用于定制化集合对象.
public class CollectionsExtendTest{
public static void main(String[] args){
forwarding();
peekingIterator();
abstractIterator();
}
private static void forwarding(){
System.out.println("forwarding ------------------------------------------------------------------------------------");
// 快速创建包装类拓展
List list = new ForwardingList(){
private final List delegate = new ArrayList<>();
@Override
protected List delegate(){
System.out.println("delegate....");
return delegate;
}
@Override
public boolean add(String element){
System.out.println("add..."+element);
return super.add(element);
}
};
list.add("1");
list.add("2");
System.out.println(list);
}
private static void peekingIterator(){
System.out.println("peekingIterator ------------------------------------------------------------------------------------");
// 可以进行窥探下一个值的迭代器
PeekingIterator peekingIterator = Iterators.peekingIterator(Lists.newArrayList("a","b","b","c","c").iterator());
List result = new ArrayList<>();
while(peekingIterator.hasNext()){
String current = peekingIterator.next();
while(peekingIterator.hasNext() && peekingIterator.peek().equals(current)){
peekingIterator.next();
}
result.add(current);
}
System.out.println(result);
}
private static void abstractIterator(){
System.out.println("abstractIterator ------------------------------------------------------------------------------------");
// 自定义迭代器
Iterator in = Iterators.forArray("a",null,"b","c");
Iterator iterator = new AbstractIterator(){
@Override
protected String computeNext(){
while(in.hasNext()){
String s = in.next();
if(s!=null) return s;
}
return endOfData();
}
};
iterator.forEachRemaining(System.out::print);
}
}
LoadingCache
缓存是很重要的,Guava的Cache是常用的一级缓存
适用性
1你愿意消耗一些内存空间来提升速度。
2你预料到某些键会被查询一次以上。
3缓存中存放的数据总量不会超出内存容量。(使用的内存空间)
public class CacheTest{
public static void main(String[] args) throws ExecutionException, InterruptedException{
System.out.println("accessTime ------------------------------------------------------------------------------------");
LoadingCache cache = CacheBuilder.newBuilder()
// 缓存回收 1基于容量的大小.1.1maximumSize()直接设置容器大小,maximumWeight()+weigher()基于权重设置
.maximumSize(3) // 设置缓存最大大小
// .maximumWeight(5) // 配合weigher()方法的权重设置
// .weigher((String key,String value) -> key.length()) // 设置缓存权重
// 缓存回收 2定时回收
.expireAfterAccess(Duration.ofSeconds(3)) // 基于访问顺序的缓存
// .expireAfterWrite(Duration.ofSeconds(3)) // 基于写入顺序的缓存
// 支持异步刷新
// .refreshAfterWrite(Duration.ofSeconds(3))
// 当缓存被移除时可以通过监听获取回调,支持异步
// .removalListener(notification -> System.out.println(notification.getKey()+"--removed"))
.removalListener(RemovalListeners.asynchronous(notification -> System.out.println(notification.getKey()+"----asynchronous--removed"),
new ThreadPoolExecutor(1,1,0,TimeUnit.SECONDS, new LinkedBlockingQueue<>(),r -> new Thread(Thread.currentThread().getThreadGroup(),r,"RemovalListeners.asynchronous"))))
// 开启统计功能
.recordStats()
.build(new CacheLoader(){
@Override
public String load(String key){
System.out.println("real key....");
return key.toUpperCase();
}
});
// 显示插入
cache.put("k1","putK1");
// 清除
cache.invalidate("k1");
cache.invalidateAll();
// 支持"如果有缓存则返回;否则运算、缓存、然后返回"
System.out.println(cache.get("kkk",() -> "fffff"));
// get方法必须捕获ExecutionException异常
System.out.println(cache.get("k1"));
TimeUnit.SECONDS.sleep(2);
// getUnchecked()当加载实际值时没有抛出异常声明可以用这个api
System.out.println(cache.getUnchecked("k2"));
System.out.println(cache.getUnchecked("k2"));
TimeUnit.SECONDS.sleep(2);
System.out.println(cache.getUnchecked("k3"));
TimeUnit.SECONDS.sleep(3);
System.out.println(cache.getUnchecked("k1"));
System.out.println(cache.getUnchecked("k2"));
System.out.println(cache.getUnchecked("k3"));
// 统计信息
System.out.println("recordStats:"+cache.stats());
System.exit(0);
}
}
ListenableFuture
ListenableFuture多了一个回调的api支持,Futures封装了更多的支持比如合并一组ListenableFuture等功能,比较实用.
public class ListenableFutureTest{
public static void main(String[] args) throws ExecutionException, InterruptedException{
ExecutorService executorService = new ThreadPoolExecutor(5,5,0, TimeUnit.SECONDS,new LinkedBlockingQueue<>(), new ThreadFactory(){
private AtomicInteger atomicInteger = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r){
Thread t = new Thread(r);
t.setName("ListeningExecutorService.Pool-"+atomicInteger.getAndIncrement());
return t;
}
});
// 包装得到ListeningExecutorService
ListeningExecutorService les = MoreExecutors.listeningDecorator(executorService);
ListenableFuture listenableFuture = les.submit(() -> {
TimeUnit.SECONDS.sleep(1);
return "aaa";
} );
// 普通的使用监听
listenableFuture.addListener(() -> {
try{
System.out.println("listenableFuture.addListener..success:"+listenableFuture.get());
}catch(InterruptedException | ExecutionException e){
e.printStackTrace();
}
},executorService);
// 通过Futures工具类使用监听
Futures.addCallback(listenableFuture, new FutureCallback(){
@Override
public void onSuccess(String result){
System.out.println("Futures.addCallback success..."+result);
}
@Override
public void onFailure(Throwable t){
t.printStackTrace();
}
},executorService);
System.out.println("--------------------------------------------");
System.out.println("正常处理返回值:"+listenableFuture.get());
System.out.println("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
// 对ListenableFuture进行合并操作,这个还比较有用
List> listenableFutureList= new ArrayList<>();
listenableFutureList.add(les.submit(() -> "aaa"));
listenableFutureList.add(les.submit(() -> "bbb"));
listenableFutureList.add(les.submit(() -> {
throw new RuntimeException("runtime exception");
}));
listenableFutureList.add(les.submit(() -> "ccc"));
// successfulAsList 有异常则返回null
// allAsList 有一个有异常都会走failure
ListenableFuture> listListenableFuture = Futures.successfulAsList(listenableFutureList);
// ListenableFuture> listListenableFuture = Futures.allAsList(listenableFutureList);
Futures.addCallback(listListenableFuture, new FutureCallback>(){
@Override
public void onSuccess(@Nullable List result){
System.out.println("Futures.successfulAsList result:"+result);
}
@Override
public void onFailure(Throwable t){
t.printStackTrace();
}
},executorService);
System.out.println("listListenableFuture.get():"+listListenableFuture.get());
TimeUnit.SECONDS.sleep(1);
System.exit(0);
}
}
Strings
很多方法时通过其他方法也可以实现替代,比如Joiner和Splitter之前都是使用Stream来实现的,不过Guava给出的这俩都是线程安全的对象这样讲处理方法定义在类上面更好的理解,后续多使用.
字符集在1.6之后出的,后面应该使用,避免使用charsetName
public class StringsTest{
public static void main(String[] args){
// JDKString自带的split方法有问题,末尾的,都被忽略了
String a = " ,a,b,,";
System.out.println(Arrays.toString(a.split(",")));
// Joiner 和 Splitter 都可以通过Stream方法替代
Joiner joiner = Joiner.on(";").skipNulls();
String joinStr = joiner.join("a","b",null,"","c");
System.out.println(joinStr);
Iterable iterableStr = Splitter.on(",").trimResults().omitEmptyStrings().split(" a,b,, c d,e ,");
System.out.println(iterableStr);
// 字符匹配器
System.out.println("-------------------------- 1a b 2 c 3 ------------------------------------------------------");
System.out.println("retainFrom 'a','z' :"+CharMatcher.inRange('a','z').retainFrom(" 1a b 2 c 3 "));
System.out.println("retainFrom '0','9' :"+CharMatcher.inRange('0','9').retainFrom(" 1a b 2 c 3 "));
System.out.println("removeFrom 'a','z' :"+CharMatcher.inRange('a','z').removeFrom(" 1a b 2 c 3 "));
System.out.println("removeFrom '0','9' :"+CharMatcher.inRange('0','9').removeFrom(" 1a b 2 c 3 "));
System.out.println("replaceFrom 'a','z' :"+CharMatcher.inRange('a','z').replaceFrom(" 1a b 2 c 3 ","f"));
System.out.println("replaceFrom '0','9' :"+CharMatcher.inRange('0','9').replaceFrom(" 1a b 2 c 3 ","f"));
// 字符集
byte[] bytes = "Charsets.UTF_8".getBytes(StandardCharsets.UTF_8);
System.out.println(new String(bytes,StandardCharsets.UTF_8));
// 某些格式转换.一些特别的格式转换,比如驼峰,全大写下划线等,写代码生成器的时候用的比较多吧
String lowerCamel = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL,"SimpleClassName");
System.out.println(lowerCamel);
}
}
Primitives
这是Guava对byte、short、int、long、float、double、char和boolean原生类型的一些工具支持
主要还是基础类型的工具方法支持,比如,asLisist,concat.平常很少用到
public class PrimitivesTest{
public static void main(String[] args){
// 原生类型数组工具,比较可能会用到的是concat方法在将原生数组做连接
int[] a =new int[]{1,2,3};
List aa = Arrays.asList(1,2,3);
List aac = Ints.asList(a);
// 将多个byte数组合并起来,内部还是使用System.arraycopy本地方法
byte[] newBytes = Bytes.concat("aa".getBytes(Charsets.UTF_8),"bb".getBytes(Charsets.UTF_8));
System.out.println(new String(newBytes,Charsets.UTF_8));
}
}
IO
Guava提供的IO操作有ByteStreams和CharStreams的一些方法支持,中规中矩,所有方法都是加了buf的,有需要可以用一下
提供了Files对文件的一些操作.
public class IOTest{
public static void main(String[] args) throws IOException{
String a = "hello world!";
// 从input stream读取byte数组
byte[] bytes = ByteStreams.toByteArray(new ByteArrayInputStream(a.getBytes(StandardCharsets.UTF_8)));
System.out.println("ByteStreams.toByteArray:"+new String(bytes, StandardCharsets.UTF_8));
// 从input stream读取到output stream
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteStreams.copy(new ByteArrayInputStream(a.getBytes()),out);
System.out.println("ByteStreams.copy:"+out.toString());
// 从reader中读取字符串信息
String result = CharStreams.toString(new InputStreamReader(new ByteArrayInputStream(a.getBytes()),StandardCharsets.UTF_8));
System.out.println("CharStreams.toString:"+result);
// Files的一些工具方法
System.out.println("Files.getFileExtension:"+Files.getFileExtension("aaa.jpg"));
System.out.println("Files.getNameWithoutExtension:"+Files.getNameWithoutExtension("aaa.jpg"));
}
}
Range
提出了区间的概念工具
在后续思考问题时可以带入区间的概念考虑解决问题.这里我只列出了简单的,实际上有更复杂的api.
public class RangeTest{
public static void main(String[] args){
// 开区间(a,b)
System.out.println(Range.open(1,3).contains(1));
// 闭区间[a,b]
System.out.println(Range.closed(1,3).contains(1));
// (-∞..b)
System.out.println(Range.lessThan(1).contains(1));
// (a..+∞)
System.out.println(Range.greaterThan(1).contains(1));
// [a..+∞)
System.out.println(Range.atLeast(1).contains(1));
// (-∞..b]
System.out.println(Range.atMost(1).contains(1));
}
}
Hashing散列
提供了常用的散列工具,比如md5,sha256,crc32等,内部实现是将JDK提供的方法进行了编写的封装
public class HashTest{
public static void main(String[] args) throws Exception{
// 构造散列算法
HashFunction hf = Hashing.md5();
// 多种多样
// Hashing.hmacMd5();
// Hashing.crc32();
// Hashing.sha256();
// 获取HashCode
HashCode hc = hf.newHasher().putBytes("your origin bytes".getBytes(StandardCharsets.UTF_8)).hash();
String md5Str = getMD5FromJdk("your origin bytes");
// 多种多样的比较方法
System.out.println("hc.toString():"+hc.toString());
System.out.println("md5Str:"+md5Str);
System.out.println(hc.toString().equals(md5Str));
// hc.asBytes()
// hc.asInt()
}
private static String getMD5FromJdk(String str) throws Exception {
try {
// 生成一个MD5加密计算摘要
MessageDigest md = MessageDigest.getInstance("MD5");
// 计算md5函数
md.update(str.getBytes());
// digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
return new BigInteger(1, md.digest()).toString(16);
} catch (Exception e) {
throw new Exception("MD5加密出现错误,"+e.toString());
}
}
}
EventBus
guava的事件机制更符合便捷开发,是一个经过充分封装的事件机制.
和一般的事件机制实现显著的区别在与监听者是一个方法,仅仅通过方法参数确定监听事件,而一般的监听者实现都会是以接口的形式
使用时注意几点
1它会根据继承体系进行传播,所有符合Event的继承体系均会受到消息
2调试时可以使用DeadEvent进行无监听警告
3使用@Subscribe注解的方法只能有一个参数
public class EventBusTest {
public static void main(String[] args) throws InterruptedException{
// 1拥有EventBus实例
EventBus eventBus = new EventBus();
// 2注册监听器
eventBus.register(new EventBusTest());
// 3发送消息(一般1和2在一起配置,3分布在代码各处)
eventBus.post(new CustomEvent("zhang san"));
// 异步的EventBus
EventBus asyncEventBus = new AsyncEventBus("AsyncEventBus",
new ThreadPoolExecutor(1, 5, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(10), new ThreadFactory() {
private AtomicInteger atomicInteger = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("AsyncEventBusExecutorService.Pool-" + atomicInteger.getAndIncrement());
return t;
}
}));
asyncEventBus.register(new EventBusTest());
asyncEventBus.post(new CustomEvent("li si"));
asyncEventBus.post(new CustomEvent2());
// 正常退出
TimeUnit.SECONDS.sleep(1);
System.exit(0);
}
/**
* 定义方法接收事件
*/
@Subscribe
public void eventReceiver(CustomEvent changeEvent) {
System.out.println("Thread name:"+Thread.currentThread().getName()+" receive event:" + changeEvent);
}
/**
* 可以定义多个,符合继承体也可以获得消息,均会被触发
*/
// @Subscribe
// public void eventReceiver(Object event) {
// System.out.println("Thread name:"+Thread.currentThread().getName()+" receive object:" + event);
// }
/**
* 如果都没有被触发,那么会尝试给DeadEvent事件,如果没有定义这个事件,那么就当做什么都没发生
*/
@Subscribe
public void deadEvent(DeadEvent event) {
System.out.println("Thread name:"+Thread.currentThread().getName()+" deadEvent:" + event);
}
/**
* 事件消息体
*/
private static class CustomEvent {
private String name;
public CustomEvent(String name) {
this.name = name;
}
@Override
public String toString() {
return "CustomEvent{" + "name='" + name + '\'' + '}';
}
}
private static class CustomEvent2 {
@Override
public String toString(){
return "CustomEvent2{}";
}
}
}
Reflection反射工具
guava提供的反射工具并不是简单的util,而是面对class/method/constructor的包装,这样提供出了额外的api进行拓展功能
TypeToken是对class的封装,它最大的特点是支持泛型获取类型
Invokable是对Method/Constructor的封装,它提供的api比jdk提供的要实用一些
Reflection只是一个反射工具类,简化了产生jdk代理以及实例化class的异常检查
public class Parent implements Comparable{
/** 这种写法可以获取泛型类型,这样在顶层可以做一些动作 */
TypeToken type = new TypeToken(getClass()) {};
private int age;
public Parent(int age){
this.age = age;
}
public void getGenericityType(){
System.out.println("getGenericityType:type.getRawType():"+type.getRawType());
}
@Override
public int compareTo(Parent o){
return ComparisonChain.start().compare(this.age,o.age).result();
}
}
public class ReflectionTest extends Parent implements Serializable{
public ReflectionTest(int age){
super(age);
}
public static void main(String[] args) throws Exception{
ReflectionTest reflectionTest = new ReflectionTest(1);
reflectionTest.typeTokenTest();
reflectionTest.invokableTest();
reflectionTest.proxyTest();
}
private void typeTokenTest(){
System.out.println("typeToken,对class做一些封装,支持泛型----------------------------------------------------------------");
// 通过这种写法可以获取泛型的具体类型
getGenericityType();
// 产生一个TypeToken对象
TypeToken typeToken = TypeToken.of(ReflectionTest.class);
// 常用的查询
System.out.println("获取当前类和所有继承类:typeToken.getTypes().classes():"+typeToken.getTypes().classes());
System.out.println("获取所有实现的接口,包括继承的类中的实现接口:typeToken.getTypes().interfaces():"+typeToken.getTypes().interfaces());
System.out.println("classes+interfaces很常用这个api:typeToken.getTypes().rawTypes():"+typeToken.getTypes().rawTypes());
System.out.println("只是获取当前TypeToken的持有类type类型:typeToken.getType:"+typeToken.getType());
System.out.println("只是获取当前TypeToken的持有类class类型:typeToken.getRawType:"+typeToken.getRawType());
}
private void invokableTest() throws NoSuchMethodException{
System.out.println("invokableTest,对Method级别的封装----------------------------------------------------------------");
// 提供了Invokable对象可以更简便的获取反射信息
Invokable invokable = Invokable.from(ReflectionTest.class.getDeclaredMethod("customMethod",Integer.class));
System.out.println("invokable.getDeclaringClass():"+invokable.getDeclaringClass());
System.out.println("invokable.getParameters():"+invokable.getParameters());
System.out.println("invokable.getReturnType():"+invokable.getReturnType());
System.out.println("invokable.isOverridable():"+invokable.isOverridable());
System.out.println("invokable.isAccessible():"+invokable.isAccessible());
System.out.println("invokable.getName():"+invokable.getName());
System.out.println("invokable.getAnnotatedReturnType():"+invokable.getAnnotatedReturnType());
System.out.println("invokable.getOwnerType():"+invokable.getOwnerType());
System.out.println("invokable.toString():"+invokable.toString());
}
private void proxyTest() throws Exception{
System.out.println("proxyTest,无fuck可说----------------------------------------------------------------");
// 用这种语法产生jdk代理
Reflection.newProxy(Serializable.class, (proxy, method, args) -> null);
System.out.println("用这种语法产生jdk代理:Reflection.newProxy(interface.class, invocationHandler)");
}
private String customMethod(Integer no){
return String.valueOf(no);
}
}
总结
拖拖拉拉用周末时间墨迹了俩月才看完...惭愧啊.还看的比较浅显,有些稍微看了一下源码实现,基本上都是采用封装的思想,对原来的类/行为进行新的封装达到更方便的使用.用起来真的会方便很多.后续自己在项目中也会更多的使用.
参考资料
中文翻译的官方文档
demo代码:https://github.com/znyh113too/guava-demo