[Java工具集]Google Guava 常用功能

来源:互联网 发布:java shiro demo 编辑:程序博客网 时间:2024/05/29 09:15

Google Guava简介

引言

Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] 、字符串处理 [string processing] 、I/O 等等。 所有这些工具每天都在被Google的工程师应用在产品服务中。

查阅Javadoc并不一定是学习这些库最有效的方式。在此,我们希望通过此文档为Guava中最流行和最强大的功能,提供更具可读性和解释性的说明。

译文格式说明

  • Guava中的类被首次引用时,都会链接到Guava的API文档。如:Optional<T>。
  • Guava和JDK中的方法被引用时,一般都会链接到Guava或JDK的API文档,一些人所共知的JDK方法除外。如:Optional.of(T), Map.get(key)。
  • 译者对文档的额外说明以斜体显示,并且以“译者注:”开始。

目录

1. 基本工具 [Basic utilities]

让使用Java语言变得更舒适

1.1 使用和避免null:null是模棱两可的,会引起令人困惑的错误,有些时候它让人很不舒服。很多Guava工具类用快速失败拒绝null值,而不是盲目地接受

1.2 前置条件: 让方法中的条件检查更简单

1.3 常见Object方法: 简化Object方法实现,如hashCode()和toString()

1.4 排序: Guava强大的”流畅风格比较器”

1.5 Throwables:简化了异常和错误的传播与检查

2. 集合[Collections]

Guava对JDK集合的扩展,这是Guava最成熟和为人所知的部分

2.1 不可变集合: 用不变的集合进行防御性编程和性能提升。

2.2 新集合类型: multisets, multimaps, tables, bidirectional maps等

2.3 强大的集合工具类: 提供java.util.Collections中没有的集合工具

2.4 扩展工具类:让实现和扩展集合类变得更容易,比如创建Collection的装饰器,或实现迭代器

3. 缓存[Caches]

Guava Cache:本地缓存实现,支持多种缓存过期策略

4. 函数式风格[Functional idioms]

Guava的函数式支持可以显著简化代码,但请谨慎使用它

5. 并发[Concurrency]

强大而简单的抽象,让编写正确的并发代码更简单

5.1 ListenableFuture:完成后触发回调的Future

5.2 Service框架:抽象可开启和关闭的服务,帮助你维护服务的状态逻辑

6. 字符串处理[Strings]

非常有用的字符串工具,包括分割、连接、填充等操作

7. 原生类型[Primitives]

扩展 JDK 未提供的原生类型(如int、char)操作, 包括某些类型的无符号形式

8. 区间[Ranges]

可比较类型的区间API,包括连续和离散类型

9. I/O

简化I/O尤其是I/O流和文件的操作,针对Java5和6版本

10. 散列[Hash]

提供比Object.hashCode()更复杂的散列实现,并提供布鲁姆过滤器的实现

11. 事件总线[EventBus]

发布-订阅模式的组件通信,但组件不需要显式地注册到其他组件中

12. 数学运算[Math]

优化的、充分测试的数学工具类

13. 反射[Reflection]

Guava 的 Java 反射机制工具类

原创文章,转载请注明: 转载自并发编程网 – ifeve.com

Google Guava 常用功能


1、 Preconditions,前置条件判断

  • 没有额外参数:抛出的异常中没有错误消息;
  • 有一个Object对象作为额外参数:抛出的异常使用Object.toString() 作为错误消息;
  • 有一个String对象作为额外参数,并且有一组任意数量的附加Object对象:这个变种处理异常消息的方式有点类似printf,但考虑GWT的兼容性和效率,只支持%s指示符。例如:
1checkArgument(i >= 0"Argument was %s but expected nonnegative", i);
2checkArgument(i < j, "Expected i < j, but %s > %s", i, j);

