首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何避免 Java 中的“NullPointerException”

我个人认为这种行为的原因如下: 大多数开发人员在这里没有看到任何问题,并将所有 NPE 异常都视为开发人员的错。 意识到这个设计问题的开发人员不知道如何解决它。...Null 值代表所有未初始化的对象。而且,只要可以初始化任何对象,就可以将 Null 值分配给任何类型。 因此,Java 允许下一个分配: 这里有什么问题?对象未初始化,因此它们指向空引用。...因此,他们错过了: 初始化对象 验证对象 没有治愈人性的方法,也与它无关。避免NPE的实用方法是什么?让我们在下面回顾一个示例并尝试修复它。...而且,即使我们忘记使用 Optional 功能,这个想法也会突出显示 .get() ,提醒我们为设计提供空检查。 9 Optional 为什么不那么受欢迎?...11 @NotNull @Nullable 我们需要一个解决方案,它可以在编译步骤中读取我们的代码,并通知我们错过了潜在的 NPE 场景。为此,我们可以使用 Java 注释处理器。

2.9K20

JVM:类加载过程

类的初始化 当一个JVM在我们通过执行Java命令启动之后,其中可能包含的类非常多,是不是每个类都会被初始化呢?答案是否定的。...,即使别的类中不new Simple(),直接访问变量x也会导致类的初始化 访问类的静态方法,也会导致类初始化 public class Simple { static { System.out.println...会导致类被初始化 Class.forName() 启动类,就是执行main函数所在的类会导致该类被初始化 当一个类在初始化时,要求其父类全部都已经初始化过了,但是一个接口在初始化时,并不要求父接口全部都完成了初始化...new方法新建了一个Simple类型的数组,但是它并不能导致Simple类的初始化。...准备 正式为类中定义的变量(即静态变量,被static修饰的变量)分配内存并设置初始值的阶段 当一个class的字节流通过了所有的验证过程之后,就开始为该对象的类变量,也就是静态变量,分配内存并且设置初始值了

83441
  • 您找到你想要的搜索结果了吗?
    是的
    没有找到

    手写的JVM面试题,你来不来围观一波??

    可能会被占满,在未配置为采用CMS GC的情况下会执行FullGC。...为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文件被编译成能被Java虚拟机执行的字节码文件。...Java被设计成允许应用程序可以运行在任意的平台,而不需要程序员为每一个平台单独重写或者是重新编译。Java虚拟机让这个变为可能,因为它知道底层硬件平台的指令长度和其他特性。...对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立在 JVM 中的唯一性,每一个类加载器,都有一个独立的类名称空间。...这就是为什么正确的永久代大小对避免Full GC是非常重要的原因。请参考下Java8:从永久代到元数据区 (注:Java8中已经移除了永久代,新加了一个叫做元数据区的native内存区) 21.

    29140

    Vue Router 导航守卫:避免多次执行的陷阱与解决方案

    在 Vue Router 中,导航守卫是非常重要的功能,它可以在路由跳转之前或之后执行一些特定的操作。但是,如果你不小心,导航守卫可能会多次执行,这可能会导致一些问题。...如果我们在每个路由的 beforeEach 守卫中执行这个操作,就可能会出现问题。因为每次导航时,都会执行 beforeEach 守卫,即使路由没有改变,也会重新执行。...这就导致了操作被多次执行,可能会导致一些问题。举个例子,假设我们在 beforeEach 守卫中检查用户是否登录,如果未登录,则跳转到登录页面。...如果用户在登录页面已经登录,但未完成登录操作就关闭了页面,再次打开页面时,由于 beforeEach 守卫会多次执行,会导致用户再次被重定向到登录页面,这就不是我们想要的结果。...因此,即使组件被销毁,这个导航守卫仍然会保留在 Vue Router 的内部实例中,并在下一次路由变化时继续执行。

    3.2K10

    2019年JVM最新面试题,必须收藏它

    由于Java的跨平台性,经过编译的Java源程序并不是一个可执行程序,而是一个或多个类文件。当Java程序需要使用某个类时,JVM会确保这个类已经被加载、连接(验证、准备和解析)和初始化。...理论上Java因为有垃圾回收机制(GC)不会存在内存泄露问题(这也是Java被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄露的发生...如果一个对象引用被无意识的保留起来了,那么垃圾回收器不会处理这个对象,也不会处理该对象引用的其他对象,即使这样的对象只有少数几个,也可能会导致很多的对象被排除在垃圾回收之外,从而对性能造成重大影响,极端情况下会引发...GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java...垃圾回收不会发生在永久代,如果永久代满了或者是超过了临界值,会触发完全垃圾回收(Full GC)。如果你仔细查看垃圾收集器的输出信息,就会发现永久代也是被回收的。

    63240

    Java并发关键字-final

    (代码涵盖了final修饰变量所有的可能情况,耐心看下去会有收获的) ? 看上面的图片已经将每种情况整理出来了,这里用截图的方式也是觉得在IDE出现红色出错的标记更能清晰的说明情况。...同时,处理器和编译为了性能优化会对指令序列有编译器和处理器重排序。那么,在多线程情况下,final会进行怎样的重排序?会导致线程安全的问题吗?下面,就来看看final的重排序。...因此,写final域的重排序规则可以确保:在对象引用为任意线程可见之前,对象的final域已经被正确初始化过了,而普通域就不具有这个保障。...比如在上例,线程B有可能就是一个未正确初始化的对象finalDemo。...具体是否插入还是得看是什么处理器 为什么final引用不能从构造函数中“溢出” 这里还有一个比较有意思的问题:上面对final域写重排序规则可以确保我们在使用一个对象引用的时候该对象的final域已经在构造函数被初始化过了

    70730

    面试必问的 JVM 类加载机制,你懂了吗?

    类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载7个阶段。其中验证、准备、解析3个部分统称为连接。...5)初始化 到了初始化阶段,才真正开始执行类中定义的Java程序代码。在准备阶段,变量已经赋过一次系统要求的初始零值,而在初始化阶段,则会根据程序员通过程序制定的主观计划去初始化类变量和其他资源。...,或者被java.ext.dirs系统变量所指定的路径中的所有类库,开发者可以直接使用扩展类加载器。...ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 1、检查请求的类是否已经被加载过了...下面的,可能会导致很多隐患。

    58420

    JMM—详细总结

    写final域的重排序规则可以保证:对象的引用对任何线程可见之间,final域已经被初始化过了。而普通域不具有这个保障。...为什么对象引用不能从构造函数内溢出 前面我们提到过,写final域的重排序规则可以保证:在引用变量为任意线程可见之前,该引用变量指向对象的final域一定被正确的初始化了。...在上图代码中,首次执行getInstance()方法的线程将导致InstanceHolder类被初始化。在Java语言规范中规定:对于每一个类或接口C,都有一个唯一的初始化锁LC与之对应。...JVM在类初始化期间会获取这个初始化锁,并且每个线程至少获取一次锁来确保这个类已经被初始化过了。...基于类的延迟初始化为什么只能对静态字段进行延迟初始化? 因为访问类的静态变量的时候,会触发类的初始化。并且会同步初始化类。基于2个特性,产生了类初始化方案。

    71320

    Java并发编程实战系列16之Java内存模型(JMM)

    如果缺少同步会有很多因素导致无法立即、甚至永远看不到一个线程的操作结果,包括 编译器中指令顺序 变量保存在寄存器而不是内存中 处理器可以乱序或者并行执行指令 缓存可能会改变将写入变量提交到主内存的次序...在初始化中使用static会提供额外的线程安全保证。静态初始化是由JVM在类的初始化阶段执行,并且在类被加载后,在线程使用前的。静态初始化期间,内存写入操作将自动对所有线程可见。...,是一种anti-pattern,它只在JAVA1.4时代好用,因为早期同步的性能开销较大,但是现在这都不是事了,已经不建议使用。...也就是说:写final域的重排序规则可以确保:在对象引用为任意线程可见之前,对象的final域已经被正确初始化过了。...(个人觉得基本意思也就是确保在构造函数外把这个被构造对象的引用赋值给一个引用变量之前,final域已经完全初始化并且赋值给了当前构造对象的成员域,至于初始化和赋值这两个操作则不确保先后顺序。)

    91860

    Java的final

    b被final修饰,因此会被当做编译器常量,所以在使用到b的地方会直接将变量b 替换为它的值。...因此,写final域的重排序规则可以确保:在对象引用为任意线程可见之前,对象的final域已经被正确初始化过了,而普通域就不具有这个保障。...比如在上例,线程B有可能就是一个未正确初始化的对象finalDemo。 读final域重排序规则 在一个线程中,初次读对象引用和初次读该对象包含的final域,JMM会禁止这两个操作的重排序。...问题:为什么final引用不能从构造函数中“溢出” 一个比较有意思的问题:上面对final域写重排序规则可以确保我们在使用一个对象引用的时候该对象的final域已经在构造函数被初始化过了。...尽管依然满足了final域写重排序规则:在引用对象对所有线程可见时,其final域已经完全初始化成功。但是,引用对象“this”逸出,该代码依然存在线程安全的问题。

    55930

    Java虚拟机

    Java虚拟机如果不检查输入的字节流,对其完全信任的话,很可能会因为载入了有错误或有恶意企图的字节码流而导致整个系统受攻击甚至崩溃,所以验证字节码是 **Java虚拟机保护自身** 的一项必要措施。...四个阶段: 文件格式验证 : 要验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理 主要目的 是保证输入的字节流能正确地解析并存储于方法区之内,格式上符合描述一个Java类型信息的要求...初始化 在编译生成class文件时,会自动产生两个方法,一个是类的初始化方法clinit(), 另一个是实例的初始化方法init() clinit():在jvm第一次加载class文件时调用,包括静态变量初始化语句和静态块的执行...类与类加载器 对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。...这句话可以表达得更通俗一些: 比较两个类是否“相等” ,只有在这两个类是 由同一个类加载器加载的前提下 才有意义,否则,即使这两个类来源于同一个 Class文件,被同一个Java虚拟机加载, 只要加载它们的类加载器不同

    71300

    Java虚拟机

    Java虚拟机如果不检查输入的字节流,对其完全信任的话,很可能会因为载入了有错误或有恶意企图的字节码流而导致整个系统受攻击甚至崩溃,所以验证字节码是 **Java虚拟机保护自身** 的一项必要措施。...四个阶段: 文件格式验证 : 要验证字节流是否符合Class文件格式的规范,并且能被当前版本的虚拟机处理 主要目的 是保证输入的字节流能正确地解析并存储于方法区之内,格式上符合描述一个Java类型信息的要求...初始化 在编译生成class文件时,会自动产生两个方法,一个是类的初始化方法clinit(), 另一个是实例的初始化方法init() clinit():在jvm第一次加载class文件时调用,包括静态变量初始化语句和静态块的执行...类与类加载器 对于任意一个类,都必须由加载它的类加载器和这个类本身一起共同确立其在Java虚拟机中的唯一性,每一个类加载器,都拥有一个独立的类名称空间。...这句话可以表达得更通俗一些: 比较两个类是否“相等” ,只有在这两个类是 由同一个类加载器加载的前提下 才有意义,否则,即使这两个类来源于同一个 Class文件,被同一个Java虚拟机加载, 只要加载它们的类加载器不同

    63720

    JUC学习笔记——共享模型之内存

    我们查看上述代码,会感觉所有内容都毫无疏漏,但是如果是多线程情况下,出现线程的指令重排就会导致错误产生: /*源代码展示*/ 0: getstatic #2 // Field INSTANCE:Lcn...,导致21,24交换位置,就会导致先进行赋值,再去创建对象 这时 t1 还未完全将构造方法执行完毕,如果在构造方法中要执行很多初始化操作,那么 t2 拿到的是将是一个未初始化完毕的单例 如果同时我们的...t2线程去运行,就会导致直接调用那个未初始化完毕的单例,会导致很多功能失效!...没有对init设置锁,可能会导致同时有多个线程调用,导致多次创造 t1进入,判断未初始化,进行doInit(),t2进入,判断未初始化,也进行doInit(),然后两者才进行initialized=true...(懒汉式,由于初始化方法是在该对象第一次调用时才初始化,同样是属于类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建) 2.

    28420

    《七周七并发模型》阅读笔记(一)一、线程与锁——第一天二、线程与锁——第二天三、线程与锁——第三天

    1、知识点 线程与锁模型会带来三个主要的危害:竞态条件、死锁和内存可见性,本节提供了一些避免这些危害的准则: 对共享变量的所有访问都需要同步化;(竞态条件) 读线程和写线程都需要同步化;(内存可见性)...(1)JVM在类的初始化阶段(即在Class被加载后,且被线程使用之前),会执行类的初始化。在执行类的初始化期间,JVM会去获取一个锁。这个锁可以同步多个线程对同一个类的初始化。...而且,所有可以通过正确构造的对象的 final 字段可及的变量,如用一个 final 字段引用的对象的 final 字段,也保证对其他线程是可见的。...(1)程晓明的这篇文章——双重检查锁定与延迟初始化讲得十分清楚,关键在于:指令重排序导致在多线程情况下,其他线程可能访问到未初始化的对象。...2、自习 ReentrantLock创建时可以设置一个描述公平性的变量。什么是“公平”的锁?何时适合使用公平锁?使用非公平的锁会怎样?

    65420

    Java IAQ:很少被回答的问题

    不过如果C是被final修饰的,那每次都会返回c是成立的。 Q:我自定义了一个equals方法,但是Hashtable忽略了它,为什么? 想要完全理解equals函数实际上是很难的。...如果你所处理的类不是被final修饰的,那么它有可能成为其它类的父类,此时作为一个良民,你会想要善待你的子类。...为什么Properties还用继承处理呢?因为Java的实现团队追求简洁的代码,而且他们太匆忙了。 Q:为什么Java里没有全局变量?...其中的内容是这样的:头信息占用了两个字大小,一个字指向了对象所属的类,另一个字指向了实例的变量。即使Object没有实例变量,Java也会为其分配一字大小的空间。...不复存在的是程序员失去了对结构体/类分配在堆或栈中的选择权。在Java中,所有对象都被分配到堆中,这就是为什么指针不需要语法标记符(如*)——在Java中,如果它是一个对象的引用,那它就是指针。

    62220

    Java 多线程(5)---- 线程的同步(下)

    这个其实就是 volatile 的第一个作用:保证其修饰变量在不同线程之间的可见性。 为什么会有这个规律呢?...可是一切并不是那么顺利,结果远小于 100000,我们来分析一下原因:我们在 Java 多线程(3)— 线程的同步(上) 这篇文章中已经分析过了 a--; 操作的字节码,同样的道理,我们也可以得出在这段代码中...普通的变量仅仅会保证在该方法执行的过程中所有依赖赋值的结果的地方都会得到正确的结果。但是在单线程中我们无法直接感知到这一点。...然而在多线程执行的情况下,指令重排可能会导致一些预期之外的情况。...引用不为 null,于是会直接返回 singleTon 指向的对象,但此时明显 singleTon 所指向的对象还未初始化完成(未执行完成 invokespecial 指令),那么这样的话线程 2 就很有可能返回了一个异常的

    57141

    了解final关键字在Java并发编程领域的作用吗?

    为什么是必须的使用final是所谓的安全发布(safe publication)的一种方式,这里 发布(publication)意味着在一个线程中创建它,同时另一个线程在之后的某时刻可以引用到该新创建的对象...而final域变量b,根据重排序规则,会禁止final修饰的变量b重排序到构造函数之外,从而b能够正确赋值,线程B就能够读到final变量初始化后的值。...因此,写final域的重排序规则可以确保:在对象引用为任意线程可见之前,对象的final域已经被正确初始化过了,而普通域就不具有这个保障。...比如在上例,线程B有可能就是一个未正确初始化的对象finalDemo。...具体是否插入还是得看是什么处理器“溢出”带来的重排序问题上面对final域写重排序规则可以确保:在使用一个对象引用的时候该对象的final域已经在构造函数被初始化过了。

    11810

    ​JMM中的final关键字解析

    写final域的重排序规则可以确保:在对象引用为任意线程可见之前,对象的final域已经被正确初始化过了,而普通域不具有这个保障。...而读final域的重排序规则会把读对象final域的操作“限定”在读对象引用之后,此时该final域已经被A线程初始化过了,这是一个正确的读取操作。...在这个示例程序中,如果该引用不为null,那么引用对象的final域一定已经被A线程初始化过了。...为什么final引用不能从构造函数内“逸出” 前面我们提到过,写final域的重排序规则可以确保:在引用变量为任意线程可见之前,该引用变量指向的对象的final域已经在构造函数中被正确初始化过了。...即使这里的操作2是构造函数的最后一步,且即使在程序中操作2排在操作1后面,执行read()方法的线程仍然可能无法看到final域被初始化后的值,因为这里的操作1和操作2之间可能被重排序。

    62720

    Android 团队宣布 Android 开源项目(AOSP),已支持 Rust 语言来开发 Android 系统本身

    最有效的内存安全检测技术,其一个关键限制是:为了检测到错误状态,必须在代码中实际触发错误状态。即使在具有出色的 test/fuzz 覆盖的代码库中,这也会导致许多错误未被发现。...这些步骤都很昂贵,缺少其中任何一个,都可能导致某些或所有用户无法对 bug 进行调度。...在标准库中,有更好的错误处理方式——在结果中,包装可能失败的调用,这会导致编译器要求用户检查失败原因,甚至是没有返回所需值的函数。...这可以防止诸如 Rage Against the Cage 漏洞之类的 bug,该漏洞即是由未处理的错误导致的。 初始化赋值——要求在使用前,初始化所有变量。...但是,初始化为零并不总是安全的,特别是对于返回值这样的情况,这可能成为错误处理的新来源。Rust 要求每个变量在使用前,都初始化为其类型的合法成员,避免了无意中初始化为不安全值的问题。

    1.8K20

    Java面试官最爱问的volatile关键字

    在Java内存模型中有序性可归纳为这样一句话:如果在本线程内观察,所有操作都是有序的,如果在一个线程中观察另一个线程,所有操作都是无序的。 有序性是指对于单线程的执行代码,执行是按顺序依次进行的。...只有在做读取操作时,发现自己缓存行无效,才会去读主存的值,而线程A的读取操作在线程B写入之前已经做过了,所以这里线程A只能继续做自增了。...具体来说就是synchronized虽然保证了原子性,但却没有保证指令重排序的正确性,会出现A线程执行初始化,但可能因为构造函数里面的操作太多了,所以A线程的instance实例还没有造出来,但已经被赋值了...而B线程这时过来了(代码1操作,发现instance不为null),错以为instance已经被实例化出来,一用才发现instance尚未被初始化。...其实,不仅面试如此,在学习知识时也可以参考这种面试思维,多问几个为什么。将一个点,通过为什么拓展成一个知识网。 原文链接:《Java面试官最爱问的volatile关键字》

    70521
    领券