com.google.guava 源码学习

  • Post author:
  • Post category:其他




结构

在这里插入图片描述



概述

工具类 就是封装平常用的方法,不需要你重复造轮子,节省开发人员时间,提高工作效率。谷歌作为大公司,当然会从日常的工作中提取中很多高效率的方法出来。所以就诞生了guava。



guava的优点

高效设计良好的API,被Google的开发者设计,实现和使用
遵循高效的java语法实践
使代码更刻度,简洁,简单
节约时间,资源,提高生产力



guava的核心库

集合 [collections]
缓存 [caching]
原生类型支持 [primitives support]
并发库 [concurrency libraries]
通用注解 [common annotations]
字符串处理 [string processing]
I/O 

在这里插入图片描述



引入

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>21.0</version>
</dependency>



使用



集合



集合创建

各种以S结尾的工厂类简化了集合的创建。在创建泛型实例的时候,它们使代码更加简洁

//java 7 中
Map<String,List<String>> m=new HashMap<>();

// java 8 普通Collection的创建
List<String> list = Lists.newArrayList("a","b","c");
Set<String> set = Sets.newHashSet();
Map<String, String> map = Maps.newHashMap();

// 不变Collection的创建
ImmutableList<String> iList = ImmutableList.of("a", "b", "c");
ImmutableSet<String> iSet = ImmutableSet.of("e1", "e2");
ImmutableMap<String, String> iMap = ImmutableMap.of("k1", "v1", "k2", "v2");

创建不可变集合 先理解什么是

immutable(不可变)对象

在 多线程操作 下,是 线程安全的 
所有不可变集合 会比 可变集合 更有效的利用资源
中途不可改变
ImmutableList<String> immutableList = ImmutableList.of("1","2","3","4");
// add 方法
@Deprecated @Override
public final void add(int index, E element) {
 	throw new UnsupportedOperationException();
}

这声明了一个

不可变的List集合

,List中有数据

1,2,3,4

。类中的 操作集合的方法(譬如

add, set, sort, replace

等)都被声明过期,并且抛出异常。 而

没用guava之前是需要声明并且加各种包裹集合才能实现这个功能



集合转换、查找、过滤、分割


将一个集合转换成另外一种类型的集合

Lists.transform()
List<String> listStr = Lists.newArrayList("1", "2", "3");
//将字符串集合转换为Integer集合
List<Integer> listInteger = Lists.transform(listStr, new Function<String, Integer>() {
          @Nullable
          @Override
          public Integer apply(@Nullable String s) {
              return Integer.valueOf(s);
          }
      });


ImmutableMap<String, Integer> m = ImmutableMap.of("begin", 12, "code", 15);
//Function<F, T> F表示apply()方法input的类型,T表示apply()方法返回类型
Map<String, Integer> m2 = Maps.transformValues(m, input -> {
	    if(input > 12){
	        return input;
	    }else{
	        return input + 1;
	    }
	});
System.out.println(m2);
//{begin=13, code=15} 
//java 8 中
 List<Integer> listInteger2 = listStr.stream().map(Integer::valueOf).collect(Collectors.toList());


查找集合首个匹配的元素

 List<String> listStr = Lists.newArrayList("hello", "world", "hehe");
  //查找首个以h开头的值    
  String value = Iterables.find(listStr, new Predicate<String>() {
      @Override
      public boolean apply(String input) {
          return input.startsWith("h");
      }
  });
//java 8
String value2 = listStr.stream().findFirst().filter(input -> input.startsWith("h")).get();


过滤集合中所有符合特定条件的元素

List<String> listWithH = Lists.newArrayList(Collections2.filter(listStr, new Predicate<String>() {
         @Override
         public boolean apply(@Nullable String s) {
             return s.startsWith("h");
         }
     }));

//按照条件过滤
ImmutableList<String> names = ImmutableList.of("begin", "code", "Guava", "Java");
Iterable<String> fitered = Iterables.filter(names, Predicates.or(Predicates.equalTo("Guava"), Predicates.equalTo("Java")));
//java 8
List<String> listWithH2 = listStr.stream().filter(input -> input.startsWith("h")).collect(Collectors.toList());


