【Java】 Java 中处理 null 或缺失数据

news2025/1/13 8:04:36

本文仅供学习参考!

相关教程地址:

https://juejin.cn/post/7234924083842154556

https://cloud.tencent.com/developer/article/1107739?areaSource=106005.3

https://www.developer.com/java/null-data-java/

在这里插入图片描述

将某些内容表示为空白或不存在始终是编程中的一个问题。例如,袋子里没有物品,仅仅意味着袋子是空的或者袋子里没有任何东西。但是如何表示计算机内存中缺少某些内容呢?例如,在内存中声明的对象包含一些值(变量是否初始化并不重要),即使它在上下文中可能没有任何意义 - 这称为垃圾。程序员最多可以丢弃它,但重点是声明的对象不为空。我们可以通过一个值来初始化它或放置一个null。然而,这仍然具有一定的价值;甚至为空是不代表任何东西的东西。在本编程教程中,我们分析了数据缺失和null的情况,看看 Java 在处理这个问题方面提供了什么。

Java 中什么是 null?

计算机中没有数据只是一个概念性的想法;内部表述实际上与之相反。我们可以将其与集合论联系起来,它定义了一个基数为0的空集。但是,在实际的表达中,它使用一个称为null的符号来表示空。因此,如果我们问“空集包含什么?”这个问题,一个可能的答案是null,即什么都没有或为空。但是,在软件开发中,我们知道null也是一个值。

通常,值0或内存中所有为 0 的位用于表示常量,其名称为null。与其他变量或常量不同,null表示没有与名称关联的值,它表示为内置常量,其中包含0值。

一段数据实际上被表示为指向它的引用。因此,为了在缺乏数据的情况下表示某些东西,开发人员必须编造一些什么也表示不了的东西。所以null(在 Go 中被称为nil ——也许是因为他们发现nilnull少一个字符,而且越少越好)是被选择的。这就是我们所说的空指针。因此,我们可以看到null既是一个指针,又是一个值。在 Java 中,某些对象(静态变量和实例变量)默认使用null创建,但稍后可以更改为指向值。

这里值得一提的是,null作为编程中的参考,是由 Tony Hoare 在 1965 年设计ALGOL时发明的。在他晚年的时候,他后悔这是一个价值数十亿美元的错误,他说:

我称之为我的十亿美元错误。这是 1965 年空引用的发明。当时,我正在设计第一个面向对象语言(ALGOL W)中引用的综合类型系统。我的目标是确保所有引用的使用都绝对安全,并由编译器自动执行检查。但我无法抗拒放入空引用的诱惑,只是因为它很容易实现。这导致了无数的错误、漏洞和系统崩溃,在过去四十年中可能造成了数十亿美元的痛苦和损失。

这个看似无害的名为null的东西多年来却造成了一些严重的麻烦。但是,也许在编程中不能完全忽视null的重要性。这就是许多后来的编译器创建者认为保留遗产是明智之举的原因。然而,Java 8 及更高版本尝试提供一种名为Optional的类型,直接处理与使用null相关的一些问题。

Java中空指针的问题

NullPointerException是每个 Java 程序员经常遇到的常见错误**。当我们尝试取消引用一个不指向任何内容的标识符时,就会引发此错误 - 这仅仅意味着我们期望获取一些数据,但数据丢失了。我们试图访问的标识符指向null**。

下面是我们如何在 Java 中引发NullPointerException错误的代码示例:

public class Main {
    public static void main(String[] args) {
        Object obj = null;
        System.out.println(obj.toString());
    }
}

在集成开发环境 (IDE) 或代码编辑器中运行此代码将产生以下输出:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Object.toString()" because "obj" is null
	at Main.main(Main.java:4)

通常在编程中,避免问题的最佳方法是知道如何创建问题。现在,尽管众所周知必须避免null引用,但 Java API 仍然大量使用null作为有效引用。一个这样的例子如下。java.net 包中Socket类构造函数的文档说明如下:

public Socket( InetAddress address, int port, InetAddress localAddr,             int localPort ) throws IOException

这段Java代码:

  • 创建一个套接字并将其连接到指定远程端口上的指定远程地址。Socket还将**bind()**到提供的本地地址和端口。
  • 如果指定的本地地址为null,则相当于将该地址指定为AnyLocal地址(请参阅InetAddress.isAnyLocalAddress())。
  • 本地端口号为零将使系统在绑定操作中选择一个空闲端口。
  • 如果有安全管理器,则会调用其checkConnect方法,并以主机地址和端口作为参数。这可能会导致SecurityException

