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";
}
}