将一个大的集合分割成小集合,适用于分批查询、插入等场景

 List<String> listStr = Lists.newArrayList("1", "2", "3","4","5","6","7");
 List<List<String>>  batchList = Lists.partition(listStr,3);
 //被分割成了: [[1, 2, 3], [4, 5, 6], [7]]



分组

Maps.uniqueIndex 根据集合中的唯一键把集合转换为以唯一键为key,以元素为value的Map 
Multimaps.index 根据集合中的相同的值把集合转换为以相同值为key,以List<元素>为value的Map. 相当于一键多值Map
class Apple {
    int id;
    String color;
    public Apple(int id, String color) {
        this.id = id;
        this.color = color;
    }
    public int getId() {
        return id;
    }
    public String getColor() {
        return color;
    }
    @Override
    public String toString() {
        return MoreObjects.toStringHelper(Apple.class).add("id", id).add("color", color).toString();
    }
}

@Test
public void test1() {
    List<Apple> appleList = Lists.newArrayList(new Apple(1, "red"), new Apple(2, "red"), new Apple(3, "green"), new Apple(4, "green"));
    // 以主键为key,生成键值对:Map<id,Apple>
    Map<Integer, Apple> appleMap = Maps.uniqueIndex(appleList, new Function<Apple, Integer>() {
        @Nullable
        @Override
        public Integer apply(@Nullable Apple apple) {
            return apple.getId();
        }
    });
    
   // 相当于根据颜色分类:转为Map<颜色,Collection<Apple>>
   Multimap<String, Apple> multiMap = Multimaps.index(appleList,
            new Function<Apple, String>() {
                @Nullable
                @Override
                public String apply(@Nullable Apple apple) {
                    return apple.getColor();
                }
            });
}
List<Apple> appleList = Lists.newArrayList(new Apple(1, "red"), new Apple(2, "red"), new Apple(3, "green"), new Apple(4, "green"));

Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, apple -> apple));

Map<String, List<Apple>> groupsByColor = appleList.stream().collect(Collectors.groupingBy(Apple::getColor));



集合运算工具类



Sets


集合差

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


集合对称差

Sets.SetView res2 = Sets.symmetricDifference(s1, s2);
for(Object it14 : res2){
   System.out.println(it14); // 1 5
}


集合交

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


集合并

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



Map

MapDifference differenceMap = Maps.difference(mapA, mapB);
differenceMap.areEqual();
Map entriesDiffering = differenceMap.entriesDiffering();
Map entriesOnlyLeft = differenceMap.entriesOnlyOnLeft();
Map entriesOnlyRight = differenceMap.entriesOnlyOnRight();
Map entriesInCommon = differenceMap.entriesInCommon();

System.out.println(entriesDiffering);   // {b=(2, 20)}
System.out.println(entriesOnlyLeft);    // {a=1}
System.out.println(entriesOnlyRight);   // {d=4}
System.out.println(entriesInCommon);    // {c=3} 



对JDK集合的有效补充

MultiSet: 无序+可重复   count()方法获取单词的次数  增强了可读性+操作简单
创建方式:  Multiset<String> set = HashMultiset.create();

Multimap: key-value  key可以重复  
创建方式: Multimap<String, String> teachers = ArrayListMultimap.create();

BiMap: 双向Map(Bidirectional Map) 键与值都不能重复
创建方式:  BiMap<String, String> biMap = HashBiMap.create();

Table: 双键的Map Map--> Table-->rowKey+columnKey+value  //和sql中的联合主键有点像
创建方式: Table<String, String, Integer> tables = HashBasedTable.create();

...等等(guava中还有很多java里面没有给出的集合类型)



灰色地带:Multiset


JDK

的集合,提供了

有序且可以重复的List



无序且不可以重复的Set

。那这里其实对于集合涉及到了2个概念,一个order,一个dups。那么List vs Set,and then some ?

在这里插入图片描述

Multiset就是无序的,但是可以重复的集合,它就是游离在List/Set之间的“灰色地带”!
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

注意 区分下面
import org.apache.commons.collections4.MultiSet;
import com.google.common.collect.Multiset;
Multiset<String> set = HashMultiset.create();
set.add("a");
set.add("b");
set.add("c");
System.out.println(set.size());
System.out.println(set.count("a"));  //Multiset自带一个有用的功能,就是可以跟踪每个对象的数量