方法声明(不包括额外参数)描述检查失败时抛出的异常checkArgument(boolean)检查boolean是否为true,用来检查传递给方法的参数。IllegalArgumentExceptioncheckNotNull(T)检查value是否为null,该方法直接返回value,因此可以内嵌使用checkNotNullNullPointerExceptioncheckState(boolean)用来检查对象的某些状态。IllegalStateExceptioncheckElementIndex(int index, int size)检查index作为索引值对某个列表、字符串或数组是否有效。index>=0 && index<size *IndexOutOfBoundsExceptioncheckPositionIndex(int index, int size)检查index作为位置值对某个列表、字符串或数组是否有效。index>=0 && index<=size *IndexOutOfBoundsExceptioncheckPositionIndexes(int start, int end, int size)检查[start, end]表示的位置范围对某个列表、字符串或数组是否有效*IndexOutOfBoundsException2、常见Object方法

equals:bjects.equal("a""a"); // returns true

hashCode:Object.hashCode(Object ..)

compare:使用 ComparisonChain类:

实现一个比较器[Comparator],或者直接实现Comparable接口有时也伤不起。考虑一下这种情况:

01class Person implements Comparable<Person> {
02  private String lastName;
03  private String firstName;
04  private int zipCode;
05 
06  public int compareTo(Person other) {
07    int cmp = lastName.compareTo(other.lastName);
08    if (cmp != 0) {
09      return cmp;
10    }
11    cmp = firstName.compareTo(other.firstName);
12    if (cmp != 0) {
13      return cmp;
14    }
15    return Integer.compare(zipCode, other.zipCode);
16  }
17}

这部分代码太琐碎了,因此很容易搞乱,也很难调试。我们应该能把这种代码变得更优雅,为此,Guava提供了ComparisonChain

ComparisonChain执行一种懒比较:它执行比较操作直至发现非零的结果,在那之后的比较输入将被忽略。

1public int compareTo(Foo that) {
2    return ComparisonChain.start()
3            .compare(this.aString, that.aString)
4            .compare(this.anInt, that.anInt)
5            .compare(this.anEnum, that.anEnum, Ordering.natural().nullsLast())
6            .result();
7}
3、Ordering,排序功能 :

链式调用方法:通过链式调用,可以由给定的排序器衍生出其它排序器

方法描述reverse()获取语义相反的排序器nullsFirst()使用当前排序器,但额外把null值排到最前面。nullsLast()使用当前排序器,但额外把null值排到最后面。compound(Comparator)合成另一个比较器,以处理当前排序器中的相等情况。lexicographical()基于处理类型T的排序器,返回该类型的可迭代对象Iterable<T>的排序器。onResultOf(Function)对集合中元素调用Function,再按返回值用当前排序器排序。

例如,你需要下面这个类的排序器。

class Foo {    @Nullable String sortedBy;    int notSortedBy;}

考虑到排序器应该能处理sortedBy为null的情况,我们可以使用下面的链式调用来合成排序器:

Ordering<Foo> ordering = Ordering.natural().nullsFirst().onResultOf(new Function<Foo, String>() {  public String apply(Foo foo) {    return foo.sortedBy;  }});

当阅读链式调用产生的排序器时,应该从后往前读。上面的例子中,排序器首先调用apply方法获取sortedBy值,并把sortedBy为null的元素都放到最前面,然后把剩下的元素按sortedBy进行自然排序。之所以要从后往前读,是因为每次链式调用都是用后面的方法包装了前面的排序器。

注:用compound方法包装排序器时,就不应遵循从后往前读的原则。为了避免理解上的混乱,请不要把compound写在一长串链式调用的中间,你可以另起一行,在链中最先或最后调用compound。

超过一定长度的链式调用,也可能会带来阅读和理解上的难度。我们建议按下面的代码这样,在一个链中最多使用三个方法。此外,你也可以把Function分离成中间对象,让链式调用更简洁紧凑。

Ordering<Foo> ordering = Ordering.natural().nullsFirst().onResultOf(sortKeyFunction)
4、字符串处理

大小写:CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "CONSTANT_NAME")); // returns "constantName"

字符集:不需要做异常处理:bytes = string.getBytes(Charsets.UTF_8);

