【Java技术专题】「Guava开发指南」带你认识和学习Guava的集合API的实用技巧和实战技术(实战基础)

这里写目录标题

  • 什么是Guava
  • Guava架构分析
    • 源码包的分布
    • 功能组件分布
  • Guava开发入门
    • Maven依赖
    • 集合使用技巧
      • 创建和初始化
        • 集合创建
          • guava的写法
          • 简化集合的创建
            • LinkedList的创建操作
            • HashSet的创建操作
            • HashMap的创建操作
            • Array数据的创建操作
            • 复杂集合+泛型话处理
        • 集合初始化
          • Set集合的原生创建模式
          • Set集合的Guava创建模式
          • List集合的Guava创建模式
        • 集合不变性
          • 创建不可变的集合
            • 实用原生的方式进行建立Set集合
            • 实用Guava的方式进行建立Set集合
        • 特殊的集合类型
          • MultiMap
            • 实用案例
          • MultiSet
            • 计算Multiset的对应的元素数量(去重)
            • 计算Multiset的对应的元素数量(不去重)
          • Table
            • 创建table对象
            • 设置数据案例
            • 得到行集合Map数据
          • BiMap
            • 创建双向map
            • 测试双向取数据
        • ClassToInstanceMap
        • 使用谓词进行数据筛选
          • 谓词(Predicate)是用来筛选集合
          • 案例-筛选出集合中的女人
      • 集合的功能和转换
      • 排序
        • 使用实例如下
          • 初始化数据元素
          • 拷贝且进行自然排序
          • 倒序且进行自然排序
          • 计算最大值或最小值
          • 插入一个空元素
          • 进行复杂对象的排序操作

什么是Guava

Guava是一个Java编程语言的开源工具库,由Google开发和维护。它提供了许多实用的工具类和方法,用于简化Java编程中的常见任务,例如,集合(collections)操作、缓存(caching)操作、字符串处理(string processing)、并发编程(concurrency libraries)、I/O操作等等。Guava的目标是提高Java编程的生产力和代码质量,使开发人员能够更快地编写出高质量的代码。Guava的特点主要包括:

  1. 高效的集合工具类:Guava提供了许多高效的集合工具类,例如Immutable集合、Multiset、Multimap等等,可以大大简化集合操作的代码。

  2. 字符串处理工具类:Guava提供了许多字符串处理工具类,例如Splitter、Joiner、CaseFormat等等,可以方便地进行字符串的拆分、连接、格式化等操作。

  3. 并发编程工具类:Guava提供了许多并发编程工具类,例如ListenableFuture、RateLimiter、Monitor等等,可以方便地进行并发编程。

  4. I/O操作工具类:Guava提供了许多I/O操作工具类,例如Files、ByteStreams、CharStreams等等,可以方便地进行文件读写、流操作等操作。

总之,Guava是一个非常实用的Java工具库,这些高质量的API可以使你的JAVA代码更加优雅,更加简洁,可以大大提高Java编程的效率和代码质量,下面我们就开启优雅Java编程学习之旅!

Guava架构分析

源码包的分布

  • com.google.common.annotations:普通注解类型。
  • com.google.common.base:基本工具类库和接口。
  • com.google.common.cache:缓存工具包,非常简单易用且功能强大的JVM内缓存。
  • com.google.common.collect:带泛型的集合接口扩展和实现,以及工具类集合。
  • com.google.common.eventbus:发布订阅风格的事件总线。
  • com.google.common.hash: 哈希工具包。
  • com.google.common.io:I/O工具包。
  • com.google.common.math:原始算术类型和超大数的运算工具包。
  • com.google.common.net:网络工具包。
  • com.google.common.primitives:八种原始类型和无符号类型的静态工具包。
  • com.google.common.reflect:反射工具包。
  • com.google.common.util.concurrent:多线程工具包。

功能组件分布

基本工具类:让使用Java语言更令人愉悦。

  1. 使用和避免 null:null 有语言歧义, 会产生令人费解的错误, 反正他总是让人不爽。很多 Guava 的工具类在遇到 null 时会直接拒绝或出错,而不是默默地接受他们。
  2. 前提条件:更容易的对你的方法进行前提条件的测试。
  3. 常见的对象方法: 简化了Object常用方法的实现, 如 hashCode() 和 toString()。
  4. 排序: Guava 强大的 "fluent Comparator"比较器, 提供多关键字排序。
  5. Throwable类: 简化了异常检查和错误传播。