Immutable vs unmodifiable


JDK

提供的

Collections.unmodifiableXxx



返回的集合和源集合



同一个对象

,只不过可以

对集合做出改变的API都被override

,会

抛出UnsupportedOperationException

也就是说

改变源集合,导致不可变视图(unmodifiable View)也会发生变化


在这里插入图片描述


不使用guava的情况下避免上面的问题

// 下面 揭示了一个概念:Defensive Copies,保护性拷贝
ArrayList<Object> list = Lists.newArrayList("a","b");
List<Object> objects = Collections.unmodifiableList(new ArrayList<>(list));
//  objects.add("a"); //throw java.lang.UnsupportedOperationException

list.add("c");
System.out.println(list); //a b c

使用

guava 的 Immutable

guava提供了很多Immutable集合,比如
ImmutableList/ImmutableSet/ImmutableSortedSet/ImmutableMap/......
ImmutableList<String> list = ImmutableList.of("a", "b", "c");
list.add("c"); //throw java.lang.UnsupportedOperationException

ImmutableList<String> immutableList = ImmutableList.copyOf(list);
immutableList.add("c");    //视图不随着源而改变,guava 设置了只读
System.out.println(list.size() + "\n" + immutableList.size());


ImmutableMap

ImmutableMap<String, String> map = ImmutableMap.of("name", "zhangsan", "sex", "man");
map.put("wife","no")  //throw java.lang.UnsupportedOperationException



可不可以一对多:Multimap


JDK

提供的

Map是一个键,一个值,一对一的

,那么在实际开发中,显然存在

一个KEY多个VALUE

的情况

(比如一个分类下的书本)

,我们往往这样表达:

Map<k,List<v>>

,好像有点臃肿!臃肿也就算了,更加不爽的事,我们

还得判断KEY是否存在来决定是否new 一个LIST出来

,有点麻烦!更加麻烦的事情还在后头,比如遍历,比如删除,so hard…

ArrayListMultimap<Object, Object> multimap = ArrayListMultimap.create();
multimap.put("name","zhangsan");
multimap.put("name","lisi");
multimap.put("age","12");
System.out.println(multimap.get("name"));
guava所有的集合都有create方法,这样的好处在于简单,而且我们不必在重复泛型信息了。

get()/keys()/keySet()/values()/entries()/asMap()都是非常有用的返回view collection的方法。

Multimap的实现类有:
ArrayListMultimap/HashMultimap/LinkedHashMultimap/TreeMultimap/ImmutableMultimap/....
// 用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 it20 : multimap.keySet()){
      // 返回类型List<String>
      System.out.println(it20 + " : " + multimap.get(it20));
  }
  // 返回所有ArrayList的元素个数的和
  System.out.println(multimap.size());
  
//结果
bar : [a, a, b]
foo : [1, 2, 3]
6
  //这里采用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));
  }
  // 5
  System.out.println(hashMultimap.size());

//结果
bar : [a, b]
foo : [1, 2, 3]
5



可不可以双向:BiMap


JDK

提供的MAP让我们可以

find value by key

,那么能不能通过

find key by value

呢,能不能

KEY和VALUE都是唯一的呢

。这是一个

双向的概念

,即

forward+backward

在实际场景中有这样的需求吗?比如

通过用户ID找到mail



也需要通过mail找回用户名

。没有guava的时候,我们需要

create forward map

AND

create backward map

,and now just let guava do that for you.

HashBiMap<Object, Object> bimap = HashBiMap.create();
bimap.put("name","zhangsan");

//bimap.put("student","zhangsan");   //value 相同也会报错 java.lang.IllegalArgumentException: value already present: zhangsan

bimap.put("name","lisi");   //覆盖
bimap.forcePut("student","zhangsan");  // 强制覆盖
bimap.forcePut("age","12");
System.out.println(bimap.inverse().get("zhangsan"));
biMap / biMap.inverse() / biMap.inverse().inverse() 它们是什么关系呢?

你可以稍微看一下BiMap的源码实现,实际上,当你创建BiMap的时候,在内部维护了2个map,一个forward map,一个backward map,并且设置了它们之间的关系。

