Guava

1、简介(下载地址)

Guava是Ggoole基于jdk1.6的类库集合的扩展项目,目的是简化代码,使代码更加的优雅。

1.1、基本库介绍

com.google.common.annotations 注解包
com.google.common.reflects 反射工具包
com.google.common.base 基本工具包
com.google.common.collector 带泛型集合工具包
com.google.common.io io工具包
com.google.common.net 网络包
com.google.common.math 计算包
com.google.common.eventbus 事件总线
com.google.common.concurrent 多线程工具包
com.google.common.hash 哈希包
com.google.common.caching 缓存工具包
com.google.common.primitives 八种基本数据类型和无数据类型的静态工具包

1.2、学习路线

基本工具包

使用和避免null
Null是一个关键字,代表不确定的对象,可以赋值给对象Null值,不可对基本数据类型赋Null,也不可对该变量进行操作,Null可能会造成一些不好的结果。
使用场景:
1、避免编译器报错。
2、释放内存,将对象置为空,等待垃圾回收器回收。
引发问题及解决方式
null表示不确定的对象,但使用的时候回造成二义性,例如从Map中取值,返回值为null时,可能是不存在指定的key,也有可能是key对应的value为空,也没有确切的定义,使用其他的值(非null)可以使代码更加的清晰,相反,在某些情况下使用null是正确的选择,因为在内存消耗和效率方面考虑,使用null更加的廉价,所以,问题的关键在于null能不能指明null到底代表了什么含义。
Guava中的Optional
若T类型可以为null,Optional是将以非空值来替代T类型的方法。一个Optional对象可以包含一个非空T的引用,也可以包含一个不包括任何东西的引用,但Optional从来不会包含一个null的引用。

1、常用静态方法
Optional.of(T):返回一个Optional对象,若T为null,则立即报错。
Optional.absent():返回一个Optional对象,内部包含null值。   
Optional.fromNumable(T):接受一个T类型转换为Optional对象,T可以为null。
    Optional<Integer> op1 = Optional.of(6);   // 直接NullPointException
    Optional<Integer> op2 = Optional.fromNullable(null);
    Optional<Integer> op3 = Optional.absent();
    if (op1.isPresent()) {
    	System.out.println("op1不为空");
    }
    if (op2.isPresent()) {
    	System.out.println("op2不为空");
    }
    if (op3.isPresent()) {
    	System.out.println("op3不为空");
    }
    // 输出 op1不为空
2、实例方法
    isPresent()  //如果Optional包含的T实例为空,返回false,否则返回true
    or(default)  //
	if (op3.isPresent()) {
		System.out.println(op3.get());
	}else {
		System.out.println(op3.or(666));
	}
	System.out.println(op3.orNull());
    op3.asSet();

优点:除了给null值操作代码阅读性提高之外,Optional的操作是傻瓜式的,要想取值必须要经过Optional,所以你必须要思考null值得合法性。

前提条件

常见对象方法

排序:Comparator比较器

Throwable类:简化异常检查和错误传播

数据类型相关

 Primitives
 Strings
 Ranges
math

集合&&函数式编程

Multiset:
list是有序可重复的,set是无序不可重复的,multiset是这两个集合的灰色地带,
有点类似于map,但和map又有些不同,以下几点体现:
1、新增了count相关方法
2、重复次数只能是正整数(int)
3、setCount(ele,0)相当于删除了所有元素
4、setCount(ele,old,new)当old与集合中的个数不一致时,该方法无效。
其他相同。

public class TestCollection {
	
	// Multiset(允许重复值的Set,但不保证顺序)
	public static void testMultiSet() {
		
		String word = "q|qwe|qwe|qwer|qwer|qwer|asd|sdfg|sdfsfsdfs";
		String[] wordArr = word.split("\|");
		List<String> wordList = Arrays.asList(wordArr);
		Map<String, Integer> countMap = new HashMap<String, Integer>();
		// 记录集合中不同字符出现的次数(HashMap实现)
		wordList.stream().forEach((re) -> {
			Integer count = countMap.get(re);
			if(count == null) {
				countMap.put(re, 1);
			}else {
				countMap.put(re, count+1);
			}
		});
		System.out.println("countMap:");
		for(String key:countMap.keySet()) {
			System.out.println(key+"->"+countMap.get(key));
		}
		// 记录集合中不同字符出现的次数(MultiSet实现)
		Multiset<String> set = HashMultiset.create();
		set.addAll(wordList);
		for(String key:set.elementSet()) {
			System.out.println(key+"=>"+set.count(key));
		}
		System.out.println("*********************************************");
		set.add("perl", 6);
		for(String key:set.elementSet()) {
			System.out.println(key+"=>"+set.count(key));
		}
		System.out.println("*********************************************");
		set.setCount("perl", 66);
		for(String key:set.elementSet()) {
			System.out.println(key+"=>"+set.count(key));
		}
		set.setCount("perl", 8, 88);
		System.out.println("*********************************************");
		for(String key:set.elementSet()) {
			System.out.println(key+"=>"+set.count(key));
		}
		
	}
	public static void main(String[] args) {
		testMultiSet();
	}
    
}

