欢迎訪问:个人博客
写该系列文章的目的是记录Guava源代码中个人感觉不错且值得借鉴的内容。
一、MoreObjects类
//MoreObjects.ToStringHelper类的toString()方法:对于字符串拼接的写法蛮不错的,此前本人一直用比較挫的方式:无论三七二一,先拼接然后再subString()
@Override public String toString() {
// create a copy to keep it consistent in case value changes
boolean omitNullValuesSnapshot = omitNullValues;
String nextSeparator = "";
StringBuilder builder = new StringBuilder(32).append(className)
.append('{');
for (ValueHolder valueHolder = holderHead.next; valueHolder != null;
valueHolder = valueHolder.next) {
if (!omitNullValuesSnapshot || valueHolder.value != null) {
builder.append(nextSeparator);
nextSeparator = ", ";
if (valueHolder.name != null) {
builder.append(valueHolder.name).append('=');
}
builder.append(valueHolder.value);
}
}
return builder.append('}').toString();
}
private ValueHolder addHolder() {
ValueHolder valueHolder = new ValueHolder();
holderTail = holderTail.next = valueHolder;
return valueHolder;
}
private ToStringHelper addHolder(@Nullable Object value) {
ValueHolder valueHolder = addHolder();
valueHolder.value = value;
return this;
}
private ToStringHelper addHolder(String name, @Nullable Object value) {
ValueHolder valueHolder = addHolder();
valueHolder.value = value;
valueHolder.name = checkNotNull(name);
return this;
}
private static final class ValueHolder {
String name;
Object value;
ValueHolder next;
}
二、Preconditions类
从总体上讲,在使用带有提示消息的相关check方法时须要考虑到性能问题,在一些性能敏感产品中可能。
/*
* All recent hotspots (as of 2009) *really* like to have the natural code
*
* if (guardExpression) {
* throw new BadException(messageExpression);
* }
*
* refactored so that messageExpression is moved to a separate String-returning method.
*
* if (guardExpression) {
* throw new BadException(badMsg(...)); //意思好像是说这样的写法比較影响性能
* }
*
* The alternative natural refactorings into void or Exception-returning methods are much slower.
* This is a big deal - we're talking factors of 2-8 in microbenchmarks, not just 10-20%. (This
* is a hotspot optimizer bug, which should be fixed, but that's a separate, big project).
*
* The coding pattern above is heavily used in java.util, e.g. in ArrayList. There is a
* RangeCheckMicroBenchmark in the JDK that was used to test this.
*
* But the methods in this class want to throw different exceptions, depending on the args, so it
* appears that this pattern is not directly applicable. But we can use the ridiculous, devious
* trick of throwing an exception in the middle of the construction of another exception. Hotspot
* is fine with that.
*/
/**
* Ensures that {@code index} specifies a valid <i>element</i> in an array, list or string of size
* {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive.
*
* @param index a user-supplied index identifying an element of an array, list or string
* @param size the size of that array, list or string
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static int checkElementIndex(int index, int size) {
return checkElementIndex(index, size, "index");
}
// 但作者在以下的方法中为了实现抛出不同类型的异常时,还是使用了上述所描写叙述的不太OK方式,原因我没太明确。
/**
* Ensures that {@code index} specifies a valid <i>element</i> in an array, list or string of size
* {@code size}. An element index may range from zero, inclusive, to {@code size}, exclusive.
*
* @param index a user-supplied index identifying an element of an array, list or string
* @param size the size of that array, list or string
* @param desc the text to use to describe this index in an error message
* @return the value of {@code index}
* @throws IndexOutOfBoundsException if {@code index} is negative or is not less than {@code size}
* @throws IllegalArgumentException if {@code size} is negative
*/
public static int checkElementIndex(
int index, int size, @Nullable String desc) {
// Carefully optimized for execution by hotspot (explanatory comment above)
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException(badElementIndex(index, size, desc));
}
return index;
}
private static String badElementIndex(int index, int size, String desc) {
if (index < 0) {
return format("%s (%s) must not be negative", desc, index);
} else if (size < 0) {
throw new IllegalArgumentException("negative size: " + size);
} else { // index >= size
return format("%s (%s) must be less than size (%s)", desc, index, size);
}
}
当然,另一个format方法(仍然是字符串处理)
/**
* Substitutes each {@code %s} in {@code template} with an argument. These are matched by
* position: the first {@code %s} gets {@code args[0]}, etc. If there are more arguments than
* placeholders, the unmatched arguments will be appended to the end of the formatted message in
* square braces.
*
* @param template a non-null string containing 0 or more {@code %s} placeholders.
* @param args the arguments to be substituted into the message template. Arguments are converted
* to strings using {@link String#valueOf(Object)}. Arguments can be null.
*/
// Note that this is somewhat-improperly used from Verify.java as well.
static String format(String template, @Nullable Object... args) {
template = String.valueOf(template); // null -> "null"
// start substituting the arguments into the '%s' placeholders
StringBuilder builder = new StringBuilder(template.length() + 16 * args.length);
int templateStart = 0;
int i = 0;
while (i < args.length) {
int placeholderStart = template.indexOf("%s", templateStart);
if (placeholderStart == -1) {
break;
}
builder.append(template.substring(templateStart, placeholderStart));
builder.append(args[i++]);
templateStart = placeholderStart + 2;
}
builder.append(template.substring(templateStart));
// if we run out of placeholders, append the extra args in square braces
if (i < args.length) {
builder.append(" [");
builder.append(args[i++]);
while (i < args.length) {
builder.append(", ");
builder.append(args[i++]);
}
builder.append(']');
}
return builder.toString();
}
三、Optional及事实上现类
// Optional及其两个实现类Absent,Present。这三个类用简洁的方式攻克了Java中null值的不确定性问题(其设计哲学值得学习)
// public abstract class Optional<T> implements Serializable
// final class Absent<T> extends Optional<T>
// final class Present<T> extends Optional<T>