【Java8新特性】史上最全Optional实战教程,太厉害了!

44 篇文章 5 订阅
订阅专栏

目录

一、前置基础

二、什么是Optional

2.1理论拓展

三、为什么要用Optional

3.1俄罗斯式套娃判空详解

四、Optional基本知识

4.1API的思考

五、工作中如何正确使用Optional

5.1 orElseThrow

5.2 filter

5.3 orElse和orElseGet

5.4 map和flatMap

5.5 项目实战

实战一

实战二

实战三 简化if.else

实战四 解决checkStyle问题

实战五 Optional提升代码的可读性

实战六 大胆重构代码

实战七 舍弃三目运算

六、Optional操作总结

七、Optional错误使用


一、前置基础

Optional类源码大量使用到:
1.四大函数式接口
2.lambda表达式

二、什么是Optional

1.Java 8新增了一个类 - Optional
2.Optional是一个容器,用于放置可能为空的值,它可以合理而优雅的处理 null。
3.Optional的本质,就是内部储存了一个真实的值,在构造的时候,就直接判断其值是否为空
4.java.util.Optional<T>类本质上就是一个容器,该容器的数值可以是空代表一个值不存在,也可以是非空代表一个值存在。
5.Optional类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。

2.1理论拓展

  Monad 是一种用于处理副作用的编程模式,简单来说就是将一些可能产生副作用的操作封装起来,并在特定的作用域内执行,控制其对程序产生的影响。在函数式编程中经常使用 Monad 模式来处理一些副作用,如 IO 操作、异常处理、状态管理等。
Optional 是 Java 中一个非常典型的 Monad 实现,它的主要作用是避免空指针异常并对可能为空的对象进行封装,并提供一系列函数式的操作,如 map()filter()flatMap()等方法,使代码更加健壮、优雅和安全。就像我们平时经常对空值进行判空处理一样,Optional 提供了一种更加优美和方便的方式,避免了深层次的嵌套判空,同时增加了代码的可读性和可维护性。
  对于函数式编程和 Monad 模式来说,这种方式是非常重要的,因为随着程序的规模增大,副作用也会越来越多,这时候避免副作用对程序的影响就变得尤为重要。通过使用 Monad 模式和类似 Optional 这样的容器类型,我们可以更好地控制副作用,使程序更加稳定和可靠。

三、为什么要用Optional

1.要是用来解决程序中常见的 NullPointerException异常问题。但是在实际开发过程中很多人都是在一知半解的使用 Optional,类似 if (userOpt.isPresent()){...}这样的代码随处可见。如果是这样我更愿意看到老老实实的 null 判断,这样强行使用 Optional反而增加了代码的复杂度。
2.这是一个明确的警示,用于提示开发人员此处要注意null值。
3.不显式的判空,当出现俄罗斯式套娃判空时,代码处理上更加优雅。
4.使用 Optional 有时候可以很方便的过滤一些属性,而且它的方法可以通过链式调用,方法间相互组合使用,使我们用少量的代码就能完成复杂的逻辑。
5.防止空指针(NPE)、简化if...else...判断、减少代码圈复杂度
6.Optional 之所以可以解决 NPE 的问题,是因为它明确的告诉我们,不需要对它进行判空。它就好像十字路口的路标,明确地告诉你该往哪走
7.很久很久以前,为了避免 NPE,我们会写很多类似if (obj != null) {}的代码,有时候忘记写,就可能出现 NPE,造成线上故障。在 Java 技术栈中,如果谁的代码出现了 NPE,有极大的可能会被笑话,这个异常被很多人认为是低级错误。Optional的出现,可以让大家更加轻松的避免因为低级错误被嘲讽的概率。
8.第一是改变我们传统判空的方式(其实就是帮我们包装了一层,判空的代码帮我们写了),用函数式编程和申明式编程来进行对基本数据的校验和处理。第二就是声明式的编程方式对阅读代码的人更友好。

3.1俄罗斯式套娃判空详解

  手动进行 if(obj!=null)的判空自然是最全能的,也是最可靠的,但是怕就怕俄罗斯套娃式的 if判空。
举例一种情况:
为了获取:省(Province)→市(Ctiy)→区(District)→街道(Street)→道路名(Name)
作为一个“严谨且良心”的后端开发工程师,如果手动地进行空指针保护,我们难免会这样写:

public String getStreetName( Province province ) {
    if( province != null ) {
        City city = province.getCity();
        if( city != null ) {
            District district = city.getDistrict();
            if( district != null ) {
                Street street = district.getStreet();
                if( street != null ) {
                    return street.getName();
                }
            }
        }
    }
    return "未找到该道路名";
}
为了获取到链条最终端的目的值,直接链式取值必定有问题,因为中间只要某一个环节的对象为 null,则代码一定会炸,并且抛出 NullPointerException异常,然而俄罗斯套娃式的 if判空实在有点心累。
Optional接口本质是个容器,你可以将你可能为 null的变量交由它进行托管,这样我们就不用显式对原变量进行 null值检测,防止出现各种空指针异常。
Optional语法专治上面的俄罗斯套娃式 if 判空,因此上面的代码可以重构如下:

