java中什么是空指针异常(什么是空指针异常)
各位老铁们,大家好,今天由我来为大家分享java中什么是空指针异常,以及什么是空指针异常的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!
关于java中空指针异常
空指针异常产生的主要原因如下:
(1)当一个对象不存在时又调用其方法会产生异常obj.method()// obj对象不存在
(2)当访问或修改一个对象不存在的字段时会产生异常obj.method()// method方法不存在
(3)字符串变量未初始化;
(4)接口类型的对象没有用具体的类初始化,比如:
List lt;会报错
List lt= new ArrayList();则不会报错了
当一个对象的值为空时,你没有判断为空的情况。你可以试着把下面的代码前加一行代码:
if(rb!=null&& rb!="")
改成:
if(rb==null);
if(rb!==null&&rb!="")或者if((“”).equals(rb))
空指针的解决办法:
重点关注报错发生的所在行,通过空指针异常产生的两条主要原因诊断具体的错误。同时为了避免空指针的发生,最好在做判断处理时将“null”或者空值放于设定的值之前。
什么是空指针异常
所谓的空指针异常,就是一个指针是空指针,你还要去操作它,既然它指向的是空对象,它就不能使用这个对象的方法。比如上面的s假如为null,你还要用s的方法,比如s.equals( String x);那么就会产生空指针异常。
产生空指针异常的原因:
(1) 当一个对象不存在时又调用其方法会产生异常 obj.method() // obj对象不存在
(2) 当访问或修改一个对象不存在的字段时会产生异常 obj.method() // method方法不存在
扩展资料:空指针正常工作意义:
在许多语言,这不是一个单独的转义序列,而是八进制转义序列,单个八进制数字为0;因此,‘\0’不能跟随任何数字0通过7;否则它被解释为更长的八进制转义序列的开始。被在使用中发现各种语言的其他转义序列\000,\x00,\z,或的Unicode表示\u0000。
表示空字符的能力并不总是意味着生成的字符串将被正确解释,因为许多程序将认为null作为字符串的结尾。因此,键入它的能力(在未经检查的用户输入的情况下)会创建一个称为空字节注入的漏洞,并可能导致安全漏洞。
空字符以逗号表示是^@。在Windows上,可以通过按住Ctrl键,然后按@(这通常需要同时按下⇧ Shift并按下数字2键)。
参考资料:百度百科——空指针java中的空指针异常怎么解决
原文:https://www.zhihu.com/question
你这个问题的解决
问题定位:
在堆栈异常信息的第一行就可以定位到是哪里出了空指针,倘若这里不是你写的类,可以往下翻一下,找到你写的类,就是这里出现的空指针。
问题解决:
对一个空对象调用里面的方法或者属性的时候会报空指针,检查这个对象为什么是空即可。
Java空指针异常的若干解决方案
Java中任何对象都有可能为空,当我们调用空对象的方法时就会抛出 NullPointerException空指针异常,这是一种非常常见的错误类型。我们可以使用若干种方法来避免产生这类异常,使得我们的代码更为健壮。本文将列举这些解决方案,包括传统的空值检测、编程规范、以及使用现代 Java语言引入的各类工具来作为辅助。
运行时检测
最显而易见的方法就是使用 if(obj== null)来对所有需要用到的对象来进行检测,包括函数参数、返回值、以及类实例的成员变量。当你检测到 null值时,可以选择抛出更具针对性的异常类型,如 IllegalArgumentException,并添加消息内容。我们可以使用一些库函数来简化代码,如 Java 7开始提供的 Objects#requireNonNull方法:
public void testObjects(Object arg){
Object checked= Objects.requireNonNull(arg,"arg must not be null");
checked.toString();}
Guava的 Preconditions类中也提供了一系列用于检测参数合法性的工具函数,其中就包含空值检测:
public void testGuava(Object arg){
Object checked= Preconditions.checkNotNull(arg,"%s must not be null","arg");
checked.toString();
}
我们还可以使用 Lombok来生成空值检测代码,并抛出带有提示信息的空指针异常:
public void testLombok(@NonNull Object arg){
arg.toString();
生成的代码如下:
public void testLombokGenerated(Object arg){
if(arg== null){
throw new NullPointerException("arg is marked@NonNull but is null");
}
arg.toString();
}
这个注解还可以用在类实例的成员变量上,所有的赋值操作会自动进行空值检测。
编程规范
·通过遵守某些编程规范,也可以从一定程度上减少空指针异常的发生。
使用那些已经对 null值做过判断的方法,如 String#equals、String#valueOf、以及三方库中用来判断字符串和集合是否为空的函数:
if(str!= null&& str.equals("text")){}
if("text".equals(str)){}
if(obj!= null){ obj.toString();}
String.valueOf(obj);//"null"
// from spring-core
StringUtils.isEmpty(str);
CollectionUtils.isEmpty(col);
// from guava
Strings.isNullOrEmpty(str);
// from commons-collections4
CollectionUtils.isEmpty(col);
·如果函数的某个参数可以接收 null值,考虑改写成两个函数,使用不同的函数签名,这样就可以强制要求每个参数都不为空了:
public void methodA(Object arg1){
methodB(arg1, new Object[0]);
}
public void methodB(Object arg1, Object[] arg2){
for(Object obj: arg2){}// no null check
}
·如果函数的返回值是集合类型,当结果为空时,不要返回 null值,而是返回一个空的集合;如果返回值类型是对象,则可以选择抛出异常。Spring JdbcTemplate正是使用了这种处理方式:
//当查询结果为空时,返回 new ArrayList<>()
jdbcTemplate.queryForList("SELECT* FROM person");
//若找不到该条记录,则抛出 EmptyResultDataAccessException
jdbcTemplate.queryForObject("SELECT age FROM person WHERE id= 1", Integer.class);
//支持泛型集合
public<T> List<T> testReturnCollection(){
return Collections.emptyList();
}
静态代码分析
Java语言有许多静态代码分析工具,如 Eclipse IDE、SpotBugs、Checker Framework等,它们可以帮助程序员检测出编译期的错误。结合@Nullable和@Nonnull等注解,我们就可以在程序运行之前发现可能抛出空指针异常的代码。
但是,空值检测注解还没有得到标准化。虽然 2006年 9月社区提出了 JSR 305规范,但它长期处于搁置状态。很多第三方库提供了类似的注解,且得到了不同工具的支持,其中使用较多的有:
javax.annotation.Nonnull:由 JSR 305提出,其参考实现为 com.google.code.findbugs.jsr305;
org.eclipse.jdt.annotation.NonNull:Eclipse IDE原生支持的空值检测注解;
edu.umd.cs.findbugs.annotations.NonNull:SpotBugs使用的注解,基于 findbugs.jsr305;
org.springframework.lang.NonNull:Spring Framework 5.0开始提供;
org.checkerframework.checker.nullness.qual.NonNull:Checker Framework使用;
android.support.annotation.NonNull:集成在安卓开发工具中;
我建议使用一种跨 IDE的解决方案,如 SpotBugs或 Checker Framework,它们都能和 Maven结合得很好。
SpotBugs与@NonNull、@CheckForNull
SpotBugs是 FindBugs的后继者。通过在方法的参数和返回值上添加@NonNull和@CheckForNull注解,SpotBugs可以帮助我们进行编译期的空值检测。需要注意的是,SpotBugs不支持@Nullable注解,必须用@CheckForNull代替。如官方文档中所说,仅当需要覆盖@ParametersAreNonnullByDefault时才会用到@Nullable。
官方文档中说明了如何将 SpotBugs应用到 Maven和 Eclipse中去。我们还需要将 spotbugs-annotations加入到项目依赖中,以便使用对应的注解。
<dependency><groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<version>3.1.7</version>
</dependency>
以下是对不同使用场景的说明:
@NonNullprivate Object returnNonNull(){
//错误:returnNonNull()可能返回空值,但其已声明为@Nonnull
return null;
}
@CheckForNull
private Object returnNullable(){
return null;
}
public void testReturnNullable(){
Object obj= returnNullable();
//错误:方法的返回值可能为空
System.out.println(obj.toString());
}
private void argumentNonNull(@NonNull Object arg){
System.out.println(arg.toString());
}
public void testArgumentNonNull(){
//错误:不能将 null传递给非空参数
argumentNonNull(null);
}
public void testNullableArgument(@CheckForNull Object arg){
//错误:参数可能为空
System.out.println(arg.toString());
}
对于 Eclipse用户,还可以使用 IDE内置的空值检测工具,只需将默认的注解 org.eclipse.jdt.annotation.Nullable替换为 SpotBugs的注解即可:
Checker Framework与@NonNull、@Nullable
Checker Framework能够作为 javac编译器的插件运行,对代码中的数据类型进行检测,预防各类问题。我们可以参照官方文档,将 Checker Framework与 maven-compiler-plugin结合,之后每次执行 mvn compile时就会进行检查。Checker Framework的空值检测程序支持几乎所有的注解,包括 JSR 305、Eclipse、甚至 lombok.NonNull。
import org.checkerframework.checker.nullness.qual.Nullable;@Nullable
private Object returnNullable(){
return null;
}
public void testReturnNullable(){
Object obj= returnNullable();
//错误:obj可能为空
System.out.println(obj.toString());
}
Checker Framework默认会将@NonNull应用到所有的函数参数和返回值上,因此,即使不添加这个注解,以下程序也是无法编译通过的:
private Object returnNonNull(){//错误:方法声明为@NonNull,但返回的是 null。
return null;
}
private void argumentNonNull(Object arg){
System.out.println(arg.toString());
}
public void testArgumentNonNull(){
//错误:参数声明为@NonNull,但传入的是 null。
argumentNonNull(null);
}
Checker Framework对使用 Spring Framework 5.0以上的用户非常有用,因为 Spring提供了内置的空值检测注解,且能够被 Checker Framework支持。一方面我们无需再引入额外的 Jar包,更重要的是 Spring Framework代码本身就使用了这些注解,这样我们在调用它的 API时就能有效地处理空值了。举例来说,StringUtils类里可以传入空值的函数、以及会返回空值的函数都添加了@Nullable注解,而未添加的方法则继承了整个框架的@NonNull注解,因此,下列代码中的空指针异常就可以被 Checker Framework检测到了:
//这是 spring-core中定义的类和方法public abstract class StringUtils{
// str参数继承了全局的@NonNull注解
public static String capitalize(String str){}
@Nullable
public static String getFilename(@Nullable String path){}
}
//错误:参数声明为@NonNull,但传入的是 null。
StringUtils.capitalize(null);
String filename= StringUtils.getFilename("/path/to/file");
//错误:filename可能为空。
System.out.println(filename.length());
Optional类型
Java 8引入了 Optional<T>类型,我们可以用它来对函数的返回值进行包装。这种方式的优点是可以明确定义该方法是有可能返回空值的,因此调用方必须做好相应处理,这样也就不会引发空指针异常。但是,也不可避免地需要编写更多代码,而且会产生很多垃圾对象,增加 GC的压力,因此在使用时需要酌情考虑。
Optional<String> opt;//创建
opt= Optional.empty();
opt= Optional.of("text");
opt= Optional.ofNullable(null);
//判断并读取
if(opt.isPresent()){
opt.get();
}
//默认值
opt.orElse("default");
opt.orElseGet(()->"default");
opt.orElseThrow(()-> new NullPointerException());
//相关操作
opt.ifPresent(value->{
System.out.println(value);
});
opt.filter(value-> value.length()> 5);
opt.map(value-> value.trim());
opt.flatMap(value->{
String trimmed= value.trim();
return trimmed.isEmpty()? Optional.empty(): Optional.of(trimmed);
});
方法的链式调用很容易引发空指针异常,但如果返回值都用 Optional包装起来,就可以用 flatMap方法来实现安全的链式调用了:
String zipCode= getUser().flatMap(User::getAddress)
.flatMap(Address::getZipCode)
.orElse("");
Java 8 Stream API同样使用了 Optional作为返回类型:
stringList.stream().findFirst().orElse("default");stringList.stream()
.max(Comparator.naturalOrder())
.ifPresent(System.out::println);
此外,Java 8还针对基础类型提供了单独的 Optional类,如 OptionalInt、OptionalDouble等,在性能要求比较高的场景下很适用。
其它 JVM语言中的空指针异常
Scala语言中的 Option类可以对标 Java 8的 Optional。它有两个子类型,Some表示有值,None表示空。
val opt: Option[String]= Some("text")opt.getOrElse("default")
除了使用 Option#isEmpty判断,还可以使用 Scala的模式匹配:
opt match{case Some(text)=> println(text)
case None=> println("default")
Scala的集合处理函数库非常强大,Option则可直接作为集合进行操作,如 filer、map、以及列表解析(for-comprehension):
opt.map(_.trim).filter(_.length> 0).map(_.toUpperCase).getOrElse("DEFAULT")val upper= for{
text<- opt
trimmed<- Some(text.trim())
upper<- Some(trimmed) if trimmed.length> 0
} yield upper
upper.getOrElse("DEFAULT")
Kotlin使用了另一种方式,用户在定义变量时就需要明确区分可空和不可空类型。当可空类型被使用时,就必须进行空值检测。
var a: String="text"a= null//错误:无法将 null赋值给非空 String类型。
val b: String?="text"
//错误:操作可空类型时必须使用安全操作符(?.)或强制忽略(!!.)。
println(b.length)
val l: Int?= b?.length//安全操作
b!!.length//强制忽略,可能引发空值异常
Kotlin的特性之一是与 Java的可互操作性,但 Kotlin编译器无法知晓 Java类型是否为空,这就需要在 Java代码中使用注解了,而 Kotlin支持的注解也非常广泛。Spring Framework 5.0起原生支持 Kotlin,其空值检测也是通过注解进行的,使得 Kotlin可以安全地调用 Spring Framework的所有 API。
结论
在以上这些方案中,我比较推荐使用注解来预防空指针异常,因为这种方式十分有效,对代码的侵入性也较小。所有的公共 API都应该使用@Nullable和@NonNull进行注解,这样就能强制调用方对空指针异常进行预防,让我们的程序更为健壮。
文章到此结束,如果本次分享的java中什么是空指针异常和什么是空指针异常的问题解决了您的问题,那么我们由衷的感到高兴!