实用小技巧-Optianal,Lambda,Arrays,Objects,ObjectMapper,Jackson,Stream

151 阅读6分钟

Optianal:

主要解决的问题是臭名昭著的空指针异常(NullPointerException) Optional 是 Java 实现函数式编程的强劲一步,并且帮助在范式中实现。可以使得代码更加的简洁高效。

我们从一个简单的用例开始。在 Java 8 之前,任何访问对象方法或属性的调用都可能导致 NullPointerException

String provinceName = users.getAddress().getProvince().getName();

在这个小示例中,如果我们需要确保不触发异常,就得在访问每一个值之前对其进行明确地检查:

if (users!=null){
    Address address = users.getAddress();
    if (address!=null){
        Province province = address.getProvince();
        if (province!=null){
            String provinceName = province.getName();
        }
    }
}

这很容易就变得冗长,难以维护。

接下来,进入Optional的学习。 Optional是一个没有子类的工具类,它避免的null值出现空指针异常。
【1】empty():
1):创建一个value值为null的Optional对象。
2): 示例:

Optional<Object> objectOptional = Optional.empty();
System.out.println(objectOptional.isPresent());
System.out.println(objectOptional.isEmpty());

image.png

【2】of(T value):
1):value必须是非null值,返回一个Optional对象;

public static <T> Optional<T> of(T value) {
    return new Optional(value);
}

2):value如果为空:会报异常(NullPointerException)

Optional name = Optional.of(null);
System.out.println(name);

image.png 4):

Optional name = Optional.of("smile");
System.out.println(name);

image.png
【3】:ofNullable(T value):
1):如果value为null,它会调用empty方法,如果不为null则调用of方法。
2):

Optional<Object> empty = Optional.empty();
System.out.println("empty()" +" : "+ empty);

Optional<Object> ofNullable = Optional.ofNullable(null);
System.out.println("ofNullable" +" : "+ ofNullable);

Optional<Object> ofNullable_non = Optional.ofNullable("non");
System.out.println("ofNullable_non" +" : "+ ofNullable_non);

image.png
【4】:isPresent( );如果这个对象的值不为null返回true,否则返回false。
【5】get():如果这个值存在,则返回这个值,如果这个值为null,则抛出异常;
1):

Optional<String> isPresentMethod = Optional.ofNullable("name");
if (isPresentMethod.isPresent()){
    String name = isPresentMethod.get();
    System.out.println(name);
}else {
    System.out.println("name为空");
}

Optional<String> isPresentMethod_null = Optional.ofNullable(null);
if (isPresentMethod_null.isPresent()){
    String name = isPresentMethod_null.get();
}else {
    System.out.println("name为空");
}

2)

image.png
3): 当传入的value为空时:使用get方法获取value值时,会抛出异常。

Optional<Object> objectOptional = Optional.ofNullable(null);
System.out.println(objectOptional.get());

image.png 4):isPresent():还能接收consumer函数式接口,将自己的非空的逻辑写进去。Optioanal该方法更加简洁;

Optional<String> value = Optional.ofNullable("name");
String name = value.get();

value.ifPresent((s)->{
    System.out.println(name);
});

【6】ifPresentOrElse() java 9里新增了 ifPresentOrElse(),当 Optional 里的值不为空则执行第一个参数里的代码,为空则执行第二个参数的代码,相当于 if-else :

        Student student = new Student("王五", 80);
        Optional<Student> optional = Optional.ofNullable(student);
        optional.ifPresentOrElse( value -> System.out.println("student不为空,姓名:"+value.getName()), () -> System.out.println("student为空") );

可以发现当调用get方法获取Value值时,如果value为null,则会抛出NoSuchElementException异常。
为了避免这种情况,可以使用Optianal提供另一个方法 orElse();

【6】orElse() :接收一个参数,如果存在,返回这个值本身,否则返回默认参数。 如果Optional实例有值则将其返回,否则返回orElse方法传入的默认参数。

//如果参数为null,那么name字符串则赋值为空字符串,。
Optional<String> optionalS = Optional.ofNullable(null);
String name = optionalS.orElse("空字符串");
System.out.println(name);

Optional<String> optional2 = Optional.ofNullable("不为空字符串");
String name2 = optional2.orElse("空字符串");
System.out.println(name2);

结果:

image.png

【7】:orElseGet():接收一个Supplier,如果存在,返回这个值本身,否则返回Supplier对象。orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值。

Optional<String> optionalS = Optional.ofNullable(null);

Optional<String> optionalS = Optional.ofNullable(null);
System.out.println(optionalS.orElseGet(new Supplier<String>() {
    @Override
    public String get() {
        return "Default Value";
    }
})); //Default Value

Optional<String> optionalS1 = Optional.ofNullable("LeoLi");
System.out.println(optionalS1.orElseGet(()-> "Default Value"));  //LeoLi

结果:

image.png

【8】orElseThrow():如果有值则将其返回,否则抛出supplier接口创建的异常。