Multimap:
是一个一个键对应多个值的数据结构,支持一系列强大的视图功能。
1、asMap方法可以将multimap转化为Map<K, collection>的结构视图,但该视图只支持删除和修改,不支持添加.
2、entries()返回一个展现形式为Collection<Map.entry<K,V>>的视图。
3、keySet() 返回一个不重复键的Set
4、keys() 返回重复键的set
5、values() 返回一个类似迭代器的Collection
尽管与Map相似,但二者是不同的。
1、multimap总是返回一个空的集合,但这并不代表multimap使用内存进行关联,相反,这个集合只是一个只允许添加操作的视图,如果想要键不存在返回null,则需要调用asMamp方法转为Map<K, collection>结构,返回结果需要强转。
2、containsKey(key)当key存在时才会返回true
3、entries()返回所有键值对,想要获取 <K, collection>这样的键值对,需使用asMap.entries();
4、size返回集合所有元素个数,想要获取不同的key个数,使用keySet().size()

	
	// Multimap 一个可以将一个键对应到多个值的结构
	public static void multimapTest() {
		// HashMap实现多层数据嵌套
		for(int i=0;i<20;i++) {
			Score score = new Score(i,88+i);
			addScore("zhangsan",score);
		}
		System.out.println(scoreMap.size());
		System.out.println(scoreMap.containsKey("zhangsan"));
		
		System.out.println(scoreMap.containsKey("perl"));
		List<Score> erp = scoreMap.get("zhangsan");
		if (erp != null) {
			for(Score score :erp) {
				//System.out.println(score);
			}
		}
		// Multimap实现
		Multimap<String, Score> scoreMultimap = ArrayListMultimap.create();
		for(int i=0;i<20;i++) {
			Score score = new Score(i,88+i);
			scoreMultimap.put("zhangsan",score);
		}
//		System.out.println(scoreMultimap.size());
//		System.out.println(scoreMultimap.keys());
		// 清空数据
//		scoreMultimap.clear();
//		Score newScore = new Score(1, 99);
//		scoreMultimap.put("lisi", newScore);
//		System.out.println(scoreMultimap.size());
//		System.out.println(scoreMultimap.keys());
		Collection<Score> collections = scoreMultimap.values();
		for(Score score :collections) {
			//System.out.println(score);
		}
		if (scoreMultimap.asMap().get("2") == null) {
			System.out.println(1);
		}
		// 常用方法
		for(int r=10;r<20;r++) {
			Score msi = new Score(1000+r, 2000-r);
			scoreMultimap.put("msi", msi);
		}
		System.out.println(scoreMultimap.keySet());
		System.out.println(scoreMultimap.keys());
		System.out.println(scoreMultimap.values());
		System.out.println(scoreMultimap.size());
		System.out.println(scoreMultimap.keySet().size());
	}
	
	public static void addScore(String name, final Score score) {
		List<Score> scores = scoreMap.get(name);
		if(scores == null) {
			scores = new ArrayList<Score>();
			scoreMap.put(name, scores);
		}
		scores.add(score);
	}
class Score{
	private int custormId;
	private int score;
	public int getCustormId() {
		return custormId;
	}
	public void setCustormId(int custormId) {
		this.custormId = custormId;
	}
	public int getScore() {
		return score;
	}
	public void setScore(int score) {
		this.score = score;
	}
	
	public Score(int custormId,int score) {
		this.custormId = custormId;
		this.score = score;
	}
	@Override
	public String toString() {
		return "Score [custormId=" + custormId + ", score=" + score + "]";
	}
}

Multimap的实现:

Implemention keys的行为类似 values的行为类似
ArrayListMultimap HashMap ArrayList
HashMultimap HashMap HashSet
LinkedListMultimap LinkedMap LinkedList
LinkedHashMultiMap LinkedHashMap LinkedSet
TreeMultimap TreeMap TreeSet
ImmutableListMultimap ImmutableMap ImmutableList
ImmutableSetMultimap ImmutableMap ImmutableSet

注意: 除Immutable实现外都支持空键和空值。
1、LinkedListMultimap.entries()可维持遍历的顺序
2、LinkedHashMultimap可维持插入的顺序
并不是所有的MultiMap都实现了Map<K,Collection<K,V>>结构,为了最小化开销,使用了自定义的hash table
总结:该集合类似于Map,并基于Map提供了很多实现,主要区别为asMap方法。

