SprintBoot系列(十七):开启单元测试及Optional讲解

1、SpringBoot如何开启单元测试

1.1 修改pom.xml文件,引入依赖

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

1.2、在test创建一个类

package com.fcors.fcors;

import org.junit.Test;

public class OptionalTest {

    @Test
    public void testOptional(){
        System.out.println("单元测试");
    }
}

1.3、执行单元测试

JAVA、基础技术、技术与框架SprintBoot系列(十七):开启单元测试及Optional讲解插图

Optional参考地址:https://blog.csdn.net/weixin_45821811/article/details/115656637

2、Optional的使用详解

2.1、Optional介绍

  • Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象
  • Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测
  • Optional 类的引入很好的解决空指针异常

2.2、构建Optional

构建一个Optional对象;方法有:empty( )、of( )、ofNullable( )

        //返回一个描述给定值的Optional ,如果不为null ,则返回一个空的Optional 。
        //参数:值–描述的可能为null值
        //类型参数:<T> –值的类型
        //返回值:一个Optional与如果指定值是非当前值null ,否则一个空Optional
        Optional.ofNullable("");

        //返回一个Optional描述给定的非null值。
        //参数:value –要描述的值,必须为非null
        //类型参数:<T> –值的类型
        //返回值:存在值的Optional
        Optional.of("");

        //返回一个空的Optional实例。 此Optional没有值。
        //类型参数:<T> –不存在的值的类型
        //返回值:一个空的Optional
        //api注意:尽管这样做可能很诱人,但应通过将==与Optional.empty()返回的实例进行比较来避免测试对象是否为空。
        // 不能保证它是一个单例。
        // 而是使用isPresent()
        Optional.empty();

构建测试:

2.2.1、创建一个MyUser的类

package com.fcors.fcors;

import lombok.*;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class MyUser {
    private String name1;
    private String name2;
}

2.2.2、构造Optional

package com.fcors.fcors;

import org.junit.Test;

import java.util.Optional;

public class OptionalTest {

    @Test
    public void testOptional(){
        Optional s1 = Optional.ofNullable(null);

// 构建一个value不可以为null的optional对象,如果of()的入参为null会报空指针异常;
        Optional<MyUser> s2 = Optional.of(new MyUser("阿辉2","123456"));

// 构建一个value可以为null的optional对象;
        Optional<MyUser> s3 = Optional.ofNullable(null);

        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);
/* 输出
 * Optional.empty
 * Optional[MyUser{id='阿辉2', username='123456'}]
 * Optional.empty
 **/
    }
}
JAVA、基础技术、技术与框架SprintBoot系列(十七):开启单元测试及Optional讲解插图1

2.3、获取类

package com.fcors.fcors;

import org.junit.Test;

import java.util.Optional;

public class OptionalTest {

    @Test
    public void testOptional(){
        Optional<MyUser> userInfoEmptyOpt = Optional.empty();
        Optional<MyUser> userInfoOpt = Optional.of(new MyUser("阿飞","123456"));


        // 1、直接获取,注意如果value==null,会报NoSuchElementException异常
        MyUser userInfo1 = userInfoOpt.get();

        // 2、orElse可以传入一个UserInfo类型的对象作为默认值;
        //    当value!=null时,返回value值;
        //    当value==null时,返回默认值作为代替;
        MyUser userInfo2 = userInfoEmptyOpt.orElse(new MyUser("阿飞1","123456"));

        // 3、orElseGet和orElse不同的是orElseGet可以传入一段lambda表达式;
        // 当value!=null时,返回value值;
        // 当value==null时,使用该lambda返回的对象作为默认值;
        MyUser userInfo3 = userInfoEmptyOpt.orElseGet(() -> new MyUser("阿飞2","123456"));

        // 4、orElseThrow可以传入一段lambda表达式,lambda返回一个Exception;
        // 当value!=null时,返回value值;
        // 当value==null时,抛出该异常;
        MyUser userInfo4 = userInfoOpt.orElseThrow(NullPointerException::new);

        System.out.println(userInfo2);
        System.out.println(userInfo3);
        System.out.println(userInfo4);

        // 输出如下:
        // UserInfo(username=阿飞, password=123456)
        // UserInfo(username=阿飞1, password=123456)
        // UserInfo(username=阿飞2, password=123456)
        // UserInfo(username=阿飞, password=123456)

    }
}