二. 集合类:集合类库是 Guava 对 JDK 集合类的扩展, 这是 Guava 项目最完善和为人所知的部分。

  1. Immutable collections(不变的集合): 防御性编程, 不可修改的集合,并且提高了效率。
  2. New collection types(新集合类型):JDK collections 没有的一些集合类型,主要有:multisets,multimaps,tables, bidirectional maps等等
  3. Powerful collection utilities(强大的集合工具类): java.util.Collections 中未包含的常用操作工具类
  4. Extension utilities(扩展工具类): 给 Collection 对象添加一个装饰器? 实现迭代器? 我们可以更容易使用这些方法。

三. 缓存: 本地缓存,可以很方便的操作缓存对象,并且支持各种缓存失效行为模式。
四. Functional idioms(函数式): 简洁, Guava实现了Java的函数式编程,可以显著简化代码。
五. Concurrency(并发):强大,简单的抽象,让我们更容易实现简单正确的并发性代码。

  1. ListenableFuture(可监听的Future): Futures,用于异步完成的回调。
  2. Service: 控制事件的启动和关闭,为你管理复杂的状态逻辑。
    六. Strings: 一个非常非常有用的字符串工具类: 提供 splitting,joining, padding 等操作。
    七. Primitives: 扩展 JDK 中未提供的对原生类型(如int、char等)的操作, 包括某些类型的无符号的变量。
    八. Ranges: Guava 一个强大的 API,提供 Comparable 类型的范围处理, 包括连续和离散的情况。
    九. I/O: 简化 I/O 操作, 特别是对 I/O 流和文件的操作, for Java 5 and 6.
    十. Hashing: 提供比 Object.hashCode() 更复杂的 hash 方法, 提供 Bloom filters.
    十一. EventBus: 基于发布-订阅模式的组件通信,但是不需要明确地注册在委托对象中。
    十二. Math: 优化的 math 工具类,经过完整测试。
    十三. Reflection: Guava 的 Java 反射机制工具类。

Guava开发入门

  • 源码仓库:https://github.com/google/guava
  • 中文文档:https://wizardforcel.gitbooks.io/guava-tutorial/content/1.html
  • 开发搭建:https://github.com/google/guava/wiki/UseGuavaInYourBuild

Maven依赖

<dependency>
  <groupId>com.google.guavagroupId>
  <artifactId>guavaartifactId>
  <version>31.1-jreversion>
  
  <version>31.1-androidversion>
dependency>

集合使用技巧

接下来我们主要对比原生和Guava进行操作集合的效果,从而体现出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>>>();
guava的写法
简化集合的创建
LinkedList的创建操作

我们演示一下在日常的开发过程中如何进行创建LinkedList的方式。

List<Person> personList= Lists.newLinkedList();
HashSet的创建操作

我们演示一下在日常的开发过程中如何进行创建 HashSet的方式。

Set<Person> personSet= Sets.newHashSet();
HashMap的创建操作

我们演示一下在日常的开发过程中如何进行创建 HashMap的方式。

Map<String,Person> personMap= Maps.newHashMap();
Array数据的创建操作

我们演示一下在日常的开发过程中如何进行创建Array的方式。

Integer[] intArrays= ObjectArrays.newArray(Integer.class,10);
复杂集合+泛型话处理

我们演示一下在日常的开发过程中如何进行创建复杂集合泛型的方式。

Map<String, Map<String, String>> map = Maps.newHashMap();
List<List<Map<String, String>>> list = Lists.newArrayList();
集合初始化

初始化对应的初始元素信息方案案例:

Set集合的原生创建模式
Set<String> set = new HashSet<String>();
set.add("one");
set.add("two");
set.add("three");
Set集合的Guava创建模式

初始化对应的初始元素信息方案案例:

Set<String> set = Sets.newHashSet("one","two","three");
List集合的Guava创建模式

初始化对应的初始元素信息方案案例:

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

简化泛型对象集合的初始化

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));

集合不变性

很大一部分是google集合提供了不变性,google的不变被确保真正不可改变,而不可修改实际上还是可以修改数据。

