Guava库
1, Guava是对Java API的补充,对Java开发中常用功能进行更优雅的实现,使得编码更加轻松,代码容易理解。Guava使用了多种设计模式,同时经过了很多测试,得到了越来越多开发团队的青睐。Java最新版本的API采纳了Guava的部分功能,但依旧无法替代。本文以Getting Started With Google Guava原文为学习材料,对Guava中常用的API进行学习,尽量覆盖比较有用的API,包括字符串处理,集合类处理,文件IO处理等。以往我们在使用工具包的时候首先想到是著名的Apache的Commons系列,今天我要介绍的是同样出色,并且目前发展比Apache Commons系列更为迅速的Google Guava库。Google Guava库是一个非常优秀的包含很多Java工具类集的库,广泛使用在Google公司内部,因此它可以被使用到几乎所有的Java项目中。Google Guava库最初发布在2007年,经过几年的更新发展目前其最新的版本为14.0-rc3。
如果你之前有使用过Google collections库,那么请注意该库也已经被合并到Guava中了。想使用Guava工具包很简单,在maven项目中的pom.xml文件中:
<dependency><groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>21.0</version>
</dependency>
2,Guava工具包使用:
1)对象工具类 Objects
实体类(User只有userId和name两个属性)重写toString方法:
Guava写法:
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("userId", userId)
.add("name", name).toString();
}
实体类重写compareTo方法:
public int compareTo(User o) {
return ComparisonChain.start().compare(userId, o.userId).compare(name, o.name).result();
}
实体类重写equals方法:
} public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
User user = (User) o;
return Objects.equal(userId, user.userId) && Objects.equal(name, user.name);
}
实体类重写hashCode方法:
public int hashCode() {
return Objects.hashCode(userId, name);
}
2)三目运算符的写法:
String ret=serivce.operation();
return MoreObjects.firstNonNull(ret,"默认值");//相当于jdk中的return ret!=null?ret:"默认值";
字符串连接器Joiner实现字符串的拼接:
StringBuffer sb = new StringBuffer();
Joiner joiner = Joiner.on(",").skipNulls();//字符串连接器,以|为分隔符,同时去掉null元素
sb = joiner.appendTo(sb, "pengpeng","liangliang","liang",null);
System.out.println(sb.toString());
//======================字符串连接器Joiner==============================
StringBuffer sb = new StringBuffer();
Joiner joiner = Joiner.on(",").skipNulls();//字符串连接器,以|为分隔符,同时去掉null元素
sb = joiner.appendTo(sb, "pengpeng","liangliang","liang",null);
System.out.println(sb.toString());
//将map转化成字符串
java.util.Map<String,String> map = Maps.newLinkedHashMap();
map.put("Cookies", "12332");
map.put("Content-Length", "30000");
map.put("Date", "2016.12.16");
map.put("Mime", "text/html");
String mapToStr = Joiner.on("#").withKeyValueSeparator(":").join(map);
System.out.println(mapToStr);
// 连接List元素并写到文件流
//=====================字符串分割器Splitter================================
Splitter sp = Splitter.on("|").trimResults();
String str = "pengpeng | liangliang";
Iterable<String> ss = sp.split(str);
for(String str1 : ss){
System.out.println(str1);
}
// 将字符串转化为Map 内部类的引用,得到分割器,将字符串解析为map
String mapStr = "id:10#name:pengliang";
Splitter.MapSplitter ms = Splitter.on("#").withKeyValueSeparator(":");
Map<String,String> newMap = ms.split(mapStr);
for(String key :newMap.keySet()){
System.out.println(newMap.get(key));
}
System.out.println(newMap);
//========================字符匹配器CharMatcher==============================
String str2 = "peng liang\r\ryou are a good\tboy"; //空白回车换行对应换成一个#,一对一换
String newStr = CharMatcher.breakingWhitespace().replaceFrom(str2, "#");
System.out.println(newStr);
//字符串工具类Strings 可以处理一些字符串的非空校验等等
if(Strings.isNullOrEmpty("") && Strings.isNullOrEmpty(null)){
System.out.println("字符串空值工具类可用!");
}
//字符串中保留数据
String letterAndNumber = "1234abcdABCD56789";
String num = CharMatcher.JAVA_DIGIT.retainFrom(letterAndNumber);
System.out.println(num);
//===================断言工具类Preconditions===============================
int data = 10;
String strr = null;
//Preconditions.checkNotNull(strr, "strr is null");//检查是否为null,null将抛出异常IllegalArgumentException,且第二个参数为错误消息。
//Preconditions.checkArgument(data>100, "data must be less than 100");
//对象工具类 Objects
String ostr = null;
String result = Objects.firstNonNull(ostr, "hello world");// 如果第一个为空,则返回第二个,同时为null,将抛出NullPointerException异常
System.out.println(result);
//===================整体迭代接口FluentIterable=============================
//使用Predicate整体过滤
User user1 = new User("1","tom");
User user2 = new User("2","Fred");
User user3 = new User("3","Barney");
List<User> userList = Lists.newArrayList(user1, user2, user3);
Iterable<User> iterables = FluentIterable.from(userList).filter(new Predicate<User>(){
@Override
public boolean apply(User user) {
return Integer.parseInt(user.getUserId())>2;
}
});
for(Iterator<User> it = iterables.iterator();it.hasNext();){
System.out.println(it.next());
}
//System.out.println(Iterables.contains(iterables, user3));
//使用Function整体替换,将List<Person>转化为List<String>
List<String> stringList = FluentIterable.from(userList).transform(new Function<User,String>(){
@Override
public String apply(User user) {
return Joiner.on("#").join(user.getUserId(), user.getName());
}
}).toList();
for(String sss : stringList){
System.out.println(sss);
}
//============集合运算工具类Sets========================
//Sets.difference()方法
Set<String> s1 = Sets.newHashSet("1", "2", "3", "4");
Set<String> s2 = Sets.newHashSet("2", "3", "4", "5");
// 得到第一个集合中有而第二个集合没有的字符串
Sets.SetView<String> iterable = Sets.difference(s1, s2);
for(Iterator<String> its = iterable.iterator();its.hasNext();){
System.out.println(its.next());
}
//集合对称差 得到第一个集合和第二个集合中不相同的元素组成的集合(差集) Sets.symmetricDifference()方法求差集
Sets.SetView<String> res2 = Sets.symmetricDifference(s1, s2);
for(Object it14 : res2){
System.out.println(it14); // 1 5
}
// s1和s2的交集 Sets.intersection()方法 求交集
Sets.SetView<String> res3 = Sets.intersection(s1, s2);
for(String it14 : res3){
System.out.println(it14); // 2 3 4
}
// 合并s1和s2 Sets.union()方法 求并集
Sets.SetView<String> res4 = Sets.union(s1, s2);
for(String it14 : res4){
System.out.println(it14); // 1 2 3 4 5
}
//利用Functions将Map转化为Function
Map<String, User> mp = Maps.newHashMap();
mp.put(user1.getName(), user1);
mp.put(user2.getName(), user2);
mp.put(user3.getName(), user3);
// 将map转化为Function,Function的功能是将一个类型转化为另一个类型
Function<String, User> lookup = Functions.forMap(mp);
// 如果键值不存在,则会抛出异常。lookup内部已经有元素
User tmp = lookup.apply("tom");
System.out.println(tmp == user1); // true
//Predicate单个判断 单条的过滤元素
Predicate<User> userPre = new Predicate<User>(){
@Override
public boolean apply(User input) {
return Integer.parseInt(input.getUserId())>2;
}
};
//判断是否符合条件
System.out.println(userPre.apply(user3 ));
//Predicates的and运算 userPre和namePre两个条件都满足才输出true
Predicate<User> namePre = new Predicate<User>(){
@Override
public boolean apply(User user) {
return user.getName().equals("Barney");
}
};
Predicate<User> both = Predicates.and(userPre, namePre); // 利用Predicates工具类,同时满足两个条件成一个predicate
System.out.println(both.apply(user1)); // false
System.out.println(both.apply(user2)); // false
System.out.println(both.apply(user3)); // true
// 至少一个满足组成一个Predicate
Predicate<User> orPre = Predicates.or(userPre, namePre);
System.out.println(orPre.apply(user3)); // false
//==============Map工具类Maps===============
// 将List<User> 转化为Map<String, User>,其中键值对是user.userId -> User
Map<String,User> mapp = Maps.uniqueIndex(userList.iterator(), new Function<User,String>(){
@Override
public String apply(User user) {
return user.getUserId();
}
});
for(Entry<String, User> en : mapp.entrySet()){
System.out.println("key:"+en.getKey()+";"+"value:"+en.getKey());
}
//==============一键多值类Multimap=================
// 用ArrayList保存,一键多值,值不会被覆盖
ArrayListMultimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("foo", "1");
multimap.put("foo", "2");
multimap.put("foo", "3");
multimap.put("bar", "a");
multimap.put("bar", "a");
multimap.put("bar", "b");
for(String mulKey : multimap.keySet()){
System.out.println("key:"+mulKey+";"+"values:"+multimap.get(mulKey));
}
//HashTable存储多值类 HashMultimap 这里采用HashTable保存
HashMultimap<String, String> hashMultimap = HashMultimap.create();
hashMultimap.put("foo", "1");
hashMultimap.put("foo", "2");
hashMultimap.put("foo", "3");
// 重复的键值对值保留一个
hashMultimap.put("bar", "a");
hashMultimap.put("bar", "a");
hashMultimap.put("bar", "b");
for(String it20 : hashMultimap.keySet()){
// 返回类型List<String>
System.out.println(it20 + " : " + hashMultimap.get(it20));
}
System.out.println(hashMultimap.size()); // 5
//================多键类Table===================
//两个键操作 两个键row key和column key,其实就是map中map, map<Integer, map<Integer, String> > mp
HashBasedTable<Integer,Integer,String> table = HashBasedTable.create();
table.put(1, 1, "book");
table.put(1, 2, "turkey");
table.put(2, 2, "apple");
System.out.println(table.get(1, 1));
System.out.println(table.contains(2, 3)); // false
System.out.println(table.containsRow(2)); // true
table.remove(2, 2);
System.out.println(table.get(2, 2)); // null
//从HashBasedTable中获取单独的一个map
Map<Integer, String> row = table.row(1);
Map<Integer, String> column = table.column(2);
System.out.println(row.get(1)); // book
System.out.println(column.get(1)); // turkey
//不可变集合类ImmutableListMultimap
Multimap<Integer, String> mulTileMap = new ImmutableListMultimap.Builder<Integer,String>().put(1, "apple").putAll(2, "apple","pear","book").build();
System.out.println("不可变集合类-"+"key:"+String.valueOf(2)+";"+"values:"+mulTileMap.get(2));
System.out.println(mulTileMap);
//=============区间工具类Range====================
//闭区间 Range.closed
Range<Integer> closedRange = Range.closed(30, 33);
System.out.println("是否包含闭区间内的值:"+closedRange.contains(30));
// 开区间 Range.open
Range<Integer> openRange = Range.open(30, 33);
System.out.println("是否包含开区间内的值:"+openRange.contains(30));
// Range实现了Predicate接口,这里的第一个参数是Predicate,第二个参数是Function
// ageFunction必须返回整数
Person person1 = new Person("zhangsan",30);
Person person2 = new Person("lisi",31);
Person person3 = new Person("wangwu",32);
Function<Person, Integer> ageFunction = new Function<Person, Integer>(){
@Override
public Integer apply(Person person) {
return person.getAge();
}
}; //Predicate判断【断言】
Predicate<Person> agePredicate = Predicates.compose(closedRange, ageFunction);//Predicates的compose运算
System.out.println(agePredicate.apply(person1)); // person1.age == 30 true
//===========比较器工具类 Ordering============
//逆置比较器
Comparator<Person> ageCmp = new Comparator<Person>(){
// Ints是Guava提供的,递增
@Override
public int compare(Person o1, Person o2) {
return Ints.compare(o1.getAge(), o2.getAge());
}
};
List<Person> perList = Lists.newArrayList(person1,person2,person3);
// 将比较器转化为Ordering,得到比较器ageCmp的相反比较器,递减
Collections.sort(perList,Ordering.from(ageCmp).reverse());
//遍历集合
for(Iterator iterList = perList.iterator();iterList.hasNext();){
System.out.println(iterList.next());
}
System.out.println("===============================================");
// 组合多个比较器 Ordering.compound()方法
Comparator<Person> nameCmp = new Comparator<Person>(){
@Override
public int compare(Person o1, Person o2) {
return o1.getName().compareTo(o2.getName());
}
};
Ordering order = Ordering.from(ageCmp).compound(nameCmp); //按照age,name进行排序得到的集合
Collections.sort(perList,order);
for(Iterator its = perList.iterator();its.hasNext();){
System.out.println(its.next());
}
//直接获取最小几个和最大几个
Ordering order2 = Ordering.from(ageCmp);
List<Person> leastList = order2.leastOf(perList, 2);
for(Person per1 : leastList){
System.out.println("per1:"+per1.getAge()+";"+per1.getName());
}
List<Person> greateList = order2.greatestOf(perList, 2);
for(Person per2 : greateList){
System.out.println("per1:"+per2.getAge()+";"+per2.getName());
}
//===============文件工具类Files=======================
//复制,移动重命名文件 可以通过代码来执行命令
File file1 = new File("E:/words.txt");
File file2 = new File("E:/copywords.txt");
File file3 = new File("E:/renamewords.txt");
Files.copy(file1, file2);
Files.move(file2, file3);
// 写文件流
File file4 = new File("E:/write.txt");
Files.write("hello world", file4 ,Charsets.UTF_8);//重新写
Files.append("china", file4, Charsets.UTF_8); // 追加 在hello world后面追china
//获取文件哈希码
HashCode hashCode = Files.hash(file3, Hashing.md5());
System.out.println(file3.getName() + " : " + hashCode);
//读取文件流,将文件行转化为List
// 读文件流
int lineNumber = 1;
List<String> fileList = Files.readLines(file3, Charsets.UTF_8);
for(Iterator<String> it = fileList.iterator(); it.hasNext();){
System.out.println("line " + lineNumber + ":" + it.next()); //把文件中每行的内容都输出来的 有一种mapreduce处理文本文件的意思
lineNumber++;
}
System.out.println("====================================");
//对文件中的内容进行处理,再一次得到List
int lineNumber1 = 1;
File file5 = new File("E:/after.txt");
//TitleLineProcessor:读取文本的每一行内容,以,分割成数组,再将数组中的第一个元素组转到集合List中
List<String> afterFileList = Files.readLines(file5, Charsets.UTF_8,new TitleLineProcessor());
for(Iterator<String> afterIt = afterFileList.iterator();afterIt.hasNext();){
System.out.println("line " + lineNumber1 + ":" + afterIt.next());
lineNumber1++;
}
public class TitleLineProcessor implements LineProcessor<List<String>> {
private final static int INDEX = 0;
private final static Splitter splitter = Splitter.on(",");
private List<String> titles = new ArrayList<String>();
// 每一行都会调用这个函数,进而追加成一个list
@Override
public boolean processLine(String line) throws IOException {
// 获取第一项,并追加到titles
titles.add(Iterables.get(splitter.split(line), INDEX));
return true;
}
// 最终的结果
@Override
public List<String> getResult() {
return titles;
}
}
//================编码工具类BaseEncoding================
//BaseEncoding.base64()的编码和解码
BaseEncoding base64Encoding = BaseEncoding.base64();
byte[] content = Files.toByteArray(file5);
//对原内容进行加密 base64编码
String encoded = base64Encoding.encode(content);
System.out.println("encoded:\n" + encoded);
// 获得对应的加密字符串,可以解密,可逆的,得到原来的字节
byte[] decoded = base64Encoding.decode(encoded);
for(int i = 0; i < decoded.length; i++){
System.out.print(decoded[i] + " ");
}
System.out.println(" ");
//读输入字节流ByteSource和写输出字节流ByteSink
// source是源的意思,封装输入流
ByteSource byteSource = Files.asByteSource(file4);
try {
byte[] contents1 = byteSource.read();
byte[] contents2 = Files.toByteArray(file4); // 两个方法的作用相同
for(int i = 0; i < contents1.length; i++){
assert(contents1[i] == contents2[i]);
System.out.print(contents1[i] + " ");
}
} catch (IOException e) {
e.printStackTrace();
}
// sink是目的地的意思,封装输出流,流会自动关闭
File tmpFile = new File("E:/hello.txt"); // acd
ByteSink byteSink = Files.asByteSink(tmpFile);
try {
byteSink.write(new byte[]{'a', 'c', 'd', '\n'});
} catch (IOException e) {
e.printStackTrace();
}
public class GuavaDemo {
private static Logger logger = Logger.getLogger(GuavaDemo.class);
/*
* 使用Optional的意义:
* Optional对象的使用强迫你去积极的思考这样一种情况,如果你想让你的程序返回null值,这null值代表的含义是什么,因为你想要取得返回值,
* 必然从Optional对象内部去获得,所以你必然会这么去思考,增加了程序的可读性。
*
* 常用方法
* Optional.fromNullable(T):将一个T的实例转换为Optional对象,T的实例可以不为空,也可以为空
* Optional.of(T):获得一个Optional对象,其内部包含了一个非null的T数据类型实例,若T=null,则立刻报错。
* T get():返回Optional包含的T实例,该T实例必须不为空;否则,对包含null的Optional实例调用get()会抛出一个IllegalStateException异常
* 用途:
* Optional<T>的最常用价值在于,例如,假设一个方法返回某一个数据类型,调用这个方法的代码来根据这个方法的返回值来做下一步的动作,
* 若该方法可以返回一个null值表示成功,或者表示失败,在这里看来都是意义含糊的,所以使用Optional<T>作为返回值,
* 则后续代码可以通过isPresent()来判断是否返回了期望的值(原本期望返回null或者返回不为null,其意义不清晰),并且可以使用get()来获得实际的返回值。
*/
public static Optional<Integer> test1() {
return Optional.fromNullable(15);
}
/*
* Preconditions
* 判断参数,如果参数配置错误,就抛出异常
* 写代码时我们可以这样参数判断。
*
* 用途:所以推荐在方法的入口,或运算开始前,先检查数据。
*/
public static void test2(boolean status,List<String> list, int position) {
Preconditions.checkArgument(status); //等价: if (!preCondition) {throw new IllegalArgumentException("preCondition not allow!!");}
Preconditions.checkNotNull(list, "数组对象为:null");//等价于: if (array == null) {throw new NullPointerException("array is null!!");}
Preconditions.checkPositionIndex(position, list.size(), "index超出数组的index了");//等价: if (position > array.length || position < 0) {throw new ArrayIndexOutOfBoundsException("position error!!");}
}
public static String test3( ) {
return null;
}
public static void doSomething() throws Throwable {
//ignore method body
}
/*
* Guava中的排序器是Ordering
*
* 常用的静态方法
* natural():对传入的参数进行自然排序,例如:String排字典序,Int排大小。。。
* usingToString():排字典序。
* artibrary():无序。每次的排序结果都不同。
*
*/
public static void OrderingTest(){
List<Integer> intList = Lists.newArrayList(1,4,3,5,0,8,7);
Ordering<Integer> natural = Ordering.natural();
intList = natural.sortedCopy(intList);
logger.info("natural.sortedCopy:"+intList);
//也可以自定义Ordering排序器
Ordering<Integer> orderingBig = new Ordering<Integer>() {
@Override
public int compare(Integer left, Integer right) {
return left - right;
}
};
}
/*
* Guava Throwable类
* 简化了异常和错误的传播与检查;
*
* 功能:
* guava类库中的Throwables提供了一些异常处理的静态方法,这些方法的从功能上分为两类:
*1, 一类是帮你抛出异常
* 2,另外一类是帮你处理异常。
* 案例:当我们调用一个抛出Throwable或者Exception异常的方法时他们什么异常都有可能抛出来,如果我们要调用这样的方法,
* 就需要对他们的异常做一些处理了,我们需要判断什么样的异常需要抛出去,什么样的异常需要封装成RuntimeException。
* 假定我们要实现一个doIt的方法,该方法要调用doSomething方法,而doIt的定义中只允许抛出SQLException,我们可以这样做:
*
*/
public static void doIt() throws SQLException {
try {
doSomething();
} catch (Throwable throwable) {
//如果是SQLException就抛出
Throwables.propagateIfInstanceOf(throwable, SQLException.class);
//抛出RuntimeException异常
Throwables.propagateIfPossible(throwable);
}
}
public static void main(String[] args){
//===================Optional 处理方法返回为null的情况=================
Optional<Integer> possible = test1();
if(possible.isPresent()){
logger.info("possible value:"+possible.get());
}else{
logger.error("possible value : null");
}
//==========================================================
//===================Preconditions 参数判断========================
test2(true,Lists.newArrayList("yytttrrrr","fsdf","fsfsff"),2);
//==========================================================
//====================默认值得设定==============================
String ret=test3();
//String result = ret!=null?ret:"默认值";
String result = MoreObjects.firstNonNull(ret,"默认值"); //Guava工具包的写法
logger.info("result默认值:"+result);
//===========================================================
//=====================排序===================================
OrderingTest();
//===========================================================
try {
doIt();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//=====================Cuava集合================================
Multimap<String,User> scoreMultimap = ArrayListMultimap.create();
for (int i = 0; i < 5; i++) {
User user = new User();
user.setUserId(String.valueOf(i));
user.setName("tom"+i);
scoreMultimap.put("key"+i, user);
}
Collection<User> userCollection = scoreMultimap.get("key1");
scoreMultimap.remove("key1", userCollection);
for(User user : userCollection){
System.out.println("name:"+user.getName());
}
//google guava集合之Table
Table<Integer, Integer, String> table = HashBasedTable.create();
for (int row = 0; row < 10; row++) {
for (int column = 0; column < 5; column++) {
table.put(row, column, "value of cell (" + row + "," + column + ")");
}
}
//遍历Table
for (int row=0;row<table.rowMap().size();row++) {
Map<Integer,String> rowData = table.row(row);
for (int column =0;column < rowData.size(); column ++) {
System.out.println("cell(" + row + "," + column + ") value is:" + rowData.get(column));
}
}
}
}
参考:http://blog.csdn.net/guozebo/article/details/51590517
/*
* GuavaCache实现本地缓存
*清楚缓存的策略:
* 1)基于存活时间的清除(Timed Eviction)
* 这应该是最常用的清除策略,在构建Cache实例的时候,CacheBuilder提供两种基于存活时间的构建方法:
* (1)expireAfterAccess(long, TimeUnit):缓存项在创建后,在给定时间内没有被读/写访问,则清除。
* (2)expireAfterWrite(long, TimeUnit):缓存项在创建后,在给定时间内没有被写访问(创建或覆盖),则清除。
* expireAfterWrite()方法有些类似于redis中的expire命令,但显然它只能设置所有缓存都具有相同的存活时间。若遇到一些缓存数据的存活时间为1分 * 钟,一些为5分钟,那只能构建两个Cache实例了。
* 2)于容量的清除(size-based eviction)
* 在构建Cache实例的时候,通过CacheBuilder.maximumSize(long)方法可以设置Cache的最大容量数,当缓存数量达到或接近该最大值时,Cache将* * 清除掉那些最近最少使用的缓存。以上是这种方式是以缓存的“数量”作为容量的计算方式,还有另外一种基于“权重”的计算方式。比如每一项缓存 * 所占据的内存空间大小都不一样,可以看作它们有不同的“权重”(weights)。你可以使用CacheBuilder.weigher(Weigher)指定一个权重函数,并 * 且用CacheBuilder.maximumWeight(long)指定最大总重。
*/
public class CacheService {
static SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
// 构建cache实例
final static Cache<Integer, String> cache = CacheBuilder.newBuilder().initialCapacity(10) // 设置cache的初始大小为10,要合理设置该值
.concurrencyLevel(5) // 设置并发数为5,即同一时间最多只能有5个线程往cache执行写入操作
.expireAfterWrite(5, TimeUnit.SECONDS) // 设置cache中的数据在写入之后的存活时间为5秒
.build();
public static void main(String[] args) throws Exception {// main方法是一个线程
// 启动一个线程,每隔2秒输出当前缓存容器缓存数据大小
new Thread() {
@Override
public void run() {
while (true) {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println(
Thread.currentThread().getName() + sdf.format(new Date()) + " size: " + cache.size());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
}
}.start();
// main方法线程做得事情
cache.put(1, "pengliang");
System.out.println(Thread.currentThread().getName() + "write key:1 ,value:" + cache.getIfPresent(1));
Thread.sleep(10000);
cache.put(2, "bbb");
System.out.println(Thread.currentThread().getName() + "write key:2 ,value:" + cache.getIfPresent(2));
Thread.sleep(10000);
// when read other key ,key:2 do not clear
System.out.println(Thread.currentThread().getName() + sdf.format(new Date()) + " after write, key:1 ,value:"
+ cache.getIfPresent(1));
Thread.sleep(2000);
// when read same key ,key:2 clear
System.out.println(Thread.currentThread().getName() + sdf.format(new Date()) + " final, key:2 ,value:"
+ cache.getIfPresent(2));
/*
* 总结: 这在GuavaCache被称为“延迟删除”,即删除总是发生得比较“晚”,这也是GuavaCache不同于其他Cache的地方!
* 这种实现方式的问题:缓存会可能会存活比较长的时间,一直占用着内存。如果使用了复杂的清除策略如基于容量的清除,
* 还可能会占用着线程而导致响应时间变长。但优点也是显而易见的,没有启动线程,不管是实现,还是使用起来都让人觉得简单(轻 量)。
* 如果你还是希望尽可能的降低延迟,可以创建自己的维护线程,以固定的时间间隔调用Cache.cleanUp(),
* ScheduledExecutorService可以帮助你很好地实现这样的定时调度。不过这种方式依然没办法百分百的确定一定是自己的维护线程
* “命中”了维护的工作。
*/
}
}