因此,biMap.inverse() != biMap ;biMap.inverse().inverse() == biMap



可不可以多个KEY:Table

数据库除了主键外,还提供了

复合索引

,而且实际中这样的

多级关系查找

也是比较多的,当然我们可以利用

嵌套的Map来实现:Map<k1,Map<k2,v2>>

。为了让我们的代码看起来不那么丑陋,guava为我们提供了Table。

rowKey,columnKey,value

在这里插入图片描述

  // 两个键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)); // book
  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
	// 获取单独的一个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

   // 不可变的集合,都有一个Builder内部类。不可以修改和添加
   Multimap<Integer, String> map = new ImmutableListMultimap.Builder<Integer, String>().put(1, "hello")
           .putAll(2, "abc", "log", "in").putAll(3, "get", "up").build();
   System.out.println(map.get(2)); // [abc, log, in]



字符串



拼接 Joiner


Joiner

可以快速地

把多个字符串或字符串数组连接成为用特殊符号连接的字符串

List<String> list = Lists.newArrayList("a","b","c");
String value =Joiner.on("-").skipNulls().join(list);
System.out.println(value);
//输出为: a-b-c


joiner.appendTo()

按照

Joiner 规则

追加

StringBuilder stringBuilder = new StringBuilder("hello");
// 字符串连接器,以|为分隔符,同时去掉null元素
Joiner joiner1 = Joiner.on("|").skipNulls();
// 构成一个字符串foo|bar|baz并添加到stringBuilder
stringBuilder = joiner1.appendTo(stringBuilder, "foo", "bar", null, "baz");
System.out.println(stringBuilder); // hellofoo|bar|baz


把map集合转换为特定规则的字符串

Map<String, Integer> map = Maps.newHashMap();
map.put("xiaoming", 12);
map.put("xiaohong",13);
String result = Joiner.on(",").withKeyValueSeparator("=").join(map);
// result为 xiaoming=12,xiaohong=13


连接List元素并写到文件流

FileWriter fileWriter = null;
try{
    fileWriter = new FileWriter(new File("/home/gzx/Documents/tmp.txt"));
} catch(Exception e){
    System.out.println(e.getMessage());
}
List<Date> dateList = new ArrayList<Date>();
dateList.add(new Date());
dateList.add(null);
dateList.add(new Date());

// 构造连接器:如果有null元素,替换为no string
Joiner joiner2 = Joiner.on("#").useForNull("no string");
try{
    // 将list的元素的tostring()写到fileWriter,是否覆盖取决于fileWriter的打开方式,默认是覆盖,若有true,则是追加
    joiner2.appendTo(fileWriter, dateList);
    // 必须添加close(),否则不会写文件
    fileWriter.close();
} catch(IOException e){
    System.out.println(e.getMessage());
}



分割 Splitter


Splitter

用来分割字符串

String testString = "Monday,Tuesday,,Thursday,Friday,,";
//英文分号分割;忽略空字符串
Splitter splitter = Splitter.on(",").omitEmptyStrings().trimResults();
System.out.println(splitter.split(testString).toString());
//转换为了:[Monday, Tuesday, Thursday, Friday]


将String转换为特定的集合

//use java
List<String> list = new ArrayList<String>();
String a = "1-2-3-4-5-6";
String[] strs = a.split("-");
for(int i=0; i<strs.length; i++){
	list.add(strs[i]);
}

//use guava
String str = "1-2-3-4-5-6";
List<String> list = Splitter.on("-").splitToList(str);
//list为  [1, 2, 3, 4, 5, 6]


使用 omitEmptyStrings().trimResults() 去除空串与空格

String str = "1-2-3-4-  5-  6   ";  
List<String> list = Splitter.on("-").omitEmptyStrings().trimResults().splitToList(str);
System.out.println(list);


将String转换为map

String str = "xiaoming=11,xiaohong=23";
Map<String,String> map = Splitter.on(",").withKeyValueSeparator("=").split(str);


特定的正则分隔

String input = "aa.dd,,ff,,.";
List<String> result = Splitter.onPattern("[.|,]").omitEmptyStrings().splitToList(input);



CharMatcher


匹配



CharMatcher

常用来

从字符串里面提取特定字符串