如下所示:

  • 数据不可改变
  • 线程安全
  • 不需要同步逻辑
  • 可以被自由的共享
  • 容易设计和实现
  • 内存和时间高效
  • 不变对比不可修改
创建不可变的集合
实用原生的方式进行建立Set集合
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]
实用Guava的方式进行建立Set集合

实用Guava创建一个不可变的Set集合。

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

使用Guava拷贝一个集合,实用的是copyOf方法。

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

使用Builder方法,进行构建Set集合信息。

ImmutableSet<Integer> numbers2 = ImmutableSet.<Integer>builder().addAll(numbers).add(60) .add(70).add(80).build();
特殊的集合类型

Guava API 提供了有用的新的集合类型,协同已经存在的java集合工作的很好。主要集中于MultiMap, MultiSet, Table, BiMap, ClassToInstanceMap。

MultiMap

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

实用案例

创建对应的ArrayListMultimap集合对象

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);
}
计算Multiset的对应的元素数量(去重)
System.out.println(multiSet.count(30)); // 2
计算Multiset的对应的元素数量(不去重)
System.out.println( multiSet.size()); //4
Table

相当于有两个key的map,可以等价于:Map> doubleMap;

创建table对象

采用工厂方法建立Table对象信息集合,如下所示。

Table<Integer,Integer,Person> personTable=HashBasedTable.create();

上面我们采用的是HashMap为基础的Table数据模型。

设置数据案例
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));
}
得到行集合Map数据
Map<Integer,Person> rowMap= personTable.row(0);
int maxAge= Collections.max(rowMap.keySet());
BiMap

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

创建双向map
BiMap<Integer,String> biMap = HashBiMap.create();
测试双向取数据
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 putInstance(Class, T),消除了强制类型转换。该类有一个简单类型的参数,通常称为B,代表了map控制的上层绑定,例如:

ClassToInstanceMap<Number> numberDefaults = MutableClassToInstanceMap.create();
numberDefaults.putInstance(Integer.class, Integer.valueOf(0));

从技术上来说,ClassToInstanceMap 实现了Map, B>,或者说,这是一个从B的子类到B对象的映射,这可能使得ClassToInstanceMap的泛型轻度混乱,但是只要记住B总是Map的上层绑定类型,通常来说B只是一个对象。
guava提供了有用的实现, MutableClassToInstanceMap 和 ImmutableClassToInstanceMap.

重点:像其他的Map,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);
}

使用谓词进行数据筛选
谓词(Predicate)是用来筛选集合

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

案例-筛选出集合中的女人

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>() {
		@Override
		public boolean apply( Person input) {
				return input.getSex()==0;
		}
	}));
}

Optional<ImmutableMultiset<Person>> optional=Optional.fromNullable(testPredict());
if(optional.isPresent()){
	for(Person p:optional.get()){
		System.out.println("女人:"+p);
	}
}

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

集合的功能和转换

主要将转换一个集合为另外一个集合;

实例如下:

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>() {
		@Override
		public String apply( Person input) {
			return input.getName();
		}
	}));
}

Optional<ImmutableMultiset<String>> optional=Optional.fromNullable(testTransform());
if(optional.isPresent()){
	for(String p:optional.get()){
		System.out.println("名字:"+p);
	}
}

排序

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

使用实例如下
初始化数据元素
Lists.newArrayList(30, 20, 60, 80, 10);
//10,20,30,60,80
拷贝且进行自然排序
Ordering.natural().sortedCopy(Lists.newArrayList()); 
//10,20,30,60,80
倒序且进行自然排序
//80,60,30,20,10
Ordering.natural().reverse().sortedCopy(numbers); 
计算最大值或最小值
Ordering.natural().min(numbers); //10
Ordering.natural().max(numbers); //80
插入一个空元素
// 队尾插入空元素
Ordering.natural().nullsLast().sortedCopy(numbers); //10, 20,30,60,80,null
// 队头插入空元素
Ordering.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>() {
		@Override
		public int compare( Person left, Person right) {
			return right.getAge() - left.getAge();
		}
	};
 for(Person p: byAge.immutableSortedCopy(personList)){
		System.out.println(p);
 }
}

你可能感兴趣的:(深入浅出Java原理及实战,java,guava,学习)