Guava:好用java类库学习
原创基础功能
google guava中定义的String操作
在google guava它为字符串操作提供了极大的便利。判断字符串是空字符串还是null、用指定的字符填充字符串,以及拆分合并字符串、字符串匹配判断等。
- 使用com.google.common.base.Strings类的isNullOrEmpty(input)该方法确定字符串是否为空。
1 //Strings.isNullOrEmpty(input) demo 2 String input = ""; 3 boolean isNullOrEmpty = Strings.isNullOrEmpty(input); 4 System.out.println("input " + (isNullOrEmpty?"is":"is not") + " null or empty.");
- 获取两个具有相同前缀或后缀的字符串。
1 //Strings.commonPrefix(a,b) demo 2 String a = "com.jd.coo.Hello"; 3 String b = "com.jd.coo.Hi"; 4 String ourCommonPrefix = Strings.commonPrefix(a,b); 5 System.out.println("a,b common prefix is " + ourCommonPrefix); 6 7 //Strings.commonSuffix(a,b) demo 8 String c = "com.google.Hello"; 9 String d = "com.jd.Hello"; 10 String ourSuffix = Strings.commonSuffix(c,d); 11 System.out.println("c,d common suffix is " + ourSuffix);
- Strings的padStart和padEnd方法填充字符串。
1 int minLength = 4; 2 String padEndResult = Strings.padEnd("123", minLength, 0); 3 System.out.println("padEndResult is " + padEndResult); 4 5 String padStartResult = Strings.padStart("1", 2, 0); 6 System.out.println("padStartResult is " + padStartResult);
- 使用Splitter类以拆分字符串。
Splitter类可以根据正则表达式轻松拆分字符串,从拆分结果中删除空字符串trim操作,也可以做二次拆分。
让我们从一个基本的拆分示例开始:
Iterable splitResults = Splitter.onPattern("[,,]{1,}")
.trimResults()
.omitEmptyStrings()
.split("hello,word,,世界,级别");
for (String item : splitResults) {
System.out.println(item);
}
Splitter的onPattern该方法作为正则表达式传入,后跟trimResults()该方法表明结果有待完成。trim,omitEmptyStrings()指示忽略空字符串,split该方法执行拆分操作。
split返回的结果是Iterable
Splitter还有一个更强大的功能,做二次拆分,这里的二次拆分意味着拆分两次,例如,我们可以a=b;c=d这样的字符串被拆分为一个字符串。Map<String,String>。
1 String toSplitString = "a=b;c=d,e=f"; 2 Map<String,String> kvs = Splitter.onPattern("[,;]{1,}").withKeyValueSeparator(=).split(toSplitString); 3 for (Map.Entry<String,String> entry : kvs.entrySet()) { 4 System.out.println(String.format("%s=%s", entry.getKey(),entry.getValue())); 5 }
首先使用第二个分割。onPattern做第一次劈叉,然后通过。withKeyValueSeperator()方法进行第二次拆分。
- 如果存在拆分字符串,则必须存在合并字符串,guava为我们提供Joiner类合并字符串
让我们从一个简单的例子开始:
1 String joinResult = Joiner.on(" ").join(new String[]{"hello","world"}); 2 System.out.println(joinResult);
在面部示例中,我们使用Joiner.on(" ").join(xx)合并字符串。它简单有效。
Splitter该方法可以将字符串拆分两次,对应于Joiner你也可以反转操作,威尔。Map<String,String>进行合并。让我们看看下面的示例:
1 Map<String,String> map = new HashMap<String,String>(); 2 map.put("a", "b"); 3 map.put("c", "d"); 4 String mapJoinResult = Joiner.on(",").withKeyValueSeparator("=").join(map); 5 System.out.println(mapJoinResult);
使用withKeyValueSeparator方法可以应用于map进行合并。合并的结果是: a=b,c=d
guava该库还可以对字符串进行大小写转换(CaseFormat枚举),可以对字符串进行模式匹配。使用起来很方便。
guava对象操作封装
在开发中,经常需要比较两个对象是否相等。此时,我们需要考虑要比较的两个对象是否null,然后拨打equals方法比较是否相等,google guava库的com.google.common.base.Objects类提供了一个静态方法。equals我们可以避免对它是否为空做出自己的判断。示例如下:
1 Object a = null; 2 Object b = new Object(); 3 boolean aEqualsB = Objects.equal(a, b);
Objects.equals实现非常完美,代码如下:
1 public static boolean equal(@Nullable Object a, @Nullable Object b) { 2 return a == b || (a != null && a.equals(b)); 3 }
首先判断a b是否是同一个对象,如果是同一对象,则直接返回相等,如果不是同一对象则判断a不为null并且a.equals(b). 这考虑了性能和null空指针的问题。
另外Objects类中还为我们提供方便的重写toString()该方法的机制,让我们举个例子来理解它:
1 import com.google.common.base.Objects; 2 3 public class ObjectsDemo { 4 public static void main(String [] args) { 5 Student jim = new Student(); 6 jim.setId(1); 7 jim.setName("Jim"); 8 jim.setAge(13); 9 System.out.println(jim.toString()); 10 } 11 12 public static class Student { 13 private int id; 14 private String name; 15 private int age; 16 17 public int getId() { 18 return id; 19 } 20 public void setId(int id) { 21 this.id = id; 22 } 23 24 public String getName() { 25 return name; 26 } 27 public void setName(String name) { 28 this.name = name; 29 } 30 31 public int getAge() { 32 return age; 33 } 34 public void setAge(int age) { 35 this.age = age; 36 } 37 38 public String toString() { 39 return Objects.toStringHelper(this.getClass()) 40 .add("id", id) 41 .add("name", name) 42 .add("age", age) 43 .omitNullValues().toString(); 44 } 45 } 46 }
我们定义了Student类,它有三个属性,即id,name,age,我们改写了toString()方法,我们在其中使用Objects.toStringHelper方法,首先指定toString上课,然后轮流上课。add属性名称和属性值,您可以使用。omitNullValues()方法指定忽略并最终调用空值。toString()方法,你可以得到一个好的格式。toString实现了。
上述代码输出的结果是:
Student{id=1, name=Jim, age=13}
这种方式写起来很简单,可读性也很好,所以可以使用。Guava吧。
guava的Preconditions使用
guava的base包装中提供Preconditions类用于方便地检查参数。主要提供以下方法:
- checkArgument 接受一个boolean参数类型和可选errorMsg参数,此方法用于确定参数是否满足某些条件以及满足哪些条件。google guava别在意,当你不符合条件时就扔。IllegalArgumentException异常
- checkState 和checkArgument参数和实现基本相同,从字面上我们也可以知道,该方法用于确定状态是否正确,如果状态不正确,将抛出。IllegalStateException异常
- checkNotNull方法用于确定参数是否null,如果为null则会抛出NullPointerException空指针异常
- checkElementIndex该方法用于确定用户的传入数组下标或list索引位置,是否合法,如果非法,将被抛出。IndexOutOfBoundsException
- checkPositionIndexes方法的作用和checkElementIndex该方法类似,只是该方法的索引范围为。0到size包括size,而上述方法不包括size。
让我们看一个具体的使用示例:
1 import com.google.common.base.Preconditions; 2 3 public class PreconditionsDemo { 4 public static void main(String[] args) { 5 PreconditionsDemo demo = new PreconditionsDemo(); 6 demo.doSomething("Jim", 19, "hello world, hello java"); 7 } 8 9 public void doSomething(String name, int age, String desc) { 10 Preconditions.checkNotNull(name, "name may not be null"); 11 Preconditions.checkArgument(age >= 18 && age < 99, "age must in range (18,99)"); 12 Preconditions.checkArgument(desc !=null && desc.length() < 10, "desc too long, max length is ", 10); 13 14 //do things 15 } 16 }
在上面的示例中doSomething()该方法被调用了三次。Preconditions方法检查参数。
看似Preconditions实现很简单,他的意义在于为我们提供同一的参数校验,并对不同的异常情况抛出合适类型的异常,并对异常信息做格式化。
使用google guava的Optional避免空指针错误的接口
null这将带来许多问题,首先null起初,有无数的程序被植入null的手里,null意思不清楚,检查一下。null在大多数情况下,我们必须这样做,而在很多情况下我们忘记了正确的做法null为了检查,当我们的产品真正投入使用时,出现了异常的空指针,这是一种令人恶心的情况。
鉴于此google的guava图书馆提供Optional接口来使null快速故障,如可能null在对象上制作一层封装Optional静态方法of如果传入的参数为null就抛出NullPointerException异常。
让我们看一个实际的例子:
1 import com.google.common.base.Optional;
2
3 public class OptionalDemo {
4 public static void main(String[] args) {
5 Optional
上面的程序,我们使用Optional.of(null)方法,这一次程序将首次抛出空指针异常,这可以帮助我们尽快找到问题。
让我们看看另一个例子,我们使用。Optional.absent要初始化的方法posibleNull实例,然后我们get这个对象,看看会发生什么。
1 public class OptionalDemo {
2 public static void main(String[] args) {
3 Optional
运行上述程序并发现:Exception in thread "main" java.lang.IllegalStateException: Optional.get() cannot be called on an absent value。
这种使用也会有异常Optional这有什么意义?
使用Optional除了赋予null语义上,增加了可读性,最大的优点是它是一种愚蠢的保护类型。 Optional迫使你积极思考没有引用的问题 因为您必须显式地从。Optional获取参考。直接使用null虽然很容易忘记某些情况FindBugs可以帮助查找null相关问题,但我们仍然认为它没有准确定位问题的根源。
与输入参数一样,方法的返回值也可以是null。和其他人一样,你绝对有可能忘记别人是怎么写的。method(a,b)将返回null就像当你意识到method(a,b)还可能忘记输入参数。a可以为null。指定方法的返回类型。Optional,还可以迫使调用方考虑返回的引用丢失的情况。
google guava Throwables帮助您抛出异常并处理它们。
guava类库中的Throwables提供了一些用于异常处理的静态方法,这些方法在功能上分为两类,一类是帮助您抛出异常,另一类是用于帮助您处理异常。
也许你会想:你为什么要帮助我们处理异常情况?我们自己不例外吗?
假设下面的方法是我们要调用的方法。
1 public void doSomething() throws Throwable { 2 //ignore method body 3 } 4 5 public void doSomethingElse() throws Exception { 6 //ignore method body 7 }
这两种方法的签名是一个。throws出了Throwable另外一个throws出了Exception,它们没有定义将抛出什么异常,也就是说,它们可以抛出任何异常。如果我们想调用这样的方法,我们需要对它们的异常进行一些处理。我们需要判断需要抛出何种异常以及需要封装何种异常。RuntimeException。这些东西是Throwables班级帮助我们做事。
假设我们要实现doIt方法,它将被调用。doSomething方法,而doIt定义中只允许抛掷SQLException,我们可以这样做:
1 public void doIt() throws SQLException { 2 try { 3 doSomething(); 4 } catch (Throwable throwable) { 5 Throwables.propagateIfInstanceOf(throwable, SQLException.class); 6 Throwables.propagateIfPossible(throwable); 7 } 8 }
请注意doIt的catch块,下一行代码表示如果异常类型为SQLException,然后引发此异常
Throwables.propagateIfInstanceOf(throwable, SQLException.class);
第二行指示如果异常Error类型,然后抛出此类型,否则将抛出它。RuntimeException,我们知道RuntimeException中不需要throws在中声明。
Throwables.propagateIfPossible(throwable);
Throwables类还为我们提供一些方便的异常处理帮助方法:
- 我们可以通过Throwables.getRooCause(Throwable)获取根异常
- 可以使用getCausalChain方法获取异常列表。
- 可以通过getStackTraceAsString获取异常堆栈的字符串。
集合增强
guava不可变集合
不可变集合的含义
不可变对象具有许多优点,包括:
- 当对象被不受信任的库调用时,不可变形的形式是安全的;
- 当多个线程调用不可变对象时,不存在竞争条件问题。
- 不变集不需要考虑更改,因此节省了时间和空间。所有不可变集合都比它们的变量形式具有更好的内存利用率(分析和测试细节);
- 不可变对象可以安全地用作常量,因为它们是固定的。
创建对象的不可变副本是一种很好的防御编程技术。Guava为所有JDK标准集类型和Guava新的集合类型都提供了易于使用的不可变版本。
JDK也提供了Collections.unmodifiableXXX该方法将集合包装为不可变形,但我们认为它不够好:
- 沉重而笨重:在所有想要制作防御性副本的场景中都不太舒服;
- 不安全:为了确保没有人通过引用修改原始集合,返回的集合实际上是不可变的;
- 效率低下:打包的集合仍然保留了变量集合的开销,例如并发修改检查、哈希列表的额外空间等等。
如果您不需要修改集合,或者不希望集合保持不变,最好将其复制到不可变的集合中。
重要提示: 所有Guava不接受不可变集合的实现null价值我们对Google对内部代码库进行了详细研究,发现只有5%该案例需要在集合中被允许。null元素,剩余95%所有场景都会遇到null该值很快失效。如果您需要在不可变集合中使用。null,请使用JDK中的Collections.unmodifiableXXX方法有关更多详细建议,请参阅 “使用和避免null” 。
如何使用guava不可变集合
1. 如何创建不可变集合。
第一种方法使用builder创建:
1 public class ImmutableDemo {
2 public static void main(String[] args) {
3 Set
第二种方法使用of静态方法创建:
ImmutableSet.of("red","green","black","white","grey");
第三种方法使用copyOf静态方法创建:
ImmutableSet.copyOf(new String[]{"red","green","black","white","grey"});
2. 使用asList()获取不可变集list视图
asList方法是在ImmutableCollection中定义,而所有不可变集合都会从ImmutableCollection继承,所以所有不可变集合都会有asList()方法返回当前不可变集合。list视图,此视图也是不变的。
3. 使用不可变集合
使用不可变集合和普通集合一样,只是不能使用他们的add,remove以及其他方法来修改集合。
guava集合之Multiset
Multiset看起来是Set,但本质上它不是Set,它不继承Set接口,它继承Collection
它本质上是一个Set添加元素计数器。
1 import com.google.common.base.Splitter;
2 import com.google.common.collect.HashMultiset;
3 import com.google.common.collect.Multiset;
4
5 public class MultisetDemo {
6 public static void main(String[] args) {
7 Multiset multiset = HashMultiset.create();
8 String sentences = "this is a story, there is a good girl in the story.";
9 Iterable
在上面的示例中,我们将一段文本逐个拆分为单词,然后依次放置。multiset在中,请注意本文中有多个重复单词,然后我们传递for循环遍历multiset并输出它们的计数。输出如下:
story:2 is:2 girl:1 there:1 a:2 good:1 the:1 in:1 this:1
显然,计数不是问题,Multiset还提供了add和remove重载方法的,可以在add或这remove同时指定计数的值。
常用实现 Multiset 接口的类包括:
- HashMultiset: 元素存储在 HashMap
- LinkedHashMultiset: 元素存储在 LinkedHashMap也就是说,元素的排列顺序取决于它们首先放置的顺序。
- TreeMultiset:
元素排序并存储在
TreeMap - EnumMultiset: 元素必须为 enum 类型
- ImmutableMultiset: 不可修改 Mutiset
看到这里你可能已经找到了 Guava Collections 都是以 create 或是 of 这样的静态方法构造对象。这是因为这些集合类中的大多数都有多个参数的私有构造函数,并且由于参数的数量太多,客户端代码程序员不方便使用它们。通过这种方式,您可以返回原始类型的子类型对象。此外,这种方法对于创建范例对象更为简洁。
google guava的BiMap:双向Map
我们知道Map是键-值对映射,这是键到值的映射,并且BiMap首先,它也是一种Map让他与众不同的是,他同时提供了键到值的映射和值到键的映射,因此它是双向的。Map.
想象这样一个场景,例如,我们需要在一周的时间里用中文和英文表示地图。Monday对应的中文意思是周一,对应的英文意思是周一Monday。这是一个极好的用途。BiMap的场景。
1 mport com.google.common.collect.BiMap; 2 import com.google.common.collect.HashBiMap; 3 4 public class BiMapDemo { 5 public static void main(String[] args) { 6 BiMap<String,String> weekNameMap = HashBiMap.create(); 7 weekNameMap.put("星期一","Monday"); 8 weekNameMap.put("星期二","Tuesday"); 9 weekNameMap.put("星期三","Wednesday"); 10 weekNameMap.put("星期四","Thursday"); 11 weekNameMap.put("星期五","Friday"); 12 weekNameMap.put("星期六","Saturday"); 13 weekNameMap.put("星期日","Sunday"); 14 15 System.out.println("星期天的英文名称是" + weekNameMap.get("星期日")); 16 System.out.println("Sunday的中文是" + weekNameMap.inverse().get("Sunday")); 17 } 18 }
BiMap值键对的Map可以通过inverse()获得方法。
BiMap 常见的实现有:
- HashBiMap: key 集合与 value 集合都有 HashMap 实现
- EnumBiMap: key 与 value 都必须是 enum 类型
- ImmutableBiMap: 不可修改 BiMap
google guava的Multimaps:一键多值Map
有时我们需要这样的数据类型。Map<String,Collection
Multimap的实现
Multimap提供了一个丰富的实现,因此您可以使用它来替换程序。Map<K, Collection
实现
Key实现
Value实现
ArrayListMultimap
HashMap
ArrayList
HashMultimap
HashMap
HashSet
LinkedListMultimap
LinkedHashMap
LinkedList
LinkedHashMultimap
LinkedHashMap
LinkedHashSet
TreeMultimap
TreeMap
TreeSet
ImmutableListMultimap
ImmutableMap
ImmutableList
ImmutableSetMultimap
ImmutableMap
ImmutableSet
让我们举个例子来理解Multimap如何使用:
1 public class MutliMapTest {
2 public static void main(String... args) {
3 Multimap<String, String> myMultimap = ArrayListMultimap.create();
4
5 // 添加键值对
6 myMultimap.put("Fruits", "Bannana");
7 //给Fruits元素添加另一个元素
8 myMultimap.put("Fruits", "Apple");
9 myMultimap.put("Fruits", "Pear");
10 myMultimap.put("Vegetables", "Carrot");
11
12 // 获得multimap的size
13 int size = myMultimap.size();
14 System.out.println(size); // 4
15
16 // 获得Fruits所有对应值
17 Collection
18 System.out.println(fruits); // [Bannana, Apple, Pear]
19
20 Collection
21 System.out.println(vegetables); // [Carrot]
22
23 //遍历Mutlimap
24 for(String value : myMultimap.values()) {
25 System.out.println(value);
26 }
27
28 // Removing a single value
29 myMultimap.remove("Fruits","Pear");
30 System.out.println(myMultimap.get("Fruits")); // [Bannana, Pear]
31
32 // Remove all values for a key
33 myMultimap.removeAll("Fruits");
34 System.out.println(myMultimap.get("Fruits")); // [] (Empty Collection!)
35 }
36 }
google guava集合之Table
在guava该库还提供了二维表格结构:Table。使用Table可以实现二维矩阵的数据结构,其可以是薄滑动矩阵。
让我们看一个使用示例:
1 public class TableDemo { 2 public static void main(String[] args) { 3 Table<Integer, Integer, String> table = HashBasedTable.create(); 4 for (int row = 0; row < 10; row++) { 5 for (int column = 0; column < 5; column++) { 6 table.put(row, column, "value of cell (" + row + "," + column + ")"); 7 } 8 } 9 for (int row=0;row<table.rowMap().size();row++) { 10 Map<Integer,String> rowData = table.row(row); 11 for (int column =0;column < rowData.size(); column ++) { 12 System.out.println("cell(" + row + "," + column + ") value is:" + rowData.get(column)); 13 } 14 } 15 } 16 }
在上面的示例中,我们传递HashBasedTable已创建行类型。Integer,列类型也是Integer,值为String的Table。然后我们使用put方法向Table添加一些值,然后显示这些值。
Guava设置:使用Iterators简化Iterator操作
Iterators是Guava中对Iterator迭代器操作的帮助类,它提供了许多有用的简化方法。Iterator的操作。
- 确定迭代器中的所有元素是否满足特定条件。 all 方法
1 List
all该方法的第一个参数是Iterator,第二个参数是Predicate
-
通过any确定迭代器中是否存在满足条件的记录,any方法参数和all同样的方法,没有更多具体的例子。
-
get方法获取迭代器中的第一个。x个元素
String secondElement = Iterators.get(list.iterator(), 1);
-
filter方法筛选符合条件的项目
1 Iterator
filter该该方法的第一个参数是源迭代器,第二个参数是。Predicate实施,其apply该方法返回当前元素是否合格。
- find方法返回满足条件的第一个元素。
1 String length5Element = Iterators.find(list.iterator(), new Predicate
- transform方法转换迭代器元素。
1 Iterator
在上面的示例中,我们将字符串转换为其长度,transform该方法输出另一个Iterator.
如果你不迈出一小步,你可以到达数千英里。
版权声明
所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除