StringUtils

  spring以及springboot项目是经典的web应用框架,在web应用中经常会从前端传来用户输入的数据。可以使用spring提供的工具类:org.springframework.util.StringUtils

下面是判空以及对于一些没有实际意义的字符串的判断

System.out.println(StringUtils.hasText(null));    // false
System.out.println(StringUtils.hasText(""));      // false
System.out.println(StringUtils.hasText(" "));     // false
System.out.println(StringUtils.hasText(" \t"));   // false
System.out.println(StringUtils.hasText(" \t \n"));// false

简而言之使用StringUtils.hasText()方法对字符串变量进行判断可以简化代码

也是比较推荐的方式,比起写一大串!=null 或者 equals好很多,而且这种方式的比较比equals效率高
例如

if( StringUtils.hasText(username) && StringUtils.hasText(password)){

}

StringUtils.hasText(@Nullable String str)的源码如下:

// 这里的isEmpty底层调用的是String的方法,
// 也就是判断底层存储字符串的字符数组length是否==0,
// 扩展一个知识点,java8的字符串底层采用了byte做完字符串的存储,目的是为了节省空间
public static boolean hasText(@Nullable String str) {
    return str != null && !str.isEmpty() && containsText(str);
}
/**
 * 下面的Character是jdk自带的,在java.lang包下
 * 其中的Character.isWhitespace(char ch)方法则是判断: 空格、\t制表符等字符
 */
private static boolean containsText(CharSequence str) {
    int strLen = str.length();

    for(int i = 0; i < strLen; ++i) {
        if ( !Character.isWhitespace(str.charAt(i))) {
            return true;
        }
    }

    return false;
}

Character.isWhitespace(char ch)在内部定义了一些字符,总得来说就是判断ch是否是无实际意义的的字符(Unicode编码)。

也就是先判 null 以及字符串长度是否为0,然后再判断字符串中每一个字符是否都不属于空白字符。

如果有一个字符是符合条件的则直接进入
if ( !Character.isWhitespace(str.charAt(i)))进行return true;

如果方法返回true则说明字符串有非空白字符的字符再内语义:字符串是有意义的字符串
如果返回false则说明字符串要么是null要么就是空白字符组合成的字符串


java8对象判空

一直以来判空的操作都是 obj !=null这样做的,这种方式在功能和语法以及效果上是没有问题的,但是这种程序不利于阅读,最最主要的原因是对象判空太常见了,如果一个方法有4-5个这样需要判空的对象,并且这几个参数可能需要同时进行判断,那么这个 if看起来很不方便。

对于判空java8提供了一个工具类Optional容器,Optional的作用就相当于给对象套了一层,如果想要拿到对象得调用内部的get()方法进行获取。


在Optional的源码中有这样几句话:

在Optional实例上使用标识敏感的操作(包括引用等于( == ),标识哈希码或同步)可能会产生不可预测的结果,应避免使用。

Optional主要用于在明确需要表示“无结果”并且使用null可能导致错误的情况下用作方法返回类型。 类型为Optional变量本身不应为null ; 它应始终指向Optional实例。


Optional源码
Optional源码不多,有很多逻辑是差不多的,总的来说对于一个对象的判空可以这样使用

下面这个传的是一个对象,这种类似的逻辑还有传接口的

Optional.ofNullable(value1).orElse(value2);// 如果value1为空则返回value2

传接口,下面的逻辑可以代替 if(value1 != null)

Optional.ofNullable(value1).ifPresent((v)->{
    // 不为null的逻辑
});

Optional最主要的作用可以进行连需判断,也就相当于可以代替if-else-if这类结构,而传的就是java8的四大类型接口:Consumer、Suppplier、Function、Predicate

因此有很多网上的博客大谈java8的Optional判空,笔者认为,存在即合理。

Optional容器的使用更多场景应该是与stream-api一起使用,Optional可以对于null元素进行包裹,这样避免了stream流操作时因为空指针异常导致stream被迫终止,如果不使用Optional则可能需要对元素try-catch进行异常捕获,这种代码是非常影响阅读的,因此在这种场景中建议使用Optional容器

Optional.ofNullable(value1).orElseGet(() -> {
    return Optional.ofNullable(value2);
});