根据Java文档,突出显示的点清楚地表明引用被用作有效参数。这个null在这里是无害的,并用作哨兵值来表示缺少某些内容(此处是在套接字中缺少端口值的情况下)。因此,我们可以看到null并没有完全避免,尽管它有时很危险。Java中有很多这样的例子。

如何处理 Java 中数据缺失的情况

一个完美的程序员总是会编写完美的代码,实际上不会对null产生任何问题。但是,对于我们这些容易犯错误并需要某种更安全的替代方案来表示某些内容不存在而不诉诸 null 的创新用法的人来说,我们需要一些支持。因此,Java 引入了一种类型(称为Optional 的类),它以更体面的方式处理不是由于错误而发生的缺席值。

现在,在讨论任何代码示例之前,让我们先看一下来自 Java API 文档的以下摘录:

public final class Optional
extends Object

这段摘录展示了:

  • 一个容器对象,可能包含也可能不包含非空值。如果存在值,isPresent()将返回true,而**get()**将返回该值。
  • 还提供了取决于所包含值是否存在的其他方法,例如orElse()(如果值不存在则返回默认值)和ifPresent()(如果值存在则执行代码块)。
  • 这是一门以价值观为基础的课程;在Optional实例上使用身份敏感操作(包括引用相等(== )、身份哈希码或同步)可能会产生不可预测的结果,开发人员应该避免。

事实上,Java 中有许多可选类,例如OptionalOptionalDoubleOptionalIntOptionalLong——所有这些都处理开发人员不确定值是否存在的情况。在 Java 8 引入这些类之前,程序员习惯使用null值来表示值不存在。因此,称为NullPointerException的错误是一种常见现象,因为我们有意(或无意)尝试取消引用引用;一种解决方法是经常检查值以避免生成异常。

这些课程提供了更好的策略来应对这种情况。请注意,所有可选类都是基于值的,因此它们是不可变的并且具有各种限制,例如不使用实例进行同步并避免使用任何引用相等。在下一节中,我们将特别关注Optional类。其他可选类的功能类似。

Optional类中的T表示存储的值的类型,可以是T类型的任何。它也可能是空的。尽管Optional类定义了多个方法,但没有定义任何构造函数**。开发人员可以判断某个值是否存在,如果存在则获取该值,如果不存在则获取默认值,或者构造一个可选值**。查看 Java 文档以获取有关这些类的可用函数的详细信息。

如何在Java中使用Optional

下面的代码示例展示了如何优雅地处理 Java 中返回null或缺少元素的对象。Optional类充当可能不存在的对象的包装器:

package org.app;

public class Employee {
    private int id;
    private String name;
    private String email;

    public Employee(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}




package org.app;

import java.util.HashMap;
import java.util.Optional;

public class Main {
    private HashMap <Integer,Employee>db = new HashMap<>();
    public Main() {
        db.put(101, new Employee(101, "Pravin Pal", "pp@gmail.com"));
        db.put(102, new Employee(102, "Tuhin Shah", "ts@gmail.com"));
        db.put(103, new Employee(103, "Pankaj Jain", "pj@gmail.com"));
        db.put(104, new Employee(104, "Anu Sharma", "as@gmail.com"));
        db.put(105, new Employee(105, "Bishnu Prasad", "bp@gmail.com"));
        db.put(106, null);
        db.put(107, null);
    }

    public Optional findEmployeeById(int id){
         return Optional.ofNullable(db.get(id));
    }

    public Employee findEmployeeById2(int id){
        return db.get(id);
    }

