Java9都发布了,现在讲java8有点落伍了,不过我觉得java8相对来说是Java的一个大的分水岭。
Java8有许多好用的新特性,如Lambda,接口方法默认实现,Stream等,但这些都不是本章的重点。本章的重点是两个工具类:Optional和StringJoiner。
1. Optional
- 1.1 简介
- Optional类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
- Optional是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
- Optional 类的引入很好的解决空指针异常。
- 1.2 API
static <T> Optional<T> empty()
- 返回空的 Optional 实例
boolean equals(Object obj)
- 判断其他对象是否等于 Optional
Optional<T> filter(Predicate<? super <T> predicate)
- 如果值存在,并且这个值匹配给定的 predicate,返回一个Optional用以描述这个值,否则返回一个空的Optional
<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
- 如果值存在,返回基于Optional包含的映射方法的值,否则返回一个空的Optional
T get()
- 如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException
int hashCode()
- 返回存在值的哈希码,如果值不存在返回 0
void ifPresent(Consumer<? super T> consumer)
- 如果值存在则使用该值调用consumer,否则不做任何事情
boolean isPresent()
- 如果值存在则方法会返回true,否则返回 false
<U>Optional<U> map(Function<? super T, ? extends U> mapper)
- 如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的Optional作为map方法返回值,否则返回空Optional
static <T> Optional<T> of(T value)
- 返回一个指定非null值的Optional
static <T> Optional<T> ofNullable(T value)
- 如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional
T orElse(T other)
- 如果存在该值,返回值, 否则返回 other
T orElseGet(Supplier<? extends T> other)
- 如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果
<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
- 如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常
String toString()
- 返回一个Optional的非空字符串,用来调试
1.3 使用
public static void main(String[] args) {
// Optional.ofNullable - 允许传递为 null 参数
Optional<Integer> num1 = Optional.ofNullable(null);
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> num2 = Optional.of(new Integer(10));
System.out.println(sum(num1, num2));
}
private static int sum(Optional<Integer> num1, Optional<Integer> num2) {
System.out.println("num1值存在: " + num1);
System.out.println("num2值存在: " + num2);
// Optional.orElse - 如果值存在,返回它,否则返回默认值
Integer integer1 = num1.orElse(0);
// Optional.get - 获取值,值需要存在
Integer integer2 = num2.get();
return integer1 + integer2;
}
执行输出:
num1值存在: Optional.empty
num2值存在: Optional[10]
10
- 1.4 实现原理
先来看看变量与静态工厂的定义:
// 默认的空Optional对象
private static final Optional<?> EMPTY = new Optional<>();
// 实际存储的值
private final T value;
// 私有构造器,获取Optional对象只能通过静态工厂方法
private Optional() {
this.value = null;
}
// 静态工厂方法,获取空Optional对象
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
// 私有构造器
private Optional(T value) {
// value不能为空,为空会抛出异常
this.value = Objects.requireNonNull(value);
}
// 静态工厂方法,通过value获取Optional对象,value不能为空
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
// 静态工厂方法,通过value获取Optional对象,允许value为空
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
再来看看Optional的成员方法:
(1) public T get()
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
- 如果在这个Optional中包含这个值,返回值,否则抛出异常:NoSuchElementException。
(2) public boolean isPresent()
public boolean isPresent() {
return value != null;
}
- 如果值存在则方法会返回true,否则返回 false。
(3) public boolean isPresent()
public boolean isPresent() {
return value != null;
}
- 如果值存在则方法会返回true,否则返回 false。
(4) public T orElse(T other)
public T orElse(T other) {
return value != null ? value : other;
}
- 如果存在该值,返回值, 否则返回 other
其他的我就不再分析了,Optional的实现原理非常简单,同时也充分利用了Java8的新特性,如:Function,Predicate,Consumer,使用起来也非常简单,可以很好的解决程序员空指针的头疼问题。
2. StringJoiner
- 2.1 简介
StringJoiner用于构造由分隔符分隔的字符序列,并可选择性地从提供的前缀开始和以提供的后缀结尾,省的开发人员再次通过StringBuffer或者StingBuilder拼接。
- 2.2 使用
StringJoiner sj = new StringJoiner(":", "[", "]");
sj.add("Kuang").add("Zhong").add("Wen");
System.out.println(sj.toString());
执行输出: [Kuang:Zhong:Wen]
- 2.3 实现原理
全局变量和构造器:
private final String prefix;
private final String delimiter;
private final String suffix;
private StringBuilder value;
private String emptyValue;
public StringJoiner(CharSequence delimiter) {
this(delimiter, "", "");
}
public StringJoiner(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix) {
Objects.requireNonNull(prefix, "The prefix must not be null");
Objects.requireNonNull(delimiter, "The delimiter must not be null");
Objects.requireNonNull(suffix, "The suffix must not be null");
this.prefix = prefix.toString();
this.delimiter = delimiter.toString();
this.suffix = suffix.toString();
this.emptyValue = this.prefix + this.suffix;
}
定义了prefix(前缀),delimiter(分割符),suffix(后缀),value是存放结果的StringBuilder对象,emptyValue为空结果。
构造器就是传入前缀,分割符和后缀,然后给emptyValue设置默认值(前缀+后缀)。
我觉得emptyValue用String定义不合理,应该用StringBuilder,毕竟StringJoiner除了拼接方便,也要考虑周全String的性能问题。
成员方法:
(1) public StringJoiner setEmptyValue(CharSequence emptyValue)
public StringJoiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue = Objects.requireNonNull(emptyValue,
"The empty value must not be null").toString();
return this;
}
- 设置空值,不能为null,为null将抛出异常。
(2) public StringJoiner add(CharSequence newElement)
public StringJoiner add(CharSequence newElement) {
prepareBuilder().append(newElement);
return this;
}
private StringBuilder prepareBuilder() {
if (value != null) {
value.append(delimiter);
} else {
value = new StringBuilder().append(prefix);
}
return value;
}
- 拼接字符,可以看到,在拼接字符前先追加分割符。
(3) public StringJoiner merge(StringJoiner other)
public StringJoiner merge(StringJoiner other) {
Objects.requireNonNull(other);
if (other.value != null) {
StringBuilder builder = prepareBuilder();
builder.append(other.value, other.prefix.length(), length);
}
return this;
}
- 合并另一个StringJoiner对象,去掉other的前缀,然后将other的值作为单个字符串追加到当前StringJoiner中,使用的也是StringBuilder。
StringJoiner sj = new StringJoiner(":", "[", "]");
sj.add("Kuang").add("Zhong").add("Wen");
System.out.println(sj.toString());
StringJoiner sj1 = new StringJoiner(",", "{", "}");
sj1.add("zhao").add("xue");
System.out.println(sj1.toString());
System.out.println("merge = " + sj.merge(sj1).toString());
执行输出:
[Kuang:Zhong:Wen]
{zhao,xue}
merge = [Kuang:Zhong:Wen:zhao,xue]
(4) public String toString()
public String toString() {
if (value == null) {
return emptyValue;
} else {
if (suffix.equals("")) {
return value.toString();
} else {
int initialLength = value.length();
String result = value.append(suffix).toString();
value.setLength(initialLength);
return result;
}
}
}
- 如过没有调用过add或者merge方法,value则为null,此时toString将返回空值,否则调用stringBuilder拼接后缀然后返回它的内容。注意,因为stringBuilder.append()可能会对stringBuilder扩容(默认容量16),上面代码中有句setLength,是为了拼接完后缀后,收缩stringBuilder的容量,因为后缀只有在toString时才有用。
(5) public int length()
public int length() {
return (value != null ? value.length() + suffix.length() :
emptyValue.length());
}
- 获取value的长度,如果value不为空,则返回value的长度 + 前缀的长度,为空的话则返回空value的长度。
整体来说,这篇文章比较简单,因为这周轮到单休,团队的事很多,很辛苦,所以我想让自己的大脑休息会。
下一章将介绍Java反射,并且涵盖反射大部分的面试题,周末快乐~