collapseFrom(CharSequence, char):把每组连续的匹配字符替换为特定字符。如WHITESPACE.collapseFrom(string, ‘ ‘)把字符串中的连续空白字符替换为单个空格。
matchesAllOf(CharSequence): 测试是否字符序列中的所有字符都匹配。
removeFrom(CharSequence): 从字符序列中移除所有匹配字符。
retainFrom(CharSequence): 在字符序列中保留匹配字符,移除其他字符。
trimFrom(CharSequence): 移除字符序列的前导匹配字符和尾部匹配字符。
replaceFrom(CharSequence, CharSequence):用特定字符序列替代匹配字符

5、

可以简化集合的创建和初始化;

类别原来的写法guava的写法集合创建

Map<String, Map<String, String>> map = new HashMap<String, Map<String,String>>();

List<List<Map<String, String>>> list = new ArrayList<List<Map<String,String>>>();

Map<String, Map<String, String>> map = Maps.newHashMap();

List<List<Map<String, String>>> list = Lists.newArrayList();

//1,简化集合的创建
List<Person> personList= Lists.newLinkedList();
Set<Person> personSet= Sets.newHashSet();
Map<String,Person> personMap= Maps.newHashMap();
Integer[] intArrays= ObjectArrays.newArray(Integer.class,10);

集合初始化 

Set<String> set = new HashSet<String>();

set.add("one");

set.add("two");

set.add("three");

 

Set<String> set = Sets.newHashSet("one","two","three");

List<String> list = Lists.newArrayList("one","two","three");

Map<String, String> map = ImmutableMap.of("ON","TRUE","OFF","FALSE");

//2,简化集合的初始化
List<Person> personList2= Lists.newArrayList(new Person(1, 1, "a", "46546", 1, 20),

new Person(2, 1, "a", "46546", 1, 20));
Set<Person> personSet2= Sets.newHashSet(new Person(1,1,"a","46546",1,20),

new Person(2,1,"a","46546",1,20));
Map<String,Person> personMap2= ImmutableMap.of("hello",new Person(1,1,"a","46546",1,20),"fuck",new Person(2,1,"a","46546",1,20));

 

3.2 不变性

很大一部分是google集合提供了不变性,不变对比可变:

  •  数据不可改变
  • 线程安全
  • 不需要同步逻辑
  •  可以被自由的共享
  • 容易设计和实现
  •  内存和时间高效

不变对比不可修改

google的不变被确保真正不可改变,而不可修改实际上还是可以修改数据;如下所示:

 

Set<Integer> data = new HashSet<Integer>();

data.addAll(Arrays.asList(10, 20, 30, 40, 50, 60, 70, 80));

Set<Integer> fixedData = Collections.unmodifiableSet(data); // fixedData - [50, 70, 80, 20, 40, 10, 60, 30]

data.add(90); // fixedData - [50, 70, 80, 20, 40, 10, 90, 60, 30]

如何创建不可变的集合:

ImmutableSet<Integer> numbers = ImmutableSet.of(10, 20, 30, 40, 50);

使用copyOf方法

ImmutableSet<Integer> another = mmutableSet.copyOf(numbers);

使用Builder方法

ImmutableSet<Integer> numbers2 = ImmutableSet.<Integer>builder().addAll(numbers) .add(60) .add(70).add(80).build();

//3,创建不可变的集合

ImmutableList<Person> personImmutableList=
ImmutableList.of(new Person(1, 1, "a", "46546", 1, 20), new Person(2, 1, "a", "46546", 1, 20));

ImmutableSet<Person> personImmutableSet=ImmutableSet.copyOf(personSet2);

ImmutableMap<String,Person> personImmutableMap=ImmutableMap.<String,Person>builder()
.put("hell",new Person(1,1,"a","46546",1,20)).putAll(personMap2) .build();

 

3.3 新的集合类型

The Guava API provides very useful new collection types that work very nicely with existing java collections.

guava API 提供了有用的新的集合类型,协同已经存在的java集合工作的很好。

分别是 MultiMap, MultiSet, Table, BiMap, ClassToInstanceMap

种类写的例子MultiMap