比如想

从字符串中得到所有的数字

String value = CharMatcher.DIGIT.retainFrom("some text 2046 and more");
//value=2046


替换

// 空白回车换行对应换成一个#,一对一换
String stringWithLinebreaks = "hello world\r\r\ryou are here\n\ntake it\t\t\teasy";
String s6 = CharMatcher.BREAKING_WHITESPACE.replaceFrom(stringWithLinebreaks,'#');
System.out.println(s6); // hello#world###you#are#here##take#it###easy


连续空白缩成一个字符

// 将所有连在一起的空白回车换行字符换成一个#,倒塌
String tabString = "  hello   \n\t\tworld   you\r\nare             here  ";
String tabRet = CharMatcher.WHITESPACE.collapseFrom(tabString, '#');
System.out.println(tabRet); // #hello#world#you#are#here#


去掉前后空白和缩成一个字符

// 在前面的基础上去掉字符串的前后空白,并将空白换成一个#
String trimRet = CharMatcher.WHITESPACE.trimAndCollapseFrom(tabString, '#');
System.out.println(trimRet);// hello#world#you#are#here


inRange

// 判断匹配结果
boolean result = CharMatcher.inRange('a', 'z').or(CharMatcher.inRange('A', 'Z')).matches('K'); //true

// 保留数字文本  CharMatcher.digit() 已过时   retain 保留
//String s1 = CharMatcher.digit().retainFrom("abc 123 efg"); //123
String s1 = CharMatcher.inRange('0', '9').retainFrom("abc 123 efg"); // 123

// 删除数字文本  remove 删除
// String s2 = CharMatcher.digit().removeFrom("abc 123 efg");    //abc  efg
String s2 = CharMatcher.inRange('0', '9').removeFrom("abc 123 efg"); // abc  efg




Strings 工具类

System.out.println(Strings.isNullOrEmpty("")); // true
System.out.println(Strings.isNullOrEmpty(null)); // true
System.out.println(Strings.isNullOrEmpty("hello")); // false
// 将null转化为""
System.out.println(Strings.nullToEmpty(null)); // ""

// 从尾部不断补充T只到总共8个字符,如果源字符串已经达到或操作,则原样返回。类似的有padStart
System.out.println(Strings.padEnd("hello", 8, 'T')); // helloTTT



Function



利用Functions将Map转化为Function


Function

的功能是

将一个类型转化为另一个类型

 Map<String, Person> mp = Maps.newHashMap();
 mp.put(person1.getName(), person1);
 mp.put(person2.getName(), person2);
 mp.put(person3.getName(), person3);
 mp.put(person4.getName(), person4);
 
 // 将map转化为Function
 Function<String, Person> lookup = Functions.forMap(mp);
 // 如果键值不存在,则会抛出异常。lookup内部已经有元素
 Person tmp = lookup.apply("Betty");
 System.out.println(tmp == person3); // true
public void testConverte1() {
    ArrayList<String> strings = Lists.newArrayList("helloworld", "deadtodead", "newbirth");
    Function<String, String> function = new Function<String, String>() {
        @Nullable
        @Override
        public String apply(@Nullable String s) {
            return s.length()<=4 ? s : s.substring(0,4);
        }
    };

    Function<String, String> function1 = new Function<String, String>() {
        @Nullable
        @Override
        public String apply(@Nullable String s) {
            return s.toUpperCase();
        }
    };

    Function<String, String> compose = Functions.compose(function, function1);
    Collection<String> transform = Collections2.transform(strings, compose);
    transform.forEach(t-> System.out.println(t));
}

好处在于在

集合遍历操作中提供自定义Function的操作

,比如

transform转换

。我们再也不需要一遍遍的遍历集合,显著的简化了代码

在这里插入图片描述



断言 Predicate


Predicate

最常用的功能就是

运用在集合的过滤当中


在这里插入图片描述

//use java
if(list!=null && list.size()>0)
'''
if(str!=null && str.length()>0)
'''
if(str !=null && !str.isEmpty())

//use guava
if(!Strings.isNullOrEmpty(str))
//use java
if (count <= 0) {
    throw new IllegalArgumentException("must be positive: " + count);         
}    