2.4、判断类

package com.fcors.fcors;

import org.junit.Test;

import java.util.Optional;

public class OptionalTest {

    @Test
    public void testOptional(){


        Optional<MyUser> myUser1 = Optional.empty();
        Optional<MyUser> myUser2 = Optional.of(new MyUser("阿飞", "123456"));

        // filter传入一个lambda,lambda返回值为boolean;true:不做任何改变,false:返回一个空的optional;
        //因为阿飞2不等于阿飞,所以会返回一个空的optional
        Optional<MyUser> myUser3 = myUser2.filter(user -> "阿飞2".equals(user.getName1()));

        // isPresent就是判断value是不是null;我们在调用get之前,一定要先调用isPresent,因为直接如果value是null,直接调用get会报异常;
        if (myUser1.isPresent()) {
            MyUser value = myUser1.get();
            System.out.println("optional value:" + value);
        } else {
            System.out.println("optional value==null");
        }
        // ifPresent传入一段lambda,当value!=null时,执行里面的逻辑;当当value==null时,啥都不干;
        myUser2.ifPresent(value -> System.out.println("optional value:" + value));
        System.out.println(myUser3);
        // 输入如下:
        //optional value==null
        //optional value:MyUser{id='阿飞', username='123456'}
        //Optional.empty
    }
}

2.5、转换类

package com.fcors.fcors;

import org.junit.Test;

import java.util.Optional;

public class OptionalTest {

    @Test
    public void testOptional(){
        Optional<MyUser> userInfoOpt = Optional.of(new MyUser("阿飞","123456"));

        // 原来value的类型是UserInfo,经过map转换为Optional<String>
        Optional<String> username = userInfoOpt.map(MyUser::getName1);

        // 当map的入参也是一个Optional时,经过map转化后会形成Optional<Optional<String>>这种嵌套结构;但flatMap可以把这种嵌套结构打平;
        Optional<Optional<String>> unFlatMap = userInfoOpt.map(user -> Optional.of(user.getName1()));
        Optional<String> flatMap = userInfoOpt.flatMap(user -> Optional.of(user.getName1()));

        System.out.println(username);
        System.out.println(unFlatMap);
        System.out.println(flatMap);

        // 输出如下:
        // Optional[阿飞]
        // Optional[Optional[阿飞]]
        // Optional[阿飞]

    }
}

2.6 为空处理

  • orElse(T other)
  • orElseGet(Supplier<? extends T> other)
  • orElseThrow(Supplier<? extends X> exceptionSupplier)

2.6.1 orElse

如果Optional中的值不为空,则返回Optional中的值,如果为空,则返回other值

 /**orElse**/
 String value = "2";
 String orElse = Optional.ofNullable(value).orElse("1");  
 System.out.println(orElse);  //2  
         
 String value = null;
 String orElse = Optional.ofNullable(value).orElse("1"); 
 System.out.println(orElse);  //1

2.6.2 orElseGet

如果Optional中存在值,则返回值,否则返回other调用的结果

     /**orElseGet**/
     public static void main(String[] args) {
         /**optional不为空值**/
         String value = "2";
         String orElse = Optional.ofNullable(value).orElseGet(OptionalTest::get);
         System.out.println(orElse);  // 2

         /**optional空值**/
         String value2 = null;
         String orElse2 = Optional.ofNullable(value2).orElseGet(OptionalTest::get);
         System.out.println(orElse2);  // 123
     }
     public static String get(){
         return "123";
     }

2.6.3 orElseThrow