一种key可以重复的map,子类有ListMultimap和SetMultimap,对应的通过key分别得到list和set


Multimap<String, Person> customersByType =ArrayListMultimap.create();customersByType.put("abc", new Person(1, 1, "a", "46546", 1, 20));

customersByType.put("abc", new Person(1, 1, "a", "46546", 1, 30));
customersByType.put("abc", new Person(1, 1, "a", "46546", 1, 40));
customersByType.put("abc", new Person(1, 1, "a", "46546", 1, 50));
customersByType.put("abcd", new Person(1, 1, "a", "46546", 1, 50));
customersByType.put("abcde", new Person(1, 1, "a", "46546", 1, 50));

for(Person person:customersByType.get("abc"))
{
System.out.println(person.getAge());
}

MultiSet

 

不是集合,可以增加重复的元素,并且可以统计出重复元素的个数,例子如下:

private static void testMulitiSet() {
Multiset<Integer> multiSet = HashMultiset.create();
multiSet.add(10);
multiSet.add(30);
multiSet.add(30);
multiSet.add(40);

System.out.println( multiSet.count(30)); // 2
System.out.println( multiSet.size()); //4
}

Table

 

相当于有两个key的map,不多解释

private static void testTable() {
Table<Integer,Integer,Person> personTable=HashBasedTable.create();
personTable.put(1,20,new Person(1, 1, "a", "46546", 1, 20));
personTable.put(0,30,new Person(2, 1, "ab", "46546", 0, 30));
personTable.put(0,25,new Person(3, 1, "abc", "46546", 0, 25));
personTable.put(1,50,new Person(4, 1, "aef", "46546", 1, 50));
personTable.put(0,27,new Person(5, 1, "ade", "46546",0, 27));
personTable.put(1,29,new Person(6, 1, "acc", "46546", 1, 29));
personTable.put(0,33,new Person(7, 1, "add", "46546",0, 33));
personTable.put(1,66,new Person(8, 1, "afadsf", "46546", 1, 66));

//1,得到行集合
Map<Integer,Person> rowMap= personTable.row(0);
int maxAge= Collections.max(rowMap.keySet());

}

BiMap是一个一一映射,可以通过key得到value,也可以通过value得到key; 

private static void testBitMap() {
//双向map
BiMap<Integer,String> biMap=HashBiMap.create();

biMap.put(1,"hello");
biMap.put(2,"helloa");
biMap.put(3,"world");
biMap.put(4,"worldb");
biMap.put(5,"my");
biMap.put(6,"myc");

int value= biMap.inverse().get("my");
System.out.println("my --"+value);

}

ClassToInstanceMap 
有的时候,你的map的key并不是一种类型,他们是很多类型,你想通过映射他们得到这种类型,guava提供了ClassToInstanceMap满足了这个目的。
 
除了继承自Map接口,ClassToInstaceMap提供了方法 T getInstance(Class<T>) 和 T putInstance(Class<T>, T),消除了强制类型转换。
 
该类有一个简单类型的参数,通常称为B,代表了map控制的上层绑定,例如:
 
ClassToInstanceMap<Number> numberDefaults = MutableClassToInstanceMap.create();
numberDefaults.putInstance(Integer.class, Integer.valueOf(0));
从技术上来说,ClassToInstanceMap<B> 实现了Map<Class<? extends B>, B>,或者说,这是一个从B的子类到B对象的映射,这可能使得ClassToInstanceMap的泛型轻度混乱,但是只要记住B总是Map的上层绑定类型,通常来说B只是一个对象。
guava提供了有用的实现, MutableClassToInstanceMap 和 ImmutableClassToInstanceMap.
重点:像其他的Map<Class,Object>,ClassToInstanceMap 含有的原生类型的项目,一个原生类型和他的相应的包装类可以映射到不同的值;

private static void testClass() {
ClassToInstanceMap<Person> classToInstanceMap =MutableClassToInstanceMap.create();

Person person= new Person(1,20,"abc","46464",1,100);

classToInstanceMap.putInstance(Person.class,person);


// System.out.println("string:"+classToInstanceMap.getInstance(String.class));
// System.out.println("integer:" + classToInstanceMap.getInstance(Integer.class));

Person person1=classToInstanceMap.getInstance(Person.class);

}

 

