学习和使用Guava可以使自己的代码变得更加优雅、简洁。 Guava is the open-sourced version of Google's core Java libraries: the core utilities that Googlers use every day in their code. The Guava utilities have been carefully designed, tested, optimized and used in production at Google. Know and use the libraries, don’t reinvent the wheel.
Objects类
Objects类有几个比较不错的方法,toString、hashCode和equals方法
测试类
@Data
class Person{
private String name;
private int sex;
private int age;
public Person(String name,int sex,int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.omitNullValues()
.add("name", this.getName())
.add("sex", this.getSex())
.add("age", this.getAge())
.toString();
}
}
1.重写toString方法,减少if else判空逻辑
public void testToString() {
Person zhangsan = new Person(null, 1, 28);
String nameStr = MoreObjects.toStringHelper(zhangsan).omitNullValues()
.add("name", zhangsan.getName()).add("sex", zhangsan.getSex())
.add("age", zhangsan.getAge()).toString();
assetTrue(nameStr.equals("Person{sex=1, age=28}"));
}
2.获取hash值,null也可以当成数据项
public void testObjectsHashCode() {
int hashCode1 = Objects.hashCode("sting", "tony", null, "vincent");
int hashCode2 = Objects.hashCode("sting", "tony", "vincent", null);
assertTrue(hashCode1 != hashCode2);
}
3.比较对象,可以为空,减少判空逻辑
public void testObjectsEquals() {
assertTrue(Objects.equal(null, null));
assertTrue(Objects.equal("sting", "sting"));
assertTrue(!Objects.equal(null, "test"));
//assertTrue(Objects.equal("stings", "sting"));
}
排序的实现和改进
Person person1 = new Person("zhangsan", 1, 25);
Person person2 = new Person("lisi", 0, 30);
Person person3 = new Person(null, 1, 25);
Person person4 = null;
List persons = Lists
.newArrayList(person1, person2, person3, person4);
public void testOrderingWithComparisonChain() {
assertTrue(persons.toString().equals("[Person{name=zhangsan, sex=1, age=25}, Person{name=lisi, sex=0, age=30}, Person{sex=1, age=25}, null]"));
System.out.println(persons.toString());
Ordering personOrdering = new Ordering() {
@Override
public int compare(Person p1, Person p2) {
return ComparisonChain.start().compare(p1.getAge(), p2.getAge())
.compare(p1.getName(), p2.getName())
.compare(p1.getSex(), p2.getSex()).result();
}
}.nullsFirst();
Collections.sort(persons, personOrdering);
System.out.println(persons.toString());
//Collections.sort(persons, personOrdering.reverse());
}
public void testOrderingWithComparator() {
System.out.println(persons.toString());
Collections.sort(persons, new Comparator() {
public int compare(Person p1, Person p2) {
return ComparisonChain.start().compare(p1.getAge(), p2.getAge())
.compare(p1.getName(), p2.getName())
.compare(p1.getSex(), p2.getSex()).result();
}
});
System.out.println(persons.toString());
}
CharMatcher
CharMatcher内部的大量实现
BREAKING_WHITESPACE:用于匹配所有的可换行的空白符,如\t,\n,\f,\r
WHITESPACE:用于匹配所有空白字符
ASCII:用于匹配ASCII字符
DIGIT:匹配ASCII数字
JAVA_DIGIT:匹配unicode数字
JAVA_LETTER:匹配字母(含中文)
JAVA_LETTER_OR_DIGIT:匹配字母(含中文)或数字
JAVA_UPPER_CASE:匹配所有大写字符
JAVA_LOWER_CASE:匹配所有小写字符
ANY:用于匹配任意字符
NONE:不匹配所有字符
CharMatcher提供的工厂方法
is(final char match):返回匹配指定字符的Matcher
isNot(final char match):返回不匹配指定字符的Matcher
anyOf(final CharSequence sequence):返回能够匹配sequence中任一字符的Matcher
noneOf(CharSequence sequence):返回能够过滤sequence中任一字符的Matcher
inRange(final char startInclusive, final char endInclusive):返回匹配范围内任意字符的Matcher
forPredicate(final Predicate predicate):返回使用Predicate的apply()判断匹配的Matcher
negate():返回与当前Matcher判断规则相反的Matcher
and(CharMatcher other):返回与other匹配条件组合进行与运算的Matcher
or(CharMatcher other):返回与other匹配条件组合进行或运算的Matcher
对匹配字符的操作
获取的符合规则的Matcher后,有以下常用方法来处理字符串并返回结果
removeFrom(CharSequence sequence):去除匹配到的字符
retainFrom(CharSequence sequence):筛选匹配到的字符
replaceFrom(CharSequence sequence, char replacement):使用指定字符替换匹配到的字符
replaceFrom(CharSequence sequence, CharSequence replacement):使用指定字符替换匹配到的字符
trimFrom(CharSequence sequence):去除首尾匹配到的字符
trimLeadingFrom(CharSequence sequence):去除首部匹配到的字符
trimTrailingFrom(CharSequence sequence):去除尾部匹配到的字符
collapseFrom(CharSequence sequence, char replacement):将匹配到的字符组(多个字符)替换成指定字符
trimAndCollapseFrom(CharSequence sequence, char replacement):去除首尾空格后进行字符替换
判定型方法
matchesAnyOf(CharSequence sequence):如果sequence中任一字符匹配,返回true
matchesAllOf(CharSequence sequence):如果sequence中所有字符都匹配,返回true
matchesNoneOf(CharSequence sequence):如果sequence中所有字符都不匹配,返回true
获取字符索引的方法
indexIn(CharSequence sequence):返回匹配到的第一个字符的索引
indexIn(CharSequence sequence, int start):返回从指定索引开始,匹配到的第一个字符的索引
lastIndexIn(CharSequence sequence):返回匹配到的最后一个字符的索引
countIn(CharSequence sequence):返回匹配到的字符数量
@Test
public void testAnyOf() {
assertTrue(CharMatcher.anyOf("gZ").matchesAnyOf("anything"));
}
@Test
public void testNoneOf() {
assertTrue(CharMatcher.noneOf("xZ").matchesAnyOf("anything"));
}
@Test
public void testMatchAny() {
assertTrue(CharMatcher.ANY.matchesAllOf("anything"));
}
@Test
public void testMatchAllOf() {
assertTrue(CharMatcher.BREAKING_WHITESPACE.matchesAllOf("\r\n\r\n"));
}
@Test
public void testMatchDigits() {
assertTrue(CharMatcher.JAVA_DIGIT.matchesAllOf("1231212"));
}
@Test
public void testRetainFrom() {
assertTrue(CharMatcher.DIGIT.retainFrom("Hello 1234 567").equals("1234567"));
}
@Test
public void testRetailFrom() {
System.out.println(CharMatcher.DIGIT.or(CharMatcher.WHITESPACE).retainFrom("Hel**lo 1234 567"));
assertTrue(CharMatcher.DIGIT.or(CharMatcher.WHITESPACE).retainFrom("Hel**lo 1234 567").equals(" 1234 567"));
}
@Test
public void testCollapseFrom() {
assertTrue(CharMatcher.DIGIT.collapseFrom("Hello 1234 567", 'x').equals("Hello x x"));
}
@Test
public void testReplaceFrom() {
assertTrue(CharMatcher.DIGIT.replaceFrom("Hello 1234 567", 'x').equals("Hello xxxx xxx"));
}
@Test
public void testCountIn() {
assertTrue(CharMatcher.DIGIT.countIn("Hello 1234 567") == 7);
}
@Test
public void testIndexIn() {
assertTrue(CharMatcher.WHITESPACE.indexIn("Hello 1234 567") == 5);
}
@Test
public void testLastIndexIn() {
assertTrue(CharMatcher.WHITESPACE.lastIndexIn("Hello 1234 567") == 10);
}
@Test
public void testRemoveFrom() {
assertTrue(CharMatcher.inRange('3', '6').removeFrom("Hello 1234 567").equals("Hello 12 7"));
}
@Test
public void testInRangeNegate() {
assertTrue(CharMatcher.inRange('3', '6').negate().removeFrom("Hello 1234 567").equals("3456"));
}
b.部分源码
public static CharMatcher anyOf(final CharSequence sequence) {
switch (sequence.length()) {
case 0:
return NONE;
case 1:
return is(sequence.charAt(0));
case 2:
final char match1 = sequence.charAt(0);
final char match2 = sequence.charAt(1);
return new CharMatcher() {
@Override public boolean matches(char c) {
return c == match1 || c == match2;
}
@Override public CharMatcher precomputed() {
return this;
}
};
}
final char[] chars = sequence.toString().toCharArray();
Arrays.sort(chars); // not worth collapsing duplicates
return new CharMatcher() {
@Override public boolean matches(char c) {
return Arrays.binarySearch(chars, c) >= 0;
}
};
}
public static final CharMatcher JAVA_DIGIT = new CharMatcher() {
@Override public boolean matches(char c) {
return Character.isDigit(c);
}
};
public static final CharMatcher JAVA_ISO_CONTROL =
inRange('\u0000', '\u001f').or(inRange('\u007f', '\u009f'));
使用Predicate实现集合过滤功能
//用来过滤符合条件的元素
Person person1 = new Person("zhangsan", 1, 25);
Person person2 = new Person("lisi", 0, 30);
Person person3 = new Person(null, 1, 25);
Person person4 = null;
List persons = Lists
.newArrayList(person1, person2, person3, person4);
public void testPredicte() {
Iterable personsIter = Iterables
.filter(persons, new Predicate() {
public boolean apply(Person input) {
return input != null && input.getAge() > 18;
}
});
System.out.println(personsIter.toString());
Collection filterCollection = Collections2
.filter(persons, new Predicate() {
public boolean apply(Person input) {
return input != null && input.getAge() > 18;
}
});
System.out.println(filterCollection.toString());
}
public void testPredicates() {
List colors = Lists
.newArrayList("red", "blue", "green", "purple", "yellow",
"pink", "", null);
Iterable colorIter = Iterables.filter(colors, Predicates
.and(Predicates.notNull(),
Predicates.containsPattern("pu")));
System.out.println(colorIter.toString());
}
使用Function实现集合转换功能
//将对象集合转换为字符串集合。
public void testFunction() {
Collection filterCollection = Collections2
.transform(persons, new Function() {
public String apply(Person person) {
return null == person ?
"" :
null == person.getName() ?
"" :
person.getName();
}
});
List names = Lists.newArrayList(filterCollection);
System.out.println(names.toString());
}
//过滤空对象和空的对象字段,实现复函数类似的功能
public void testFunctions() {
Function getNameFunction = new Function() {
public String apply(Person person) {
return null == person.getName() ? "" : person.getName();
}
};
Predicate strFilter = Predicates.containsPattern("li");
ImmutableList names = FluentIterable.from(persons)
.filter(Predicates.notNull()).transform(getNameFunction)
.filter(strFilter).toList();
System.out.println(names.toString());
}
像Lists和Maps这类的Collection工具类给我们提供了转换的方法:
topMap = Maps.transformValues(fromMap, function);
toList = Lists.transform(fromList, function);
public void testMapsTransformFromValues() {
Map rmbNameMoneyMapper = ImmutableMap.of("zhangsan", 100, "lisi", 80, "wangwu", 40);
System.out.println(Joiner.on('|').withKeyValueSeparator(':').join(rmbNameMoneyMapper));
Map dolorNameMoneyMapper = Maps.transformValues(rmbNameMoneyMapper, new Function() {
public Double apply(Integer input) {
if(input == null) {
return -1.0;
}
return input / 6.67;
}
});
System.out.println(Joiner.on('|').withKeyValueSeparator(':').join(dolorNameMoneyMapper));
}
结果:
//zhangsan:100|lisi:80|wangwu:40
//zhangsan:14.992503748125937|lisi:11.99400299850075|wangwu:5.997001499250375
public void testListsTransformFrom() {
List rmbMoneyList = Lists.newArrayList(100.9, 80.0, 40.0, 20.9);
System.out.println(Joiner.on(',').skipNulls().join(rmbMoneyList));
List dollarMoneyList = Lists.transform(rmbMoneyList, new Function() {
public Double apply(Double input) {
return input / 6.67;
}
});
System.out.println(Joiner.on(',').skipNulls().join(dollarMoneyList));
}
结果:
//100.9,80.0,40.0,20.9
//15.12743628185907,11.99400299850075,5.997001499250375,3.1334332833583205
//Splitter类测试代码
public void testMapSppliter() {
Map cityDistMapper = Maps.newHashMap();
String beijingDistricts = " 海淀区:北京| 朝阳区:北京| 东城区:北京 ||西城区:北京|昌平区:北京 | |";
cityDistMapper.putAll(Splitter.on("|").omitEmptyStrings().trimResults().withKeyValueSeparator(":").split(beijingDistricts));
System.out.println(cityDistMapper.entrySet().toString());
}
public void testSppliter() {
String colorStrs = "red,blue ,green, purple, yellow ,pink, , ,";
List colors = Lists.newArrayList(Splitter.on(',').omitEmptyStrings().trimResults().split(colorStrs));
System.out.println(colors.toString());
//Splitter部分源码
@CheckReturnValue
public static Splitter on(final String separator) {
checkArgument(separator.length() != 0, "The separator may not be the empty string.");
if (separator.length() == 1) {
return Splitter.on(separator.charAt(0));
}
return new Splitter(
new Strategy() {
@Override
public SplittingIterator iterator(Splitter splitter, CharSequence toSplit) {
return new SplittingIterator(splitter, toSplit) {
@Override
public int separatorStart(int start) {
int separatorLength = separator.length();
positions:
for (int p = start, last = toSplit.length() - separatorLength; p <= last; p++) {
for (int i = 0; i < separatorLength; i++) {
if (toSplit.charAt(i + p) != separator.charAt(i)) {
continue positions;
}
}
return p;
}
return -1;
}
@Override
public int separatorEnd(int separatorPosition) {
return separatorPosition + separator.length();
}
};
}
});
}
@Override
protected String computeNext() {
/*
* The returned string will be from the end of the last match to the
* beginning of the next one. nextStart is the start position of the
* returned substring, while offset is the place to start looking for a
* separator.
*/
int nextStart = offset;
while (offset != -1) {
int start = nextStart;
int end;
int separatorPosition = separatorStart(offset);
if (separatorPosition == -1) {
end = toSplit.length();
offset = -1;
} else {
end = separatorPosition;
offset = separatorEnd(separatorPosition);
}
if (offset == nextStart) {
/*
* This occurs when some pattern has an empty match, even if it
* doesn't match the empty string -- for example, if it requires
* lookahead or the like. The offset must be increased to look for
* separators beyond this point, without changing the start position
* of the next returned substring -- so nextStart stays the same.
*/
offset++;
if (offset >= toSplit.length()) {
offset = -1;
}
continue;
}
while (start < end && trimmer.matches(toSplit.charAt(start))) {
start++;
}
while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {
end--;
}
if (omitEmptyStrings && start == end) {
// Don't include the (unused) separator in next split string.
nextStart = offset;
continue;
}
if (limit == 1) {
// The limit has been reached, return the rest of the string as the
// final item. This is tested after empty string removal so that
// empty strings do not count towards the limit.
end = toSplit.length();
offset = -1;
// Since we may have changed the end, we need to trim it again.
while (end > start && trimmer.matches(toSplit.charAt(end - 1))) {
end--;
}
} else {
limit--;
}
return toSplit.subSequence(start, end).toString();
}
return endOfData();
}
Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
For example,Given 1->2->3->3->4->4->5,