//use guava
Preconditions.checkArgument(count > 0, "must be positive: %s", count);  

在这里插入图片描述

在这里插入图片描述



Predicate单个判断

   Predicate<Person> agePre = new Predicate<Person>(){
       @Override
       public boolean apply(Person person) {
           return person.getAge() < 32;
       }
   };
   Predicate<Person> namePre = new Predicate<Person>(){
       @Override
       public boolean apply(Person person) {
           return person.getName().equals("Betty");
       }
   };
   // 判断是否符合条件
   System.out.println(agePre.apply(person2)); // false
   System.out.println(namePre.apply(person3)); // true



Predicates的and运算

  // 利用Predicates工具类,同时满足两个条件成一个predicate
  Predicate<Person> both = Predicates.and(agePre, namePre);
  System.out.println(both.apply(person1)); // false 



Predicates的or运算

  //至少一个满足组成一个Predicate
  Predicate<Person> orPre = Predicates.or(agePre, namePre);
  System.out.println(orPre.apply(person2)); // false



Predicates的compose运算

   // 通过键name获得值Person,然后检查Person的age < 32,即agepre.apply(lookup.apply(name)) == true?
   // lookup内部已经有集合
   Predicate<String> two = Predicates.compose(agePre, lookup);
   System.out.println(two.apply("Wilma")); // true



文件操作 Files



写文件流

  // 写文件流
  File writeFile = new File("/home/gzx/Documents/write.txt");
  try {
      // 不必打开或关闭文件流,会自动写盘
      Files.write("hello world!", writeFile, Charsets.UTF_8); // 重新写
      Files.append("你的名字", writeFile, Charsets.UTF_8); // 追加
  } catch (IOException e) {
      e.printStackTrace();
  }



读取文件流

以前写文件读取要定义缓冲区,各种条件判断,使用 guava 后就简单多了

File file = new File("test.txt");
List<String> list = null;
try {
	list = Files.readLines(file, Charsets.UTF_8);
} catch (Exception e) {
}