为空时抛出异常

     /**orElseThrow **/
     public static void main(String[] args) {
         String value = null;
         String orElse = Optional.ofNullable(value).orElseThrow(() -> new RuntimeException("不存在值"));
         System.out.println(orElse);
     }

3、实战例子

我们将一个从远程接口获取了一个用户的信息,包含家庭信息,学历信息,个人信息,然后封装成一个VO,再返回前端进行展示。

此处我们运用到知识点Builder和Optional

3.1创建家庭、学历信息、个人信息实体类

3.1.1Family

package com.fcors.fcors.Optional;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Family {
    private String fatherName;
    private String motherName;
}

3.1.2Education

package com.fcors.fcors.Optional;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Education {
    private String education;
    private String schoolName;
    private Date admissionTime;
    private Date graduationTime;
}

3.1.3UserInfo

package com.fcors.fcors.Optional;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserInfo {
    private String name;
    private Integer age;
    private Family family;
    private Education education;
}

3.2创建UserVo

package com.fcors.fcors.Optional;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserVO {
    private String username;
    private Integer userAge;
    private String edu;
    private String school;
    private Date admissionDate;
    private Date graduationDate;
    private String mother;
    private String father;
}

单元测试例子:vo展示

    @Test
    public void OptionDemo1(){
        /*获取UserInfo*/
        UserInfo userInfo = getUser();
        UserVO.UserVOBuilder userVoBuilder = UserVO.builder();
        /**传统if的方式**/
        if(userInfo !=null){
            userVoBuilder.username(userInfo.getName())
                    .userAge(userInfo.getAge());
            if(userInfo.getEducation() != null){
                userVoBuilder.edu(userInfo.getEducation().getEducation())
                        .school(userInfo.getEducation().getSchoolName());
            }
            if(userInfo.getFamily() != null){
                userVoBuilder.father(userInfo.getFamily().getFatherName())
                        .mother(userInfo.getFamily().getMotherName());
            }
        }
        UserVO userVo1 = userVoBuilder.build();
        /**使用optional**/
        UserVO.UserVOBuilder userVoBuilder2 = UserVO.builder();

        Optional.ofNullable(userInfo).ifPresent(userInfoI -> {
            userVoBuilder2.username(userInfoI.getName()).userAge(userInfoI.getAge());

            Optional.ofNullable(userInfoI.getFamily()).ifPresent(family -> {
                userVoBuilder2.father(family.getFatherName()).mother(family.getMotherName());
            });

            Optional.ofNullable(userInfoI.getEducation()).ifPresent(education -> {
                userVoBuilder2.edu(education.getEducation())
                        .school(education.getSchoolName())
                        .admissionDate(education.getAdmissionTime())
                        .graduationDate(education.getGraduationTime());
            });
        });
        UserVO userVo2 = userVoBuilder2.build();
        System.out.println(userVo1);
        System.out.println(userVo2);

    }

    public UserInfo getUser(){
        Family family = Family.builder()
                .fatherName("father")
                .motherName("monther")
                .build();
        Education education = Education.builder()
                .education("本科")
                .schoolName("湖南工业大学")
                .admissionTime(new Date())
                .graduationTime(new Date())
                .build();

        return UserInfo.builder()
                .name("小四哥")
                .age(24)
                .family(family)
                .education(education).build();
    }

demo2:返回值

    @Test
    public void OptionDemo2(){
        /*获取用户的毕业时间*/
        UserInfo userInfo = getUser();
        Date GraduationTime1= null;
        Date GraduationTime2= null;
        if (null != userInfo) {
            if (null != userInfo.getEducation()){
                GraduationTime1 = userInfo.getEducation().getGraduationTime();
            }
        }

        GraduationTime2= Optional.ofNullable(userInfo)
                .map(UserInfo::getEducation)
                .map(Education::getGraduationTime)
                .orElse(null);
        System.out.println(GraduationTime1);
        System.out.println(GraduationTime2);
        
    }