public String getStreetName( Province province ) {
    return Optional.ofNullable( province )
            .map( i -> i.getCity() )
            .map( i -> i.getDistrict() )
            .map( i -> i.getStreet() )
            .map( i -> i.getName() )
            .orElse( "未找到该道路名" );
}

漂亮!嵌套的 if/else判空灰飞烟灭!
解释一下执行过程:
ofNullable(province ) :它以一种智能包装的方式来构造一个 Optional实例, province是否为 null均可以。如果为 null,返回一个单例空 Optional对象;如果非 null,则返回一个 Optional包装对象
map(xxx ):该函数主要做值的转换,如果上一步的值非 null,则调用括号里的具体方法进行值的转化;反之则直接返回上一步中的单例 Optional包装对象
orElse(xxx ):很好理解,在上面某一个步骤的值转换终止时进行调用,给出一个最终的默认值

四、Optional基本知识

Optional类常用方法:

Optional.of(T t) : 创建一个 Optional 实例。

Optional.empty() : 创建一个空的 Optional 实例。

Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例。

isPresent() : 判断是否包含值。

orElse(T t) : 如果调用对象包含值,返回该值,否则返回t。

orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值。

map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()。

flatMap(Function mapper):与 map 类似,要求返回值必须是Optional。

4.1API的思考

1.of(T value)
一个东西存在那么自然有存在的价值。当我们在运行过程中,不想隐藏NullPointerException。
而是要立即报告,这种情况下就用Of函数。但是不得不承认,这样的场景真的很少。我也仅在写junit测试用例中用到过此函数。

2.get()
直观从语义上来看,get() 方法才是最正宗的获取 Optional 对象值的方法,
但很遗憾,该方法是有缺陷的,因为假如 Optional 对象的值为 null,该方法会抛出 NoSuchElementException 异常。这完全与我们使用 Optional 类的初衷相悖。

五、工作中如何正确使用Optional

5.1 orElseThrow

orElseThrow()方法当遇到一个不存在的值的时候,并不返回一个默认值,而是抛出异常。

public void validateRequest(String requestId) {
    Optional.ofNullable(requestId)
            .orElseThrow(() -> new IllegalArgumentException("请求编号不能为空"));
    // 执行后续操作
}
Optional<User> optionalUser = Optional.ofNullable(null);
User user = optionalUser.orElseThrow(() -> new RuntimeException("用户不存在"));

// 传入 null 参数,获取一个 Optional 对象,并使用 orElseThrow 方法
    try {
        Optional optional2 = Optional.ofNullable(null);
        Object object2 = optional2.orElseThrow(() -> {
                    System.out.println("执行逻辑,然后抛出异常");
                    return new RuntimeException("抛出异常");
                }
        );
        System.out.println("输出的值为:" + object2);
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }

5.2 filter

接收一个函数式接口,当符合接口时,则返回一个Optional对象,否则返回一个空的Optional对象。
例如,我们需要过滤出年龄在25岁到35岁之前的人群,那在Java8之前我们需要创建一个如下的方法来检测每个人的年龄范围是否在25岁到35岁之前。

public boolean filterPerson(Peron person){
    boolean isInRange = false;
    if(person != null && person.getAge() >= 25 && person.getAge() <= 35){
        isInRange =  true;
    }
    return isInRange;
}

public boolean filterPersonByOptional(Peron person){
     return Optional.ofNullable(person)
       .map(Peron::getAge)
       .filter(p -> p >= 25)
       .filter(p -> p <= 35)
       .isPresent();
}
使用Optional看上去就清爽多了,这里,map()仅仅是将一个值转换为另一个值,并且这个操作并不会改变原来的值。

     public class OptionalMapFilterDemo {
    public static void main(String[] args) {
        String password = "password";
        Optional<String>  opt = Optional.ofNullable(password);

        Predicate<String> len6 = pwd -> pwd.length() > 6;
        Predicate<String> len10 = pwd -> pwd.length() < 10;
        Predicate<String> eq = pwd -> pwd.equals("password");

        boolean result = opt.map(String::toLowerCase).filter(len6.and(len10 ).and(eq)).isPresent();
        System.out.println(result);
    }
}

5.3 orElse和orElseGet

结论:当optional.isPresent() == false时,orElse()和orElseGet()没有区别;
而当optional.isPresent() == true时,无论你是否需要,orElse始终会调用后续函数。

若方法不是纯计算型的,使用Optional的orElse(T);
若有与数据库交互或者远程调用的,都应该使用orElseGet(Supplier)。
推荐使用orElseGet ,当存在一些复合操作,远程调用,磁盘io等大开销的动作禁止使用orElse。
原因:当value不为空时,orElse仍然会执行。

public class GetValueDemo {
    public static String getDefaultName() {
        System.out.println("Getting Default Name");
        return "binghe";
    }