【9】map(): 接收一个Function, 如果Optioanal为null则抛出异常(所以这里创建Optional对象时建议用Optional.ofNullable()),如果为空值则返回空,如果不为空则返回Function的返回值。

如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional。

Optional<String> optionalS1 = Optional.ofNullable("LeoLi");
Optional<Integer> integer = optionalS1.map(new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
        return s.length();
    }
});
System.out.println(integer.orElseGet(()-> 0));  //5


Optional<String> optionalS2 = Optional.ofNullable(null);
Optional<Integer> integer2 = optionalS2.map(new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
        return s.length();
    }
});
System.out.println(integer2.orElseGet(()-> 0));  //0

【10】flatMap : 如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。flatMap与map(Funtion)方法类似,区别在于flatMap中的mapper返回值必须是Optional。调用结束时,flatMap不会对结果用Optional封装。

【注意】:flatMap方法与map方法类似,区别在于mapping函数的返回值不同。map方法的mapping函数返回值可以是任何类型T,而flatMap方法的mapping函数必须是Optional。

//通过Optional.ofNullable 创建一个 Optianal对象,即optionalS1 泛型为String
Optional<String> optionalS1 = Optional.ofNullable("leoli");
//利用flatMap 函数 进行类型转化,该函数返回值是 Optional 对象
Optional<Object> objectOptional = optionalS1.flatMap(new Function<String, Optional<?>>() {
    @Override
    public Optional<?> apply(String s) {
        return Optional.of(s.toUpperCase());  //转为大写 LEOLI
    }
});
System.out.println(objectOptional.orElseGet(new Supplier<Object>() {
    @Override
    public Object get() {
        return "orElseGet";
    }
}));
System.out.println(objectOptional.orElse("orElse"));

image.png 【11】filter:   该方法通过传入限定条件对Optional实例的值进行过滤。如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional。(对于filter函数我们应该传入实现了Predicate接口的lambda表达式)

Optional<String> name = Optional.of("LeoLi 学习 Optional");
Optional<String> longName = name.filter((value) -> value.length() > 6);
System.out.println(longName.orElse("The name is less than 6 characters"));//输出LeoLi 学习 Optional

Optional<String> name2 = Optional.of("LeoLi");
Optional<String> lessName = name2.filter((value) -> value.length() > 6);
System.out.println(lessName.orElse("The name is less than 6 characters"));//输出The name is less than 6 characters

Optional<String> name3 = Optional.ofNullable("1111111111111111");
Optional<String> Name = name3.filter(new Predicate<String>() {
    @Override
    public boolean test(String s) {
        return s.length()>6;
    }
});
System.out.println(Name.orElse("The name is less than 6 characters"));//输出1111111111111111

注意:

Optioanal 通常作为方法的返回值来使用,它可以有效的规避返回null的结果,如果一个类需要序列化,当Optional作为参数类型或是成员变量类型是有问题的。因为Optional没有实现序列化,所以Optioanl通常不被建议作为参数或常量使用。

示例:


Users users1 = new Users("LeoLi","123",19,null);
Optional<Users> optional = Optional.ofNullable(users1);
Integer integer = optional.map(c -> c.getUsername())
        .map(r -> r.length())
        .orElse(0);
System.out.println(integer); //5

【11】:ifPresent: 当value 不为空时执行accept方法。

Optional<String> optionalS = Optional.ofNullable("null");
optionalS.ifPresent(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});

【12】:ifPresentOrElse: 当value 不为空时执行accept方法。 类似于if-else.

optionalS.ifPresentOrElse(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println("内容不为空时执行");
    }
}, new Runnable() {
    @Override
    public void run() {
        System.out.println("内容为空时执行");
    }
});

//Lambda
optionalS.ifPresentOrElse((c)-> System.out.println("内容不为空时执行"),()-> System.out.println("内容为空时执行"));

三、不适合使用Optional对象的情况

  • 不应该用于类的字段,会增加内存消耗,并使序列化变得复杂;
  • 不应该用于方法参数,使方法的理解和使用变得复杂;
  • 不应用于构造器参数,迫使调用者创建Optional实例,应该通过构造器重载解决;
  • 不应该用于集合的参数,集合已经很好的处理空集合的情况,没必要使用Optional包装集合;
  • 不建议使用get方法,若为null会报错。
public void givenPresentValue_whenCompare_thenOk() {
    User user = new User("john@gmail.com""1234");
    logger.info("Using orElse");
    User result = Optional.ofNullable(user).orElse(createNewUser());
    logger.info("Using orElseGet");
    User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());
}

orElse 和 OrElseGet区别。

这次的输出:

Using orElse
Creating New User
Using orElseGet

这个示例中,两个 Optional 对象都包含非空值,两个方法都会返回对应的非空值。不过,orElse() 方法仍然创建了 User 对象。**与之相反,orElseGet()  方法不创建 *User对象。