A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

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的长度。

---------------------
【转载,仅作分享,侵删】
作者:况众文
原文:https://blog.csdn.net/u014294681/article/details/86368921
版权声明:本文为博主原创文章,转载请附上博文链接!

1 个回复

倒序浏览
今天也要加油鸭
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马