    public static void main(String[] args) {
/*        String text = null;
        System.out.println("Using orElseGet:");
        String defaultText = Optional.ofNullable(text).orElseGet(GetValueDemo::getDefaultName);
        assertEquals("binghe", defaultText);
        System.out.println("Using orElse:");
        defaultText = Optional.ofNullable(text).orElse(GetValueDemo.getDefaultName());
        assertEquals("binghe", defaultText);*/

        // TODO: 2023/5/13 重点示例
        String name = "binghe001";

        System.out.println("Using orElseGet:");
        String defaultName = Optional.ofNullable(name).orElseGet(GetValueDemo::getDefaultName);
        assertEquals("binghe001", defaultName);

        System.out.println("Using orElse:");
        defaultName = Optional.ofNullable(name).orElse(getDefaultName());
        assertEquals("binghe001", defaultName);
    }  
}    

运行结果如下所示。
Using orElseGet:
Using orElse:
Getting default name...
可以看到,当使用orElseGet()方法时,getDefaultName()方法并不执行,因为Optional中含有值,而使用orElse时则照常执行。所以可以看到,当值存在时,orElse相比于orElseGet,多创建了一个对象。如果创建对象时,存在网络交互,那系统资源的开销就比较大了,这是需要我们注意的一个地方。

5.4 map和flatMap

        String len = null;
        Integer integer = Optional.ofNullable(len)
                .map(s -> s.length())
                .orElse(0);
        System.out.println("integer = " + integer);


        Person person = new Person("evan", 18);
        Optional.ofNullable(person)
                .map(p -> p.getName())
                .orElse("");

        Optional.ofNullable(person)
                .flatMap(p -> Optional.ofNullable(p.getName()))
                .orElse("");

注意:方法getName返回的是一个Optional对象,如果使用map,我们还需要再调用一次get()方法,而使用flatMap()就不需要了。

5.5 项目实战

实战一

public class OptionalExample {
    /**
     * 测试的 main 方法
     */
    public static void main(String[] args) {
        // 创建一个测试的用户集合
        List<User> userList = new ArrayList<>();

        // 创建几个测试用户
        User user1 = new User("abc");
        User user2 = new User("efg");
        User user3 = null;

        // 将用户加入集合
        userList.add(user1);
        userList.add(user2);
        userList.add(user3);

        // 创建用于存储姓名的集合
        List<String> nameList = new ArrayList();
        List<User> nameList03 = new ArrayList();
        List<String> nameList04 = new ArrayList();
        // 循环用户列表获取用户信息,值获取不为空且用户以 a 开头的姓名,
        // 如果不符合条件就设置默认值,最后将符合条件的用户姓名加入姓名集合
/*
        for (User user : userList) {
            nameList.add(Optional.ofNullable(user).map(User::getName).filter(value -> value.startsWith("a")).orElse("未填写"));
        }
*/

        // 输出名字集合中的值
/*        System.out.println("通过 Optional 过滤的集合输出:");
        System.out.println("nameList.size() = " + nameList.size());
        nameList.stream().forEach(System.out::println);*/


/*        Optional.ofNullable(userList)
                .ifPresent(u -> {
                    for (User user : u) {
                        nameList04.add(Optional.ofNullable(user).map(User::getName).filter(f -> f.startsWith("e")).orElse("无名"));
                    }
                });*/

        Optional.ofNullable(userList)
                .ifPresent(u -> {
                   u.forEach(m->{
                       Optional<String> stringOptional = Optional.ofNullable(m).map(User::getName).filter(f -> f.startsWith("a"));
                       stringOptional.ifPresent(nameList04::add);
                   });
                });
        System.out.println("nameList04.size() = " + nameList04.size());
        nameList04.forEach(System.err::println);


        Optional.ofNullable(userList).ifPresent(nameList03::addAll);
        System.out.println("nameList03.size() = " + nameList03.size());
        nameList03.stream().forEach(System.err::println);

    }

}

实战二

以前写法
public String getCity(User user)  throws Exception{
        if(user!=null){
            if(user.getAddress()!=null){
                Address address = user.getAddress();
                if(address.getCity()!=null){
                    return address.getCity();
                }
            }
        }
        throw new Excpetion("取值错误"); 
    }


    public String getCity(User user) throws Exception{
    return Optional.ofNullable(user)
                   .map(u-> u.getAddress())
                   .map(a->a.getCity())
                   .orElseThrow(()->new Exception("取指错误"));
}

实战三 简化if.else

以前写法
public User getUser(User user) throws Exception{
    if(user!=null){
        String name = user.getName();
        if("zhangsan".equals(name)){
            return user;
        }
    }else{
        user = new User();
        user.setName("zhangsan");
        return user;
    }
}

java8写法
public User getUser(User user) {
    return Optional.ofNullable(user)
                   .filter(u->"zhangsan".equals(u.getName()))
                   .orElseGet(()-> {
                        User user1 = new User();
                        user1.setName("zhangsan");
                        return user1;
                   });
}