3.4 谓词和筛选

谓词(Predicate)是用来筛选集合的;

谓词是一个简单的接口,只有一个方法返回布尔值,但是他是一个很令人惊讶的集合方法,当你结合collections2.filter方法使用,这个筛选方法返回原来的集合中满足这个谓词接口的元素;

举个例子来说:筛选出集合中的女人

public static void main(String[] args){Optional<ImmutableMultiset<Person>> optional=Optional.fromNullable(testPredict());if(optional.isPresent()){for(Person p:optional.get()){System.out.println("女人:"+p);}}System.out.println(optional.isPresent());}public static ImmutableMultiset<Person> testPredict(){List<Person> personList=Lists.newArrayList(new Person(1, 1, "a", "46546", 1, 20),new Person(2, 1, "ab", "46546", 0, 30),new Person(3, 1, "abc", "46546", 0, 25),new Person(4, 1, "aef", "46546", 1, 50),new Person(5, 1, "ade", "46546",0, 27),new Person(6, 1, "acc", "46546", 1, 29),new Person(7, 1, "add", "46546",0, 33));return ImmutableMultiset.copyOf(Collections2.filter(personList,new Predicate<Person>() {@Overridepublic boolean apply( Person input) {return input.getSex()==0;}}));}


Predicates含有一些内置的筛选方法,比如说 in ,and ,not等,根据实际情况选择使用。

3.5 功能和转换

转换一个集合为另外一个集合;

实例如下:

public static void main(String[] args){Optional<ImmutableMultiset<String>> optional=Optional.fromNullable(testTransform());if(optional.isPresent()){for(String p:optional.get()){System.out.println("名字:"+p);}}System.out.println(optional.isPresent());}public static ImmutableMultiset<String> testTransform(){List<Person> personList=Lists.newArrayList(new Person(1, 1, "a", "46546", 1, 20),new Person(2, 1, "ab", "46546", 0, 30),new Person(3, 1, "abc", "46546", 0, 25),new Person(4, 1, "aef", "46546", 1, 50),new Person(5, 1, "ade", "46546",0, 27),new Person(6, 1, "acc", "46546", 1, 29),new Person(7, 1, "add", "46546",0, 33));return ImmutableMultiset.copyOf(Lists.transform(personList,new Function<Person, String>() {@Overridepublic String apply( Person input) {return input.getName();}}));}

3.6 排序

 是guava一份非常灵活的比较类,可以被用来操作,扩展,当作比较器,排序提供了集合排序的很多控制;

实例如下:

Lists.newArrayList(30, 20, 60, 80, 10);Ordering.natural().sortedCopy(numbers); //10,20,30,60,80Ordering.natural().reverse().sortedCopy(numbers); //80,60,30,20,10Ordering.natural().min(numbers); //10Ordering.natural().max(numbers); //80Lists.newArrayList(30, 20, 60, 80, null, 10);Ordering.natural().nullsLast().sortedCopy(numbers); //10, 20,30,60,80,nullOrdering.natural().nullsFirst().sortedCopy(numbers); //null,10,20,30,60,80 public static void testOrdering(){List<Person> personList=Lists.newArrayList(new Person(3, 1, "abc", "46546", 0, 25),new Person(2, 1, "ab", "46546", 0, 30),new Person(5, 1, "ade", "46546",0, 27),new Person(1, 1, "a", "46546", 1, 20),new Person(6, 1, "acc", "46546", 1, 29),new Person(4, 1, "aef", "46546", 1, 50),new Person(7, 1, "add", "46546",0, 33));Ordering<Person> byAge=new Ordering<Person>() {@Overridepublic int compare( Person left, Person right) {return right.getAge()-left.getAge();}};for(Person p: byAge.immutableSortedCopy(personList)){System.out.println(p);}}



原文地址:http://blog.csdn.net/songjinbin/article/details/50199649

0 0