BiMap
键和值双向关联的数据结构
问题:
  value重复转换为key会被覆盖问题
  数据是否需要关联更新
特点:
  使用BiMap时,key和value是需要唯一,如果value重复添加,会报异常,使用inserve返回的不是一个新的集合,而是原集合关联的一个视图

    Exception in thread "main" java.lang.IllegalArgumentException: value already present: log#.log
    
    
    	public static void biMapTest() {
		// 使用HashMap
		Map<Integer, String> logMap = Maps.newHashMap();
		Map<String, Integer> revertMap;
		logMap.put(1, "log!.log");
		logMap.put(2, "log@.log");
		logMap.put(3, "log#.log");
		System.out.println("logMap:"+logMap);
		revertMap = getInverteMap(logMap);
		System.out.println(revertMap.get("log!.log"));
		
		// 使用BiMap
		BiMap<Integer, String> biMap = HashBiMap.create();
		biMap.put(1, "log!.log");
		biMap.put(2, "log@.log");
		biMap.put(3, "log#.log");
		biMap.put(4, "log#.log");
		System.out.println("before:"+biMap);
		BiMap<String, Integer> biMap2 = biMap.inverse();
		System.out.println("after:"+biMap2);
	}
	
	// 反转K,V
	public static <K, V> Map<V, K> getInverteMap(Map<K, V> map){
		HashMap<V, K> targetMap = Maps.newHashMap();
		for (Map.Entry<K, V> entry :map.entrySet()) {
			targetMap.put(entry.getValue(), entry.getKey());
		}
		return targetMap;
	}

实现:
HashBiMap
ImmutableBiMap
EnumBiMap

其他实现
Table:

	public static void tableTest() {
		Table<String, Integer, String> aTable = HashBasedTable.create();
		for (char a = 'A'; a<='C'; ++a) {
			for(int i=1;i<=3;i++) {
				aTable.put(Character.toString(a), i, String.format("%c%d", a,i));
			}
		}
		System.out.println(aTable.column(2));
		System.out.println(aTable.row("A"));
		System.out.println(aTable.get("B", 1));
		
		System.out.println(aTable.contains("D", 5));
		System.out.println(aTable.containsColumn(3));
		System.out.println(aTable.containsRow("A"));
		System.out.println(aTable.columnMap());
		System.out.println(aTable.rowMap());
		System.out.println(aTable.remove("A", 1));
		System.out.println(aTable.columnMap());
		
//		a 1 a1	b 1 b1	c 1 c1
//		a 2 a2	b 2 b2	c 2 c2
//		a 3 a3	b 3 b3	c 3 c3
	}
	输出:
	{A=A2, B=B2, C=C2}
    {1=A1, 2=A2, 3=A3}
    B1
    false
    true
    true
    {1={A=A1, B=B1, C=C1}, 2={A=A2, B=B2, C=C2}, 3={A=A3, B=B3, C=C3}}
    {A={1=A1, 2=A2, 3=A3}, B={1=B1, 2=B2, 3=B3}, C={1=C1, 2=C2, 3=C3}}
    A1
    {2={A=A2, B=B2, C=C2}, 3={A=A3, B=B3, C=C3}, 1={B=B1, C=C1}}

该接口主要是对类似于table数据结构的一种实现,
row返回一个非空的Map<C,V>视图,标识一行,修改该视图会影响原数据结构,rowMap返回一个Map<R,Map<C,V>>的视图,rowKeySet返回一个类似于Set的结构。
column参考row。
cellSet返回一行,类似于Map.entry,但它是通过行和列区分的。
相关实现:
HashBaseTable
TreeBaseTable
ImmutableTable
ArrayTable: 需要在构建时就确定大小,底层是二维数组,这样可以在数据密集的情况下,提高时间和空间的效率。
ClassToInstanceMap:
提供了类似Map<Class<? extends B>,B>的实现,可以理解为B的子类到B对象的一个映射。

	public static void classToInstanceMapTest() {
		ClassToInstanceMap<String> classToInstanceMap = MutableClassToInstanceMap.create();
		ClassToInstanceMap<Score> classToInstanceMap2 = MutableClassToInstanceMap.create();
		classToInstanceMap.put(String.class, "zhangsan");
		Score sc = new Score(1, 6);
		MathScore src = new MathScore(11, 66);
		classToInstanceMap2.put(Score.class, sc);
		classToInstanceMap2.put(Score.class, src);
		Score sr = classToInstanceMap2.getInstance(Score.class);
		System.out.println(sr);
	}

RangeSet:
RangeMap:
不常用,省略...

hashings

缓存