实战四 解决checkStyle问题


BaseMasterSlaveServersConfig smssc = new BaseMasterSlaveServersConfig();
if (clientName != null) {
    smssc.setClientName(clientName);
}
if (idleConnectionTimeout != null) {
    smssc.setIdleConnectionTimeout(idleConnectionTimeout);
}
if (connectTimeout != null) {
    smssc.setConnectTimeout(connectTimeout);
}
if (timeout != null) {
    smssc.setTimeout(timeout);
}
if (retryAttempts != null) {
    smssc.setRetryAttempts(retryAttempts);
}
if (retryInterval != null) {
    smssc.setRetryInterval(retryInterval);
}
if (reconnectionTimeout != null) {
    smssc.setReconnectionTimeout(reconnectionTimeout);
}
if (password != null) {
    smssc.setPassword(password);
}
if (failedAttempts != null) {
    smssc.setFailedAttempts(failedAttempts);
}
// ...后面还有很多这种判断,一个if就是一个分支,会增长圈复杂度


改造后:
Optional.ofNullable(clientName).ifPresent(smssc::setClientName);
Optional.ofNullable(idleConnectionTimeout).ifPresent(smssc::setIdleConnectionTimeout);
Optional.ofNullable(connectTimeout).ifPresent(smssc::setConnectTimeout);
Optional.ofNullable(timeout).ifPresent(smssc::setTimeout);
Optional.ofNullable(retryAttempts).ifPresent(smssc::setRetryAttempts);
Optional.ofNullable(retryInterval).ifPresent(smssc::setRetryInterval);
Optional.ofNullable(reconnectionTimeout).ifPresent(smssc::setReconnectionTimeout);
// ...缩减为一行,不但减少了圈复杂度,而且减少了行数

实战五 Optional提升代码的可读性

传统操作:

public class ReadExample {
    //    举个栗子:你拿到了用户提交的新密码,你要判断用户的新密码是否符合设置密码的规则,比如长度要超过八位数,然后你要对用户的密码进行加密。
    private static String newPSWD = "12345679";
    public static void main(String[] args) throws Exception {
        // 简单的清理
        newPSWD = ObjectUtil.isEmpty(newPSWD) ? "" : newPSWD.trim();
        // 是否符合密码策略
        if (newPSWD.length() <= 8) throw new Exception("Password rules are not met: \n" + newPSWD);
        // 加密
        //将 MD5 值转换为 16 进制字符串
        try {
            final MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(newPSWD.getBytes(StandardCharsets.UTF_8));
            newPSWD = new BigInteger(1, md5.digest()).toString(16);
        } catch (
                NoSuchAlgorithmException e) {
            System.out.println("Encryption failed");
        }
        System.out.println("We saved a new password for the user: \n" + newPSWD);
    }
}

优化版本:

优化一:
public class BetterReadExample {
    //    举个栗子:你拿到了用户提交的新密码,你要判断用户的新密码是否符合设置密码的规则,比如长度要超过八位数,然后你要对用户的密码进行加密。
    private static String newPSWD = "888888888";
    public static void main(String[] args) throws Exception {

        Function<String, String> md = (o) -> {
            try {
                final MessageDigest md5;
                md5 = MessageDigest.getInstance("MD5");
                md5.update(o.getBytes(StandardCharsets.UTF_8));
                return new BigInteger(1, md5.digest()).toString(16);
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException("Encryption failed");
            }
        };


        String digestpwd;
        digestpwd = Optional.ofNullable(newPSWD)
                            .map(String::trim)
                            .filter(f -> f.length() > 8)
                            .map(md)
                            .orElseThrow(() -> new RuntimeException("Incorrect saving new password"));
        System.err.println("digestpwd = " + digestpwd);

    }
}

优化二:
/**
 *增加可读性
 */
public class BetterReadExample02 {
    //    举个栗子:你拿到了用户提交的新密码,你要判断用户的新密码是否符合设置密码的规则,比如长度要超过八位数,然后你要对用户的密码进行加密。
    private static String newPSWD = "888888888";

    //清除
    private static String clean(String s){
        return s.trim();
    }

    private static boolean filterPw(String s){
        return s.length()>8;
    }

    private static RuntimeException myREx() {
        return new RuntimeException("Incorrect saving new password");
    }

    public static void main(String[] args) throws Exception {
        //项目实战中,把main方法里面的代码再抽出一个独立方法
        Function<String, String> md = (o) -> {
            try {
                final MessageDigest md5;
                md5 = MessageDigest.getInstance("MD5");
                md5.update(o.getBytes(StandardCharsets.UTF_8));
                return new BigInteger(1, md5.digest()).toString(16);
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException("Encryption failed");
            }
        };

        String digestpwd;
        digestpwd = Optional.ofNullable(newPSWD)
                            .map(BetterReadExample02::clean)
                            .filter(BetterReadExample02::filterPw)
                            .map(md)
                            .orElseThrow(BetterReadExample02::myREx);
        System.err.println("digestpwd = " + digestpwd);

    }
}