    public static void main(String[] args) {
        Main m = new Main();
        Optional opt = m.findEmployeeById(108);
        opt.ifPresent(emp->{
            System.out.println(emp.toString());
        });

        if(opt.isPresent()){
            System.out.println(opt.get().toString());
        } else {
            System.out.println("Optional is empty.");
        }

        System.out.println(m.findEmployeeById2(106));
    }
}

Optional类的一些关键函数是isPresent()get()isPresent ()函数确定该值是否存在。如果该值存在,则该函数返回布尔值,否则返回值。

可以使用**get()函数获取存在的值。但是,如果调用get()函数并且它没有值,则会引发NoSuchElementException 。理想情况下,在调用get()函数之前,始终使用ifPresent()**函数检查值是否存在。

END

如果有什么东西是编程无法消除的,但要提醒大家使用,那就是null。在数据库中,在存储值时,建议避免在表中存储空值。未正确规范化的数据库表可能有太多值。一般来说,对于计算中价值缺失的含义并没有非常明确的定义。无论如何,在某种程度上,使用Java 中的Optional类可以处理与空值相关的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/693775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TX Text Control 31 sp3 for ActiveX-VB6-Crack

Visual Basic 6 应用程序的文档处理 适用于 Visual Basic 6 和基于 COM 的语言的综合文字处理和报告 视窗用户界面 功能齐全的文档编辑器 TX Text Control 是一款免版税、完全可编程的丰富编辑控件&#xff0c;它在专为 Visual Studio 设计的可重用组件中为开发人员提供了广泛的…

数字空间【高校版】上线

WRITE-BUG团队一直在致力于推动科技创新与科研学习数字化建设&#xff0c;为学生的学习、老师的工作&#xff0c;插上数字化的翅膀。 目前&#xff0c;我们注意到高校在大力推进数字化建设&#xff0c;在内容管理上遇到以下问题亟待解决&#xff1a; 各个科研实验室资料、项目…

【后端面经-Java】Synchronize和ReentrantLock区别

【后端面经-Java】Synchronize和ReentrantLock区别 1. 概念介绍1.1 线程安全锁1.2 公平锁1.3 响应中断/等待可中断 2. 区别2.1 底层实现2.2 锁的用法2.3 锁的特点2.4 性能比较2.5 适用场景 3. 总结比较参考文献 1. 概念介绍 1.1 线程安全锁 Synchronize&#xff08;同步锁&am…

Spring Boot 中的 @PutMapping 注解是什么,原理,如何使用

Spring Boot 中的 PutMapping 注解是什么&#xff0c;原理&#xff0c;如何使用 在 Spring Boot 中&#xff0c;PutMapping 是一种注解&#xff0c;它可以将 HTTP PUT 请求映射到指定的处理方法上。本文将介绍 PutMapping 的原理以及如何在 Spring Boot 中使用它。 PutMapping…

【软考网络管理员】2023年软考网管初级常见知识考点(31)-著作权、商标权、专利权详解

涉及知识点 著作权保护期限&#xff0c;著作权人的确定&#xff0c;侵权如何去判定&#xff0c;商标权是什么&#xff1f;专利权详解&#xff0c;软考网络管理员常考知识点&#xff0c;软考网络管理员网络安全&#xff0c;网络管理员考点汇总。 原创于&#xff1a;CSDN博主-《…

Visual C++中的虚函数和纯虚函数(对比学习法之一)

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来说说Visual C中的虚函数和纯虚函数。该系列帖子全部使用我本人自创的对比学习法。也就是当C学不下去的时候&#xff0c;就用JAVA实现同样的代码&#xff0c;然后再用对比的方法把C学会。 直接说虚函数…

初识mysql数据库之表的约束

目录 一、表的约束的概念 二、非空约束&#xff08;空属性&#xff09; 2. 空属性的使用 三、default约束&#xff08;默认值&#xff09; 1. 默认值的含义 2. 默认值的使用 3. 默认值与非空约束的关系 3.1 默认值与非空约束的生效问题 3.2 default自动生成与not null的…

Linux 学习记录40(C++篇)

Linux 学习记录40(C/QT篇) 本文目录 Linux 学习记录40(C/QT篇)一、QT软件的使用1. 新建工程 二、C语言和C的区别1. C对C的扩充2. C对C的兼容 三、第一个C程序1. cout标准输出流对象(1.介绍&#xff1a;(2. 运算符(3. cout的使用 2. cin标准输出流对象(1.介绍&#xff1a;(3. ci…

python【爬虫】【批量下载】年报抓取

python年报爬取更新 本人测试发现&#xff0c;ju chao网的年报爬取距离我上一篇博客并没有啥变化&#xff0c;逻辑没变&#xff0c;应好多朋友的需要&#xff0c;这里补充代码 import json import osimport requestsweb_url 改成网站的域名&#xff0c;因为csdn屏蔽 def load…

深入了解cookie以及实际项目中的应用

目录 cookie的原理 cookie是不可跨域的 cookie 的属性 Cookie与Session的区别 在git中的应用 cookie的原理 什么是cookie呢&#xff1f; 众所周知&#xff1a;http都是无状态的 但随着 Web 的不断发展&#xff0c;这种 无状态 的特性出现了弊端。当你登录到一家购物网站…

RabbitMQ保证消息的可靠投递,Java实现RabbitMQ消息的可靠投递,Springboot实现RabbitMQ消息的可靠投递

文章目录 一、RabbitMQ消息可靠性概述1、引出问题2、RabbitMQ消息可靠性保证的四个环节 二、保证生产者消息发送到RabbitMQ服务器1、服务端确认&#xff1a;Transaction模式&#xff08;1&#xff09;JavaAPI&#xff08;2&#xff09;springbootAPI 2、服务端确认&#xff1a;…

【Matlab】根据伯德图计算pid参数方法原理

在学习鲁棒控制的过程中&#xff0c;有一些步骤需要根据一些性能参数来计算pid参数&#xff0c;因此记录一下根据伯德图的性能来计算pid参数的原理。 系统开环响应的几个关键参数 在使用开环响应初调控制器参数时&#xff0c;主要就是调整几个需要注意的关键参数&#xff0c;…

nbcio-vue中formdesigner的组件显示不正常的处理

今天看演示系统的formdesigner组件显示不正常&#xff0c;也不知道是什么时候开始的事情&#xff0c; 如下&#xff1a; 对组件的操作倒是正常&#xff0c;但看本地是正常的&#xff0c;如下&#xff1a; 开始也不知道是什么原因&#xff0c;看代码也是一样的&#xff0c;应该…

11 MFC 制作记事本

文章目录 界面制作制作菜单设置编译框随着窗口的变化而变化OnSize打开文件文件另存为设置字体颜色修改字体文件的查找与替换查找与替换对话框显示&#xff08;非模态对话框&#xff09;对话框消息与对话框处理函数 全部代码 界面制作 制作菜单 选择Menu 点击新建 将内容写入&qu…

Nightingle夜莺Docker版SNMP监控

起因 对夜莺很感兴趣&#xff0c;想使用一下。我看官方提供了v6版本的docker-compose。而且我之前有使用过promtheus和grafana&#xff0c;虽然很好但是总觉得还是得二开。总有一天有人去搞一个不错的玩意儿出来。官方文档地址 安装与配置 直接运行docker版本的demo&#xf…

mysql内部结构和InnoDB底层原理

一、mysql内部结构 mysql总体上分为客户端、Server层、引擎层&#xff0c;具体如下图&#xff1a; 1、连接器 一般客户端通过jdbc、navicat等工具发送请求连接到mysql服务端&#xff0c;完成TCP三次握手后&#xff0c;连接器就开始认证身份&#xff0c;如果身份认证成功&…

数据结构-串、数组和广义表

数据结构之串、数组和广义表 串的定义一、串的顺序存储结构1.1、串的链式存储结构1.2、串的模式匹配算法1.2.1、Brute-Force简称为BF算法1.2.2、KMP算法 数组的定义2.1、数组的顺序存储结构2.2、数组的特点&#xff1a;结构固定-----维数和维界不变2.3、特殊矩阵的压缩存储 广义…

密码学—Kasiski测试法Python程序

Kasiski Kasiski是辅助破解Vigenere的前提工作&#xff0c;Kasiski是猜测加密者使用Vigenere密码体系的密钥的长度&#xff0c;Kasiski只是猜测长度而已&#xff0c;所以说是辅助破解Vigenere 若密文中出现两个相同的密文段(密文段的长度m>2)&#xff0c;则它们对应的明文&…

leetcode第66题:加一

题目 这是一道简单的小题&#xff0c;自己却也没写出来。。。逆序遍历数组digits&#xff0c;用carry标记当前元素是否需要进位&#xff08;0不要&#xff0c;1要&#xff09;。 若carry1&#xff0c;则当前元素要么置0&#xff0c;要么自加1。自加1之后&#xff0c;再也不需要…

【深入了解Spring Cloud Alibaba Nacos:服务注册和配置中心】—— 每天一点小知识

&#x1f4a7; 深入了解 S p r i n g C l o u d A l i b a b a N a c o s &#xff1a;服务注册和配置中心 \color{#FF1493}{深入了解Spring Cloud Alibaba Nacos&#xff1a;服务注册和配置中心} 深入了解SpringCloudAlibabaNacos&#xff1a;服务注册和配置中心&#x1f4a7;…