缓存就是将数据暂时存储在内存之中,以便下次使用。在日常开发中,由于受到硬盘io性能以及我们本身系统获取和处理数据是可能比较耗时,到对这个数据请求量很大时,频繁的硬盘io和数据逻辑处理就会造成硬盘和cpu的资源瓶颈出现。缓存的作用就是将这些数据存放在内存之中,当客户端或者线程需要相同的数据是,直接从内存之中获取,这样可以提交系统的响应时间,也避免了频繁的对相同的数据进行逻辑处理,这样就提高了系统的性能。
Guava提供了两种创建缓存的方式:

	public static void doSomething1() {
		try {
			// 方式一:使用CacheLoader接口
			LoadingCache<String, String> builder = CacheBuilder.newBuilder().build(new CacheLoader<String, String>(){
				public String load(String key) throws Exception {
					return "hello:"+key;
				}
			});
//			System.out.println(builder.get("kitty"));
//			System.out.println(builder.apply("java"));
//			builder.put("key", "value");
//			System.out.println(builder.get("key"));
		
		
			// 方式二:使用callable callback
			Cache<String, String> cache = CacheBuilder.newBuilder().maximumSize(1000).build();
			String zyg = cache.get("sjk", () -> "http:tcp");
			System.out.println(zyg);
			zyg = cache.get("paiet", () -> "功夫熊猫");
			System.out.println(zyg);
			
			
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}

1、cacheLoader泛型实现

        protected static LoadingCache<String, String> loading;   
        
    	public static <K, V> LoadingCache<K, V> cached(CacheLoader<K, V> loader){
		LoadingCache<K , V> cache = CacheBuilder
		          .newBuilder()
		          .maximumSize(2)
		          .weakKeys()
		          .softValues()
		          .refreshAfterWrite(120, TimeUnit.SECONDS)
		          .expireAfterWrite(10, TimeUnit.MINUTES)        
		          .removalListener(new RemovalListener<K, V>(){
		            @Override
		            public void onRemoval(RemovalNotification<K, V> rn) {
		                System.out.println(rn.getValue()+"被移除");  
		                
		            }})
		          .build(loader);
      return cache;
	}
	
	public static LoadingCache<String, String> commonCache(){
		loading = cached(new CacheLoader<String, String>(){
			public String load(String key) throws Exception {
				return "hello"+key;
			}
		 });
		return loading;
	}
	
	public static void doSomething2() {
		// CacheLoader的泛型实现
		loading.put("1", "张三");
		loading.apply("pisa");
	}
	
	public static void doSomething3() {
		// callable callback的泛型实现
		LoadingCache<String, String> ld = commonCache();
		try {
			System.out.println(ld.get("pisa"));
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
	}

2、callable callback泛型实现

    Cache<String,String> cache;
	public static <K,V> Cache<K, V> cached2() {
		return CacheBuilder.newBuilder().maximumSize(100)
				.expireAfterAccess(10, TimeUnit.MINUTES)
				.build();
	}
	
	public static String getCacheValue(final String userName) {
		try {
			return cache.get(userName, new Callable<String>() {
				public String call() throws Exception {
					System.out.println(userName+"from lbld");
					return "hello:"+userName;
				}
			});
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public static void callableTest() {
		cache = cached2();
		System.out.println(getCacheValue("zhangsan"));
	} 

相关方法说明:
1、大小
maxinumsize(long),weigher(weigher),maxinumweigher(long)
2、时间
expireAfterAccess(long,TimeUtil),expireAfterWriter(long,TimeUtil)
3、引用
weekKeys(),weekValues(),softValues()
4、删除
invalidate(key),invalidateAll(keys),invalidateAll()
5、删除监听器
removelListenter(RemovelListener)
6、过期策略(待思考)
LoadingCache.refresh(key) // 在生成新value的时候,旧的仍可以使用
CacheLoader.load(K,V) // 允许使用
CacheBuilder.refreshAfterWriter(long,TimeUtil) // 自动刷新
数据移除:
1、被动移除
1.1、大小
一般使用的是maxinumsize(long)
size指的是缓存的条目数,不是内存或是其他
不一定刚好达到long的大小,临近就会清除不常用的缓存
如果缓存删除了,使用cacheloader方式,会再次查找一次,没有则报错
1.2、时间
expireAfterAccess(long,TimeUtil) 最后一次操作之后
expireAfterWriter(long,TimeUtil) 使用或修改之后
1.3、引用
取决于虚拟机的垃圾回收机制
2、主动移除
invalidate(key),invalidateAll(keys),invalidateAll()

删除监听器是跟删除同步进行的,如果需要异步,可以考虑使用RemovalListeners.asynchronous(RemovalListener, Executor)。 --未验证

io

refelection

concurrent

EvenBus

事件处理机制,是对事件监听、生产/消费,广播/订阅的一个优雅的解决方案。
基本使用:


参考链接:Guava学习笔记
官方教程

原文地址:https://www.cnblogs.com/kungFuPander/p/12467431.html