实战六 大胆重构代码

//1. map 示例
if ( hero != null){
   return "hero : " + hero.getName() + " is fire...";
 } else { 
   return "angela";
 }
 //重构成
 String heroName = hero
 .map(this::printHeroName)
 .orElseGet(this::getDefaultName);

public void printHeroName(Hero dog){
   return  "hero : " + hero.getName() + " is fire...";
}
public void getDefaultName(){
   return "angela";
}

//2. filter示例
Hero hero = fetchHero();
if(hero != null && hero.hasBlueBuff()){
  hero.fire();
}

//重构成
Optional<Hero> optionalHero = fetchHero();
optionalHero
 .filter(Hero::hasBlueBuff)
 .ifPresent(this::fire);

实战七 舍弃三目运算

//第一种判空
if (Objects.notNull(taskNode.getFinishTime())) {
  taskInfoVo.set(taskNode.getFinishTime().getTime());
}
//第二种判空 保留builder模式
TaskInfoVo
.builder()
.finishTime(taskNode.getFinishTime() == null ? null : taskNode.getFinishTime().getTime())
.build()));

//第三种判空
public Result<TaskInfoVo> getTaskInfo(String taskId){
  TaskNode taskNode = taskExecutor.getByTaskId(String taskId);
  //返回任务视图
  TaskInfoVo taskInfoVo = TaskInfoVo
                      .builder()
                      .taskName(taskNode.getName())
                      .finishTime(Optional.ofNullable(taskNode.getFinishTime()).map(date ->date.getTime()).orElse(null))
             .user(taskNode.getUser())
                     .memo(taskNode.getMemo())
                     .build()));;

  return Result.ok(taskInfoVo);
}

六、Optional操作总结

NPE 之所以讨厌,就是只要出现 NPE,我们就能够解决。但是一旦出现,都已经是事后,可能已经出现线上故障。偏偏在 Java 语言中,NPE 又很容易出现。Optional提供了模板方法,有效且高效的避免 NPE。

接下来,我们针对上面的使用,总结一下:
Optional是一个包装类,且不可变,不可序列化
没有公共构造函数,创建需要使用of、ofNullable方法
空Optional是单例,都是引用Optional.EMPTY
想要获取Optional的值,可以使用get、orElse、orElseGet、orElseThrow

另外,还有一些实践上的建议:
使用get方法前,必须使用isPresent检查。但是使用isPresent前,先思考下是否可以使用orElse、orElseGet等方法代替实现。
orElse和orElseGet,优先选择orElseGet,这个是惰性计算
Optional不要作为参数或者类属性,可以作为返回值
尽量将map、filter的函数参数抽出去作为单独方法,这样能够保持链式调用
不要将null赋给Optional 虽然Optional支持null值,但是不要显示的把null 传递给Optional
尽量避免使用Optional.get()
当结果不确定是否为null时,且需要对结果做下一步处理,使用Optional;
在类、集合中尽量不要使用Optional 作为基本元素;
尽量不要在方法参数中传递Optional;
不要使用 Optional 作为Java Bean Setter方法的参数
因为Optional 是不可序列化的,而且降低了可读性。
不要使用Optional作为Java Bean实例域的类型
原因同上。

七、Optional错误使用

1.使用在 POJO 中

public class User {
    private int age;
    private String name;
    private Optional<String> address;
}

这样的写法将会给序列化带来麻烦,Optional本身并没有实现序列化,现有的 JSON 序列化框架也没有对此提供支持的。

2.使用在注入的属性中
这种写法估计用的人会更少,但不排除有脑洞的。

public class CommonService {
    private Optional<UserService> userService;
    public User getUser(String name) {
        return userService.ifPresent(u -> u.findByName(name));
    }
}

首先依赖注入大多在 spring 的框架之下,直接使用 @Autowired很方便。但如果使用以上的写法,如果 userService set 失败了,程序就应该终止并报异常,并不是无声无息,让其看起来什么问题都没有。

3.直接使用 isPresent() 进行 if 检查
这个直接参考上面的例子,用 if判断和 1.8 之前的写法并没有什么区别,反而返回值包了一层 Optional,增加了代码的复杂性,没有带来任何实质的收益。其实 isPresent()一般用于流处理的结尾,用于判断是否符合条件。

list.stream()
    .filer(x -> Objects.equals(x,param))
    .findFirst()
    .isPresent()

4.在方法参数中使用 Optional
我们用一个东西之前得想明白,这东西是为解决什么问题而诞生的。Optional直白一点说就是为了表达可空性,如果方法参数可以为空,为何不重载呢?包括使用构造函数也一样。重载的业务表达更加清晰直观。

//don't write method like this
public void getUser(long uid,Optional<Type> userType);

//use Overload
public void getUser(long uid) {
    getUser(uid,null);
}
public void getUser(long uid,UserType userType) {
    //doing something
}   