读输入字节流ByteSource和写输出字节流ByteSink

	// source是源的意思,封装输入流
	ByteSource byteSource = Files.asByteSource(writeFile);
	try {
	    byte[] contents1 = byteSource.read();
	    byte[] contents2 = Files.toByteArray(writeFile); // 两个方法的作用相同
	    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("/home/gzx/Documents/hello.txt"); // acd
	ByteSink byteSink = Files.asByteSink(tmpFile);
	try {
	    byteSink.write(new byte[]{'a', 'c', 'd', '\n'});
	} catch (IOException e) {
	    e.printStackTrace();
	}



编码工具类BaseEncoding

  FilepdfFile = new File("/home/gzx/Documents/google.pdf");
  BaseEncoding baseEncoding = BaseEncoding.base64();
  try {
      byte[] content = Files.toByteArray(pdfFile);
      String encoded = baseEncoding.encode(content); // 将不可打印的字符串转化为可以打印的字符串A-Za-z0-9/+=,pdf不是纯文本文件
      System.out.println("encoded:\n" + encoded);
      System.out.println(Pattern.matches("[A-Za-z0-9/+=]+", encoded));
      // 获得对应的加密字符串,可以解密,可逆的,得到原来的字节
      byte[] decoded = baseEncoding.decode(encoded);
      for(int i = 0; i < content.length; i++){
          assert(content[i] == decoded[i]);
      }
  } catch (IOException e) {
      e.printStackTrace();
  }



移动复制重命名删除等

 // 文件操作:复制,移动,重命名
 File originFile = new File("/home/gzx/Documents/Program/Java/abc.java");
 File copyFile = new File("/home/gzx/Documents/test.java");
 File mvFile = new File("/home/gzx/Documents/abc.java");
 try {
     Files.copy(originFile, copyFile);  //复制文件
     Files.move(copyFile, mvFile); // 重命名
 }
 catch(IOException e){
     e.printStackTrace();
 }
Files.deleteDirectoryContents(File directory); //删除文件夹下的内容(包括文件与子文件夹)  
Files.deleteRecursively(File file); //删除文件或者文件夹  
URL url = Resources.getResource("abc.xml"); //获取classpath根下的abc.xml文件url
...



获取文件哈希码

 try {
     // File,HashFunction
     HashCode hashCode = Files.hash(originFile, Hashing.md5());
     System.out.println(originFile.getName() + " : " + hashCode);
 } catch (IOException e) {
     e.printStackTrace();
 }
abc.java : 66721c8573de09bd17bafac125e63e98



提醒处理null的类Optional

 Optional<Person> optional = Optional.fromNullable(person1); // 允许参数为null
 System.out.println(optional.isPresent()); // true
 System.out.println(optional.get() == person1); // 如果是person1 == null,get将抛出IllegalStateException, true

 Optional<Person> optional2 = Optional.of(person1); // 不允许参数为null。如果person1 == null, 将抛出NullPointerException
 System.out.println(optional2.isPresent()); // true


项目中用到的Optional



线程

com.google.common.util.concurrent目录下是各种线程工具类


ListenableFuture



可以监听的Future

,它是

对java原生Future的扩展增强




MoreExecutors

: 提供了很多

静态方法

。其中

listeningDecorator

方法

初始化ListeningExecutorService方法

,使用此实例

submit方法即可初始化ListenableFuture对象




ListeningExecutorService



invokeAny

继承自Jdk原生类,

率先返回线程组中首个执行完毕的




ListeningExecutorService



invokeAll


并行执行

线程组,

等待所有线程执行完毕

,适用于

批量处理

public final List<String> list = Lists.newArrayList("a", "b", "c", "d", "e", "f");

 @Test
 public void testGuava() {
     ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
     List<Callable<String>> allThread = Lists.newArrayList();
     for (final String value : list) {
         Callable<String> callable = new Callable<String>() {
             @Override
             public String call() {
                 return value + " 休息了 " + sleepRandom();
             }
         };
         allThread.add(callable);
     }
     try {
         //1. 返回首个执行完毕的值
         //  String date = listeningExecutorService.invokeAny(allThread);
         // 2. 并行执行完所有线程
         List<Future<String>> valueList = listeningExecutorService.invokeAll(allThread);
         for (Future<String> future : valueList) {
             System.out.println(future.get());
         }
     } catch (Exception e) {
         e.printStackTrace();
     } finally {
         listeningExecutorService.shutdown();
     }
 }

java 8 中

 @Test
 public void testJava8() throws Exception {

     ExecutorService executor = Executors.newFixedThreadPool(10);
     List<CompletableFuture> futures = list.stream()
             .map(value -> CompletableFuture.completedFuture(value).thenApplyAsync(s -> s + " 休息了 " + sleepRandom(), executor))
             .collect(Collectors.toList());
     //1. 返回首个执行完毕的值
     // CompletableFuture valueFuture = CompletableFuture.anyOf(futures.toArray(new CompletableFuture[futures.size()]));
     // 2. 并行执行完所有线程
     CompletableFuture valueFutureList = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
     futures.stream().forEach(f -> {
         try {
             System.out.println(f.get());
         } catch (Exception e) {

         }
     });

 }



缓存


Guava缓存详解及使用



其他

Lists并没有提供filter方法,不过你可以使用Collections2.filter



计算中间代码的运行时间 Stopwatch

import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;

public class Test9 {
    public static void main(String[] args) throws InterruptedException {
        // 创建stopwatch并开始计时
        Stopwatch stopwatch = Stopwatch.createStarted();
        Thread.sleep(1980);

        // 以秒打印从计时开始至现在的所用时间,向下取整
        System.out.println(stopwatch.elapsed(TimeUnit.SECONDS)); // 1

        // 停止计时
        stopwatch.stop();
        System.out.println(stopwatch.elapsed(TimeUnit.SECONDS)); // 1

        // 再次计时
        stopwatch.start();
        Thread.sleep(100);
        System.out.println(stopwatch.elapsed(TimeUnit.SECONDS)); // 2

        // 重置并开始
        stopwatch.reset().start();
        Thread.sleep(1030);

        // 检查是否运行
        System.out.println(stopwatch.isRunning()); // true
        long millis = stopwatch.elapsed(TimeUnit.MILLISECONDS); // 1034
        System.out.println(millis);

        // 打印
        System.out.println(stopwatch.toString()); // 1.034 s
    }
}



MoreObjects

这个方法是在

Objects过期后官方推荐使用的替代品

,该类最大的好处就是

不用大量的重写 toString

,用一种很优雅的方式实现重写,或者在某个场景定制使用

Person person = new Person("aa",11);
String str = MoreObjects.toStringHelper("Person").add("age", person.getAge()).toString();
System.out.println(str);  
//输出Person{age=11}


firstNonNull

// 如果第一个为空,则返回第二个,同时为null,将抛出NullPointerException异常
String someString = null;
String value = Objects.firstNonNull(someString, "default value");
System.out.println(value); // deafult value



区间工具类Range

   // 闭区间
   Range<Integer> closedRange = Range.closed(30, 33);
   System.out.println(closedRange.contains(30)); // true
   System.out.println(closedRange.contains(33)); // true

   // 开区间
   Range<Integer> openRange = Range.open(30, 33);
   System.out.println(openRange.contains(30)); // false
   System.out.println(openRange.contains(33)); // false

   Function<Person, Integer> ageFunction = new Function<Person, Integer>(){
       @Override
       public Integer apply(Person person) {
           return person.getAge();
       }
   };
   // Range实现了Predicate接口,这里的第一个参数是Predicate,第二个参数是Function
   // ageFunction必须返回整数
   Predicate<Person> agePredicate = Predicates.compose(closedRange, ageFunction);
   System.out.println(agePredicate.apply(person1)); // person1.age == 30 true



Ordering排序器

可以用来为构建复杂的比较器,以完成集合排序的功能

natural()	对可排序类型做自然排序,如数字按大小,日期按先后排序
usingToString()	按对象的字符串形式做字典排序[lexicographical ordering]
from(Comparator)	把给定的Comparator转化为排序器
reverse()	获取语义相反的排序器
nullsFirst()	使用当前排序器,但额外把null值排到最前面。
nullsLast()	使用当前排序器,但额外把null值排到最后面。
compound(Comparator)	合成另一个比较器,以处理当前排序器中的相等情况。
lexicographical()	基于处理类型T的排序器,返回该类型的可迭代对象Iterable<T>排序器
onResultOf(Function)	对集合中元素调用Function,再按返回值用当前排序器排序
Person person = new Person("aa",14);  //String name  ,Integer age
Person ps = new Person("bb",13);
Ordering<Person> byOrdering = Ordering.natural().nullsFirst().onResultOf(new Function<Person,String>(){
    @OverWirte
	public String apply(Person person){
		return person.age.toString();
	}
});
int res = byOrdering.compare(person, ps);
System.out.println(res); //1      person的年龄比ps大 所以输出1



组合多个比较器

  // 按照名字排序
  Comparator<Person> nameCmp = new Comparator<Person>(){
      @Override // 两个对象,而Comparable是this和一个对象
      public int compare(Person o1, Person o2) {
          return o1.getName().compareTo(o2.getName());
      }
  };
  
  // 组合两个比较器,得到第一二排序关键字
  // 年龄相同时按照名字排序
  Ordering order = Ordering.from(ageCmp).compound(nameCmp);
  Collections.sort(list, order);
  for(Iterator<Person> iter = list.iterator(); iter.hasNext(); ){
      System.out.println(iter.next());
  }
Person{name='Wilma', sex='F', age=30}
Person{name='Betty', sex='F', age=32}
Person{name='Fred', sex='M', age=32}
Person{name='Barney', sex='M', age=33} 



获取最小几个和最大几个

  Ordering order2 = Ordering.from(nameCmp);
  
  // 最小的两个,无序
  System.out.println("least 2...");
  List<Person> least = order2.leastOf(personList, 2);
  for(int i = 0; i < 2; i++){
      System.out.println(least.get(i));
  }
  
  // 最大的三个,无序
  System.out.println("greatest 3....");
  List<Person> great = order2.greatestOf(personList, 3);
  for(int i = 0; i < 3; i++){
      System.out.println(great.get(i));
  }
least 2...
Person{name='Barney', sex='M', age=33}
Person{name='Betty', sex='F', age=32}
greatest 3....
Person{name='Wilma', sex='F', age=30}
Person{name='Fred', sex='M', age=32}
Person{name='Betty', sex='F', age=32}