Guava库API使用部分总结

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文件中:

   
            com.google.guava
            guava
            21.0
       

       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 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 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 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 userList = Lists.newArrayList(user1, user2, user3); 
Iterable iterables =  FluentIterable.from(userList).filter(new Predicate(){
@Override
public boolean apply(User user) {
return Integer.parseInt(user.getUserId())>2;
}
});
for(Iterator it = iterables.iterator();it.hasNext();){
System.out.println(it.next());
}
//System.out.println(Iterables.contains(iterables, user3));  

//使用Function整体替换,将List转化为List
List stringList = FluentIterable.from(userList).transform(new Function(){


@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 s1 = Sets.newHashSet("1", "2", "3", "4");  
Set s2 = Sets.newHashSet("2", "3", "4", "5");  
// 得到第一个集合中有而第二个集合没有的字符串  
Sets.SetView iterable =  Sets.difference(s1, s2);
for(Iterator its = iterable.iterator();its.hasNext();){
System.out.println(its.next());
}

//集合对称差 得到第一个集合和第二个集合中不相同的元素组成的集合(差集)    Sets.symmetricDifference()方法求差集
Sets.SetView res2 = Sets.symmetricDifference(s1, s2);  
for(Object it14 : res2){  
   System.out.println(it14); // 1 5  
}  

// s1和s2的交集   Sets.intersection()方法     求交集
Sets.SetView res3 = Sets.intersection(s1, s2);  
for(String it14 : res3){  
   System.out.println(it14); // 2 3 4  
}

// 合并s1和s2    Sets.union()方法     求并集
Sets.SetView res4 = Sets.union(s1, s2);  
for(String it14 : res4){  
   System.out.println(it14); // 1 2 3 4 5  
}

//利用Functions将Map转化为Function
Map mp = Maps.newHashMap();  
mp.put(user1.getName(), user1);  
mp.put(user2.getName(), user2);  
mp.put(user3.getName(), user3);  
// 将map转化为Function,Function的功能是将一个类型转化为另一个类型  
Function lookup = Functions.forMap(mp);  
// 如果键值不存在,则会抛出异常。lookup内部已经有元素  
User tmp = lookup.apply("tom");  
System.out.println(tmp == user1); // true  

//Predicate单个判断   单条的过滤元素
Predicate userPre = new Predicate(){
@Override
public boolean apply(User input) {
return Integer.parseInt(input.getUserId())>2;
}
};
//判断是否符合条件
System.out.println(userPre.apply(user3 ));

   //Predicates的and运算     userPre和namePre两个条件都满足才输出true
Predicate namePre = new Predicate(){  
   @Override  
   public boolean apply(User user) {  
       return user.getName().equals("Barney");  
   }  
};  
Predicate 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 orPre = Predicates.or(userPre, namePre);  
System.out.println(orPre.apply(user3)); // false  

//==============Map工具类Maps===============
// 将List 转化为Map,其中键值对是user.userId -> User  
Map mapp = Maps.uniqueIndex(userList.iterator(), new Function(){
@Override
public String apply(User user) {
return user.getUserId();
}
});
for(Entry en : mapp.entrySet()){
System.out.println("key:"+en.getKey()+";"+"value:"+en.getKey());
}

//==============一键多值类Multimap=================
// 用ArrayList保存,一键多值,值不会被覆盖  
ArrayListMultimap 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 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  
   System.out.println(it20 + " : " + hashMultimap.get(it20));  
}  
System.out.println(hashMultimap.size());  // 5  

//================多键类Table===================
//两个键操作        两个键row key和column key,其实就是map中map, map > mp  
HashBasedTable 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 row = table.row(1);  
Map column = table.column(2);  
System.out.println(row.get(1)); // book  
System.out.println(column.get(1)); // turkey  

//不可变集合类ImmutableListMultimap
Multimap mulTileMap = new ImmutableListMultimap.Builder().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 closedRange = Range.closed(30, 33); 
System.out.println("是否包含闭区间内的值:"+closedRange.contains(30));
// 开区间  Range.open
Range 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 ageFunction = new Function(){  
   @Override  
   public Integer apply(Person person) {  
       return person.getAge();  
   }  
};  //Predicate判断【断言】
Predicate agePredicate = Predicates.compose(closedRange, ageFunction);//Predicates的compose运算
System.out.println(agePredicate.apply(person1)); // person1.age == 30 true  

//===========比较器工具类 Ordering============
//逆置比较器
Comparator ageCmp = new Comparator(){  
   // Ints是Guava提供的,递增  
   @Override  
   public int compare(Person o1, Person o2) {  
       return Ints.compare(o1.getAge(), o2.getAge());  
   }  
};  
List 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 nameCmp = new Comparator(){
@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 leastList = order2.leastOf(perList, 2);
for(Person per1 : leastList){
System.out.println("per1:"+per1.getAge()+";"+per1.getName());
}
List 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 fileList = Files.readLines(file3, Charsets.UTF_8);
   for(Iterator 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 afterFileList = Files.readLines(file5, Charsets.UTF_8,new TitleLineProcessor());
   for(Iterator afterIt = afterFileList.iterator();afterIt.hasNext();){
    System.out.println("line " + lineNumber1 + ":" + afterIt.next());  
    lineNumber1++;  
   }


         public class TitleLineProcessor implements LineProcessor> {

private final static int INDEX = 0;  
private final static Splitter splitter = Splitter.on(",");  
private List titles = new ArrayList();  


// 每一行都会调用这个函数,进而追加成一个list
@Override
public boolean processLine(String line) throws IOException {
// 获取第一项,并追加到titles  
        titles.add(Iterables.get(splitter.split(line), INDEX));  
        return true;  
}


// 最终的结果  
@Override
public List 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的最常用价值在于,例如,假设一个方法返回某一个数据类型,调用这个方法的代码来根据这个方法的返回值来做下一步的动作,
 * 若该方法可以返回一个null值表示成功,或者表示失败,在这里看来都是意义含糊的,所以使用Optional作为返回值,
 * 则后续代码可以通过isPresent()来判断是否返回了期望的值(原本期望返回null或者返回不为null,其意义不清晰),并且可以使用get()来获得实际的返回值。
 */
   public static Optional test1() {
       return Optional.fromNullable(15);
   }
   
   /*
    * Preconditions
    * 判断参数,如果参数配置错误,就抛出异常
    * 写代码时我们可以这样参数判断。 
    * 
    * 用途:所以推荐在方法的入口,或运算开始前,先检查数据。
    */
   public static void test2(boolean status,List 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 intList = Lists.newArrayList(1,4,3,5,0,8,7);
    Ordering natural = Ordering.natural();
    intList = natural.sortedCopy(intList);
    logger.info("natural.sortedCopy:"+intList);
                   //也可以自定义Ordering排序器
        Ordering orderingBig = new Ordering() {
        @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 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 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 userCollection = scoreMultimap.get("key1");
       scoreMultimap.remove("key1", userCollection);
       for(User user : userCollection){
        System.out.println("name:"+user.getName());
       }
       //google guava集合之Table
       Table 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            Map 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 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可以帮助你很好地实现这样的定时调度。不过这种方式依然没办法百分百的确定一定是自己的维护线程
* “命中”了维护的工作。
*/


}
}

















你可能感兴趣的:(1)