求求你不要在用 !=null 判空了

本文介绍Java中Optional类的作用,如何避免传统判空带来的冗余,并通过实例展示其常用方法如of、ofNullable、isPresent、get、ifPresent、orElse等的用法,以及它们在实际开发中的优势和性能差异。

点击上方“芋道源码”,选择“设为星标

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 8:55 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:toutiao.com/i6872294360059216388

  • 导语

  • 为什么要用Optional,它到底是什么东西

  • Optional 的方法,如下图

  • Optional实例

  • 小结

导语

在没有用Optional判空之前,你是否也像下面的代码一样判空呢?如果是,请往下看,Optional 相对传统判空的优势。

传统阶层判空

为什么要用Optional,它到底是什么东西

你也看到了上面的那张图,一旦代码量大起来了,条件多了,代码就会变得很冗余,变得难以维护。那么此时我们就有必要了解Optional了。

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

Optional 的方法,如下图

Optional方法-图1
Optional方法-图2

好,方法就是这么多,其他的也不必多说,相信各位小伙伴一看就懂;如何使用,我还是用代码演示,请往下移步。

Optional实例

1.of:为非null的值创建一个Optional。of方法通过工厂方法创建Optional类。需要注意的是,创建对象时传入的参数不能为null。如果传入参数为null,则抛出NullPointerException 。

Optional<String> optional = Optional.of("xiaoming");
//传入null,抛出NullPointerException
Optional<Object> o = Optional.of(null);

2.ofNullable:为指定的值创建一个Optional,如果指定的值为null,则返回一个空的Optional。

Optional<Object> o1 = Optional.ofNullable(null);

3.isPresent:值存在返回true,否则返回false

Optional<String> optiona2 = Optional.of("xiaoming");
System.out.println(optiona2.isPresent());

4.get:Optional有值就返回,没有抛出NoSuchElementException

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

5.ifPresent:如果Optional有值则调用consumer处理,否则不处理

Optional<Object> o1 = Optional.ofNullable(null);
 o1.ifPresent(s -> System.out.println(s));

6.orElse:如果有值则将其返回,否则返回指定的其它值

Optional<Object> o1 = Optional.ofNullable(null);
System.out.println(o1.orElse("输出orElse")); // 输出orElse

7.orElseGet:orElseGet与orElse方法类似,区别在于得到的默认值。orElse方法将传入的字符串作为默认值,orElseGet方法可以接受Supplier接口的实现用来生成默认值

Optional<Object> o1 = Optional.ofNullable(null);
System.out.println(o1.orElseGet(() -> "default value")); // default value

*注意:orElse 和 orElseGet 看似差不多,其实有很大不同;看下面例子

Shop shop = null;
System.out.println("test orElse");
Optional.ofNullable(shop).orElse(createNew());System.out.println("test orElseGet");
Optional.ofNullable(shop).orElseGet(()->createNew());
//createNew
private static Shop createNew() {  System.out.println("create new");
  return new Shop("丝袜", 50);
}//输出:
test orElsecreate newtest orElseGetcreate new
Shop shop = new Shop("长腿丝袜",100);
System.out.println("test orElse");
Optional.ofNullable(shop).orElse(createNew());System.out.println("test orElseGet");
Optional.ofNullable(shop).orElseGet(()->createNew());
//输出
test orElsecreate newtest orElseGet

从上面两个例子可以看到,当Optional 为空时,orElse和orElseGet 区别不大,但当Optional有值时,orElse仍然会去调用方法创建对象,而orElseGet不会再调用方法;在我们处理的业务数据量大的时候,这两者的性能就有很大的差异。


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

Optional<Object> o1 = Optional.ofNullable(null);
try {
  o1.orElseThrow(() -> new Exception("异常!"));
} catch (Exception e) {
  System.out.println("info:" + e.getMessage());
}//输出:info:异常!

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

Optional<String> optional = Optional.of("xiaoming");
String s = optional.map(e -> e.toUpperCase()).orElse("shiyilingfeng");
System.out.println(s); //输出: XIAOMING

10.flatMap:如果有值,为其执行mapping函数返回Optional类型返回值,否则返回空Optional。与map不同的是,flatMap 的返回值必须是Optional,而map的返回值可以是任意的类型T