Optional容器的确可以代替if-else-if,但源码的注释中也提到了同步代码块、引用比较、标识hash等敏感操作不建议使用Optional

package java.util;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;


public final class Optional<T> {

    private final T value;// 存储值的结构

    private static final Optional<?> EMPTY = new Optional<>(null);// 创建空容器常量对象EMPTY
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

    /**
     * 私有构造器,内部其它方法
     */
    private Optional(T value) {
        this.value = value;
    }

    /**
     * 将value存入Optional容器,如果传入的值为null 则会报空指针异常
     * 调用私有构造方法得到Optional实例
     */
    public static <T> Optional<T> of(T value) {
        return new Optional<>(Objects.requireNonNull(value));
    }

    /**
     * 于of作用相同,返回包裹value的Optional容器实例,但不会报空指针异常
     */
    @SuppressWarnings("unchecked")
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? (Optional<T>) EMPTY
                             : new Optional<>(value);
    }

    /**
     * 返回容器中的实例对象,会抛异常,需要注意,值不能为null
     */
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

    /**
     * 判断值是否存在,存在返回true,不存在返回false
     */
    public boolean isPresent() {
        return value != null;
    }

    /**
     * 判断值是否不存在,不存在返回true、存在则返回false
     * @since   11
     */
    public boolean isEmpty() {
        return value == null;
    }

    /**
     * 传入的是一个消费型接口如果值存在则进行其它操作
     */
    public void ifPresent(Consumer<? super T> action) {
        if (value != null) {
            action.accept(value);
        }
    }

    /**
     * Consumer和Runnable接口
     * 如果存在值,则使用该值执行给定的操作,否则执行其它操作
     * @since 9
     */
    public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
        if (value != null) {
            action.accept(value);
        } else {
            emptyAction.run();
        }
    }

    /**
     * 一个Optional描述此的值Optional ,
     * 如果一个值存在并且该值给定的谓词相匹配,否则一个空Optional
     */
    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent()) {
            return this;
        } else {
            return predicate.test(value) ? this : empty();
        }
    }

    /**
     * 一个Optional描述应用映射函数此的值的结果Optional ,
     * 如果一个值存在,否则一个空Optional
     */
    public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent()) {
            return empty();
        } else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }

    /**
     * 如果值存在将它转换为另外一个容器,否则返回一个空容器,泛型T 变成了 泛型U
     */
    public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent()) {
            return empty();
        } else {
            @SuppressWarnings("unchecked")
            Optional<U> r = (Optional<U>) mapper.apply(value);
            return Objects.requireNonNull(r);
        }
    }

    /**
     * 如果值存在则返回当前容器,否则返回Supplier接口产生的一个容器
     * @since 9
     */
    public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
        Objects.requireNonNull(supplier);
        if (isPresent()) {
            return this;
        } else {
            @SuppressWarnings("unchecked")
            Optional<T> r = (Optional<T>) supplier.get();
            return Objects.requireNonNull(r);
        }
    }

    /**
     * 如果存在值则返回stream流,否则返回空流
     * @since 9
     */
    public Stream<T> stream() {
        if (!isPresent()) {
            return Stream.empty();
        } else {
            return Stream.of(value);
        }
    }

    /**
     * 如果存在值则返回原值,否则返回一个自定义的值(传对象)
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }

    /**
     * 如果存在值,则返回该值,否则返回一个自定义的值(传接口)
     */
    public T orElseGet(Supplier<? extends T> supplier) {
        return value != null ? value : supplier.get();
    }

    /**
     * 如果存在值,则返回该值,否则抛出NoSuchElementException
     * @since 10
     */
    public T orElseThrow() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

    /**
     * 如果存在值,则返回该值,否则由提供函数抛出异常
     */
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

    /**
     * 判断两个Optional容器是否相等
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof Optional)) {
            return false;
        }

        Optional<?> other = (Optional<?>) obj;
        return Objects.equals(value, other.value);
    }


    @Override
    public int hashCode() {
        return Objects.hashCode(value);
    }


    @Override
    public String toString() {
        return value != null
            ? String.format("Optional[%s]", value)
            : "Optional.empty";
    }
}