5.直接使用 Optional.get
Optional不会帮你做任何的空判断或者异常处理,如果直接在代码中使用 Optional.get()和不做任何空判断一样,十分危险。这种可能会出现在那种所谓的着急上线,着急交付,对 Optional也不是很熟悉,直接就用了。这里多说一句,可能有人会反问了:甲方/业务着急,需求又多,哪有时间给他去做优化啊?因为我在现实工作中遇到过,但这两者并不矛盾,因为代码行数上差别并不大,只要自己平时保持学习,都是信手拈来的东西。

如对您有帮助,欢迎点赞,嘿嘿 !!

Java8】Java8实战Optional
曾经沧海难为水,除却巫山不是云
08-13 572
Java8实战Optional 前言 在前面的几个小节中,我们已经学习了Lambda表达式、Stream以及默认方法,在体会到Java8所带来的极大的便利之后,这小节我们来学习Java8中一个新的功能–OptionalOptional Optional的出现是为了解决null的问题,在Java中,如果一个对象指针没有被初始化,默认就指向null,而这种情况是比较危险的,在使用...
史上最全jdk新特性总结,涵盖jdk8到jdk15,2022最新中高阶Java面试题总结
m0_69379782的博客
04-11 326
前言 “金九银十”的秋招热潮已经开始了,经过7月8月这两个月的提前批,终于成功拿下了一些大厂的offer。小编经过这么多次的面试,这两天整理了一份面试清单分享给大家,希望能给大家一点帮助(java方向),觉得有帮助的同学可以转发点个赞哦~~ } Optional 用于处理对象空指针异常: public String getDesc(Test test){ return Optional.ofNullable(test) .map(Test::getDesc).e
JAVAOptional实战
qq_40420214的博客
03-09 358
Optional类介绍 Optional类可能包含或不包含非空值的容器对象。 如果一个值存在, isPresent()将返回true和get()将返回值。 提供依赖于存在或不存在包含值的其他方法,例如orElse() (如果值不存在则返回默认值)和ifPresent() (如果值存在则执行代码块)。 Optional类提供的方法介绍 Empty 创建一个空的Optional of如果为null会直接报空指针 ofNullable如果为null会继续执行,不影响程序 filter如果一个值存在
Java8的Optional简介
最新发布
duke_ding2的博客
09-17 1118
Java8的Optional简介
JavaOptional实战
实践求真知
04-24 494
一引入Optional前的问题 1代码 /** * Copyright (C), 2020-2020, 软件公司 * FileName: WithoutOptionalDemo * Author: cakin * Date: 2020/4/24 * Description: 没有 Optional 会有什么问题 */ package optionaldemo; import...
Java8之Optional实战
dirft_din的博客
08-11 316
Optional类(java.util.Optional)是一个容器类,代表一个值存在或不存在,原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且可以避免空指针异常。 Optional对象构建&值获取方法 实例代码如下 Optional<String> optional = Optional.of("java8"); // NullPointerException空指针异常 值不能为空 optional = Optional.of(null); opti
还在用if(obj!=null)做非空判断?带你快速上手Optional实战性理解!
Java知音
05-14 2252
作者:樊亦凡juejin.im/post/5eb9faa26fb9a0437e0e9899轻松实战性理解Optional1.前言相信不少小伙伴已经被java的NPE(Null Point...
【函数式编程实战】(九) Optional实战大全
小明的Java问道之路
07-27 2265
本讲了解null的缺陷,了解为什么用Optional 取代null,学习Optional 的必要性,代码里怎么用Optional 才能更优雅
史上最全idea插件开发入门实战(傻瓜式教程)
热门推荐
亦疏爱吃肉
03-28 2万+
idea插件开发入门实战 文章目录idea插件开发入门实战前言一、书写第一个Hello World二、IDEA插件开发进阶1.基于java文件的规则校验2.基于XML文件规则的校验3.基于java文件的代码自动生成方法4.基于XML文件的读写方法 前言 建议先看一遍官方文档再开始 IDEA插件开发官方文档 一、书写第一个Hello World 新建项目 完事之后先修改plugin.xml配置文件。 <idea-plugin> <id>com.yishu.plugin&l
Flux、Mono、Reactor 实战史上最全
Bejpse的博客
07-27 3612
响应式编程用的是越来越多,尤其是在移动端安卓的应用上边。在Java后台服务开发中,响应式编程用的不是广泛,主要原因是,响应式编程需要一个完整的生态,包括数据库、缓存、中间件,都需要配套的响应式组件。但是这点,其实很多并没有。但是,随着SpringCloudGateway的火爆,响应式编程又变成了不可回避,不得不去学习的技术。如果要做SpringCloudGateway的开发,就必须掌握一些响应式编程的知识。把响应式编程Flux和Mono的知识梳理一下,形成了此文。...
Java 8新特性详解:Lambda与Stream API的应用秘笈
Java 8是Java发展史上的一个重要里程碑,它在2014年3月正式发布,带来了许多革命性的变化。这一章我们将对Java 8引入的一系列新特性进行概述,为后续深入分析各个特性打下基础。 Java 8引入的新特性大致可以分为三...
史上最详Android版kotlin协程入门进阶实战(一),2021最新Android开发者学习路线
m0_65320833的博客
02-02 1328
等等,好像哪里不对,奇怪的知识点突然有点增多啊。 上面提到协程体中最后一行是什么类型,最终返回的是什么类型T就是什么类型,好像跟我们想的不一样,返回值不应该是用return吗,学过kotlin的会知道,在的kotlin高阶函数中,lambda表达式如果你没有显式返回一个值,那它将隐式返回最后一个表达式的值。 那Job、Deferred和协程作用域又是些啥玩意! 不急,慢慢来,我们一个一个的来解释清楚。 什么是Job 、Deferred 、协程作用域 Job我们可以认为他就是一个协程作业是通过Corout
java8 Optional类 入门 使用教程
chuopi0561的专栏
02-27 246
Optional类 如果你发现看不懂,那说明你java8的stream没真正理解,可以看我的另一篇博客:https://my.oschina.net/u/3244997/blog/3014977 介绍 主要的几个方法: of(T value):通过工厂方法创建Optional实例,如果传...
Java 8 Optional类的简单使用教程
她们都叫我靓仔
06-16 182
Optional是一个没有子类的工具类,Optional是一个可以为null的容器对象,它的主要作用就是为了避免Null检查,防止NullpointerException Optional的基本使用 Optional对象的创建方式 // 第一种方式 通过of方法 of方法是不支持null的 Optional<String> op1 = Optional.of("zhangsan"); //Optional<Object> op2 = Optio.
还在用 if(obj!=null) 做非空判断?带你快速上手 Optional 实战性理解!
JAVA葵花宝典
05-30 418
来源:樊亦凡juejin.im/post/5eb9faa26fb9a0437e0e98991.前言2.认识Optional使用3.实战场景再现4.Optional使用注意事项5.jd...
Java8 Optional用法和最佳实践
少年闰土的博客
12-07 491
Java8 Optional用法和最佳实践
java8之Optional类实践
stay_the_course的博客
04-23 317
一句话 Optional类是为了很好的解决NPE,看如下的源码的前3行代码,我们就知道Optional是如何防范NPE的:(Optional 是个容器:它可以保存类型T的值,无论该值是否为null。至于是什么设计模式,就不说了) * @param <T> the type of value * @since 1.8 */ public final class Optional&l...
详细分析Java中的Optional类以及应用场景
码农研究僧的博客
01-29 8926
用开发的角度来讲,该类是 Java 8 中引入的一个用于处理可能为 null 的值的容器类。 它的设计目的是为了解决在代码中频繁出现的空指针异常问题。
使用 Java8 Optional 的正确姿势
weixin_33866037的博客
06-02 294
我们知道 Java 8 增加了一些很有用的 API, 其中一个就是 Optional. 如果对它不稍假探索, 只是轻描淡写的认为它可以优雅的解决 NullPointException 的问题, 于是代码就开始这么写了 Optional user = ……if (user.isPresent()) {return user.getOrders();} el...
java8新特性 - optional
06-28
### 回答1: Java8中的Optional类是一个容器对象,可以包含null或非null值。它提供了一种优雅的方式来处理null值,避免了NullPointerException异常的出现。Optional类可以用于返回值、方法参数和实例变量等场景中,使代码更加简洁、清晰和安全。使用Optional类可以使代码更加健壮,减少了代码中的null检查和异常处理,提高了代码的可读性和可维护性。 ### 回答2: Optional类是Java 8中新引入的一个类,它的主要作用是在避免NullPointerException的情况下将null值返回给调用者。这个类是一个容器对象,它可以保存非空的对象,也可以保存空值(null)。 Optional类提供了通过判断一个对象是否为空来避免空指针异常的方式。它可以在代码中替换传统的null判断,这样可以更加方便地编写代码,并且可以使代码更加健壮。 在Java中,如果一个方法返回值为null,那么在调用该方法返回值的时候,会有可能抛出NullPointerException异常。而Optional类的出现可以帮助我们避免这种情况的出现,在调用Optional类的get()方法时,如果Optional类中保存的对象不为null,就会返回该对象,否则抛出一个NoSuchElementException异常。 Optional类还提供了一些方法来简化代码,比如orElse()方法,如果Optional类中保存的对象不为null,则返回该对象,否则返回指定的default值。还有ifPresent()方法,当Optional类中保存的对象不为null时,会执行指定的代码,否则不执行。 总之,Optional类是Java 8中一个很有用的类,它可以帮助我们更加方便地处理null值,避免空指针异常的出现,并且可以简化代码。但是需要注意的是,不应该滥用Optional类,因为它并不是完美的解决方案,有时候需要对null值进行特殊处理。 ### 回答3: Java 8在语言层面上增加了一个新的类:Optional。这是一个特殊的容器对象,可以包含一个null或非null的值。 Optional的目的是解决Java中的null引用问题。在Java中,如果一个变量被赋值为null,而我们试图调用该变量所对应的方法,那么就会出现NullPointerException异常。 使用Optional可以避免这种情况的发生。如果一个变量是Optional对象,那么我们必须显式地检查该对象是否包含非null的值,才能对其进行操作。这样,在我们试图调用该变量所对应的方法之前,就可以避免空指针异常的发生。 Optional类提供了很多方法来判断是否有值、获取值、如果没有值则返回默认值等等,使得我们可以更加方便地处理空值。 下面是一些Optional类提供的方法: 1. Optional.of(T value):创建一个包含非null值的Optional对象,如果T为null,则抛出NullPointerException异常。 2. Optional.ofNullable(T value):创建一个Optional对象,如果T为null,则该对象为空。 3. Optional.empty():创建一个空的Optional对象。 4. get():如果值存在,则返回该值,否则抛出异常。 5. orElse(T other):如果值存在,则返回该值,否则返回其他默认值。 6. isPresent():返回一个boolean类型的值,表示该Optional对象是否包含值。 7. ifPresent(Consumer<? super T> consumer):如果该Optional对象包含值,则对该值执行给定的操作。 在编写Java程序时,我们应该始终努力避免使用null值。使用Optional类,可以使得我们的代码更加健壮、可读性更强。但是,过多地使用Optional可能会导致代码过于冗长,所以在使用的过程中需要权衡利弊。
写文章

热门文章

  • SpringBoot——动态数据源(多数据源自动切换) 14971
  • Ubuntu安装Redis 12265
  • SpringBoot——2.7.3版本整合Swagger3 10128
  • 从零开始的软路由之爱快虚拟机搭建openwrt 9542
  • 如何在Ubuntu上安装MongoDB? 7572

分类专栏

  • 算法 付费 19篇
  • 微服务 付费 14篇
  • Python数据可视化项目案例 17篇
  • Python网页项目实战案例 1篇
  • Java精品项目实战 27篇
  • SpringBoot 12篇
  • Redis 1篇
  • consul 8篇
  • 人工智能 3篇
  • 面试 1篇
  • 虚拟机 4篇
  • 微信小程序项目实战 2篇
  • 前端 4篇
  • Java 44篇
  • Kafka 4篇
  • MySQL 13篇
  • Elasticsearch 3篇
  • android 3篇
  • 微信小程序 1篇
  • jenkins 2篇
  • Windows 1篇
  • RocketMQ 2篇
  • 网络协议 1篇
  • TCP/IP
  • 架构 2篇
  • 编程学习 3篇
  • 设计模式 8篇

最新评论

  • 基于Python的图像信息隐藏技术的设计与实现【源码+论文+演示视频+包运行成功】

    2201_75847643: 源码在哪获取

  • 基于Java+SpringBoot的鞋类商品购物商城系统设计与实现

    weixin_50344526: 我想要

  • 基于python实现的手写数字识别系统设计与实现【源码+论文+演示视频+包运行成功】

    m0_74133479: 求源码数据集

  • 基于Java+SpringBoot+vue的高校学生党员发展管理系统设计与实现

    m0_75042026: 已经关注,点赞,收藏,评论

最新文章

  • 基于Python的信息加密解密网站设计与实现【源码+论文+演示视频+包运行成功】
  • 「深度学习之优化算法」(十九)蚁狮算法
  • 基于Python的小区监控图像拼接系统设计与实现【源码+论文+演示视频+包运行成功】
2024年1篇
2023年180篇

目录

目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

玻璃钢生产厂家商场美陈購買杭州玻璃钢雕塑摆件哪里有福州玻璃钢广场雕塑厂家江西玻璃钢雕塑定制玻璃钢雕塑固定方式山东艺术商场美陈厂家直销杭州玻璃钢雕塑工程鸡西玻璃钢雕塑定制价格河南庄子名人玻璃钢雕塑天津玻璃钢人物雕塑定制小区玻璃钢卡通雕塑设计嘉峪关玻璃钢植物雕塑定制广东透明玻璃钢雕塑摆件神农架玻璃钢花盆嘉峪关卡通玻璃钢雕塑公司天津步行街玻璃钢雕塑市场祥符玻璃钢雕塑设计银川玻璃钢彩绘雕塑北京艺术雕塑玻璃钢商场美陈 厦门将军马玻璃钢雕塑贵州玻璃钢人物雕塑定制玻璃钢雕塑掉漆能用丙烯颜料河南公园标识玻璃钢仿铜雕塑菏泽玻璃钢泡沫雕塑揭阳党建文化玻璃钢人物雕塑玻璃钢雕塑怎么制作的保定玻璃钢雕塑加工江苏公园玻璃钢雕塑销售厂家泰安名人玻璃钢雕塑香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化