Optional<String> optional = Optional.of("xiaoming");
Optional<String> s = optional.flatMap(e -> Optional.of(e.toUpperCase()));
System.out.println(s.get()); //输出:XIAOMING

11.filter

List<String> strings = Arrays.asList("rmb", "doller", "ou");
for (String s : strings) {
  Optional<String> o = Optional.of(s).filter(s1 -> !s1.contains("o"));
  System.out.println(o.orElse("没有不包含o的"));
}//输出:
rmb
没有不包含o的
没有不包含o的

小结

Optional 是java非常有用的一个补充,它旨在减少代码中的NullPointerExceptions,虽然不能百分之百的消除,但也是精心设计的。使用Optional 能更好的帮助我们创建可读性强,bug更少的应用程序。



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 20 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

兄弟,一口,点个!????

#include <stdio.h> #include <string.h> // 定义学生结构体 typedef struct Student { int id; // 学号 char name[50]; // 姓名 float score; // 成绩 struct Student* next; // 指向下一个节点的指针 } StudentNode; // 添加学生(在链表末尾添加) void addStudent(StudentNode** head, int id, const char* name, float score) { StudentNode* newStudent = (StudentNode*)malloc(sizeof(StudentNode)); newStudent->id = id; strcpy(newStudent->name, name); newStudent->score = score; newStudent->next = NULL; if (*head == NULL) { *head = newStudent; } else { StudentNode* temp = *head; while (temp->next != NULL) { temp = temp->next; } temp->next = newStudent; } } // 按学号删除学生 void deleteStudent(StudentNode** head, int id) { StudentNode* temp = *head; StudentNode* prev = NULL; if (temp != NULL && temp->id == id) { *head = temp->next; free(temp); return; } while (temp != NULL && temp->id != id) { prev = temp; temp = temp->next; } if (temp != NULL) { prev->next = temp->next; free(temp); } } // 按学号查找学生 StudentNode* findStudent(StudentNode* head, int id) { StudentNode* temp = head; while (temp != NULL) { if (temp->id == id) { return temp; } temp = temp->next; } return NULL; } // 打印所有学生信息 void printAllStudents(StudentNode* head) { StudentNode* temp = head; while (temp != NULL) { printf("学号: %d, 姓名: %s, 成绩: %.2f\n", temp->id, temp->name, temp->score); temp = temp->next; } } // 计算平均成绩 float calculateAverageScore(StudentNode* head) { if (head == NULL) { return 0; } float totalScore = 0; int count = 0; StudentNode* temp = head; while (temp != NULL) { totalScore += temp->score; count++; temp = temp->next; } return totalScore / count; } // 主函数提供菜单选择操作 int main() { StudentNode* head = NULL; int choice, id; char name[50]; float score; while (1) { printf("\n学生成绩管理系统菜单:\n"); printf("1. 添加学生\n"); printf("2. 按学号删除学生\n"); printf("3. 按学号查找学生\n"); printf("4. 打印所有学生信息\n"); printf("5. 计算平均成绩\n"); printf("6. 退出\n"); printf("请输入你的选择: "); scanf("%d", &choice); switch (choice) { case 1: printf("请输入学号: "); scanf("%d", &id); printf("请输入姓名: "); scanf("%s", name); printf("请输入成绩: "); scanf("%f", &score); addStudent(&head, id, name, score); break; case 2: printf("请输入要删除的学生学号: "); scanf("%d", &id); deleteStudent(&head, id); break; case 3: printf("请输入要查找的学生学号: "); scanf("%d", &id); StudentNode* found = findStudent(head, id); if (found != NULL) { printf("学号: %d, 姓名: %s, 成绩: %.2f\n", found->id, found->name, found->score); } else { printf("未找到该学生。\n"); } break; case 4: printAllStudents(head); break; case 5: printf("平均成绩: %.2f\n", calculateAverageScore(head)); break; case 6: // 释放链表内存 while (head != NULL) { StudentNode* temp = head; head = head->next; free(temp); } return 0; default: printf("无效的选择,请重新输入。\n"); } } } 在这个代码基础上完成这个题目
12-10
调用以下两个代码: 第一个: #include <stdio.h> #include <malloc.h> #define MaxSize 100 typedef char ElemType; typedef struct tnode { ElemType data; //数据域 struct tnode *lchild,*rchild; //指针域 } BTNode; void CreateBTree(BTNode * &bt,char *str) { BTNode *St[MaxSize],*p=NULL; int top=-1,k,j=0; char ch; bt=NULL; //建立的二叉树初始时为 ch=str[j]; while (ch!='\0') //str未扫描完时循环 { switch(ch) { case '(':top++;St[top]=p;k=1; break; //为左孩子结点 case ')':top--;break; case ',':k=2; break; //为右孩子结点 default:p=(BTNode *)malloc(sizeof(BTNode)); p->data=ch;p->lchild=p->rchild=NULL; if (bt==NULL) //*p为二叉树的根结点 bt=p; else //已建立二叉树根结点 { switch(k) { case 1:St[top]->lchild=p;break; case 2:St[top]->rchild=p;break; } } } j++; ch=str[j]; } } void DestroyBTree(BTNode *&bt) { if (bt!=NULL) { DestroyBTree(bt->lchild); DestroyBTree(bt->rchild); free(bt); } } int BTHeight(BTNode *bt) { int lchilddep,rchilddep; if (bt==NULL) return(0); //树的高度为0 else { lchilddep=BTHeight(bt->lchild); //求左子树的高度为lchilddep rchilddep=BTHeight(bt->rchild); //求右子树的高度为rchilddep return (lchilddep>rchilddep)? (lchilddep+1):(rchilddep+1); } } int NodeCount(BTNode *bt) //求二叉树bt的结点个数 { int num1,num2; if (bt==NULL) //树返回0 return 0; else { num1=NodeCount(bt->lchild); //求左子树结点个数 num2=NodeCount(bt->rchild); //求右子树结点个数 return (num1+num2+1); //返回和加上1 } } int LeafCount(BTNode *bt) //求二叉树bt的叶子结点个数 { int num1,num2; if (bt==NULL) //树返回0 return 0; else if (bt->lchild==NULL && bt->rchild==NULL) return 1; //叶子结点时返回1 else { num1=LeafCount(bt->lchild); //求左子树叶子结点个数 num2=LeafCount(bt->rchild); //求右子树叶子结点个数 return (num1+num2); //返回和 } } void DispBTree(BTNode *bt) { if (bt!=NULL) { printf("%c",bt->data); if (bt->lchild!=NULL || bt->rchild!=NULL) { printf("("); //有子树时输入'(' DispBTree(bt->lchild); //递归处理左子树 if (bt->rchild!=NULL) //有右子树时输入'.' printf(","); DispBTree(bt->rchild); //递归处理右子树 printf(")"); //子树输出完毕,再输入一个')' } } } 第二个: #include "BTree.cpp" #define MaxSize 100 void PreOrder(BTNode *bt) { if (bt!=NULL) { printf("%c ",bt->data); PreOrder(bt->lchild); PreOrder(bt->rchild); } } void InOrder(BTNode *bt) { if (bt!=NULL) { InOrder(bt->lchild); printf("%c ",bt->data); InOrder(bt->rchild); } } void PostOrder(BTNode *bt) { if (bt!=NULL) { PostOrder(bt->lchild); PostOrder(bt->rchild); printf("%c ",bt->data); } } void LevelOrder(BTNode *bt) { BTNode *p; BTNode *qu[MaxSize]; //定义循环队列,存放二叉链结点指针 int front,rear; //定义队头和队尾指针 front=rear=-1; //置队列为队列 rear++; qu[rear]=bt; //根结点指针进入队列 while (front!=rear) //队列不为循环 { front=(front+1)%MaxSize; p=qu[front]; //出队结点*p printf("%c ",p->data); //访问该结点 if (p->lchild!=NULL) //有左孩子时将其进队 { rear=(rear+1)%MaxSize; qu[rear]=p->lchild; } if (p->rchild!=NULL) //有右孩子时将其进队 { rear=(rear+1)%MaxSize; qu[rear]=p->rchild; } } } 完成实验目的:掌握二叉树的基本应用 要求:编写一个程序exp10.cpp实现以下问题:假设二叉树中的每个结点是单个字符且所有结点值不相同,采用二叉链存储结构,输出二叉树的先序遍历、中序遍历和后序遍历序列,设计两个算法分别求给定的二叉树b中的所有大于x的结点个数,以及最大结点值(树返回‘0’),并用相关数据进行测试。
12-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值