首页编程java编程为什么javax不能解析 java一般怎么学习呢

为什么javax不能解析 java一般怎么学习呢

编程之家2023-10-1298次浏览

大家好,今天来为大家解答为什么javax不能解析这个问题的一些问题点,包括java一般怎么学习呢也一样很多人还不知道,因此呢,今天就来为大家分析分析,现在让我们一起来看看吧!如果解决了您的问题,还望您关注下本站哦,谢谢~

给讲讲java接口的概念!

希望你仔细阅读。对初学者来说,接口不是很好理解。我教过的学生也都提出过这个问题。

我们来看一个类

class A{

private int a;

public int getA(){

return a;

}

}

这个类的属性是私有的,外界不能访问,而外界可以通过公有方法来访问这个类。我们说一个类的公有方法就是这个类的对外接口。通常

一个类的属性都是私有的,方法大多是公有的。外界只能过个这些公有方法来访问类。这也是Java封装性的体现。如果一个类没有公有属性,

也没有公有方法,这个类就是无法使用的类了。所以我们需要为一个类提供对外接口。

一个类中的方法,不只是说明了它要“做什么”,而且方法的内容也说明了“怎么做”。打个不太恰当的例子,一个杀人方法。从名字上

看,你知道了“做什么”,但没有办法看到“怎么做”。而方法的内容说明了“怎么做”。

class killer{

private String name;

private int age;

private String phone;

private String addr;

......

public void kill(Person p){

Qiang qiang= new Qiang("ak47");

qiang.fire(p);

}

}

这个类的kill方法内容说明了杀人的过程。如果你不想用这种方式杀人。因为你很BT,你想用毒药杀人。那么这个类的内容就需要改。但

是,还有很多其它的“客户”,需要用不同的方式杀人。怎么办呢?一个很好的办法就是,我们只定义“做什么”,而不定义“怎么做”。

interface Killer{

public void kill(Person p);

}

接口说明了“做什么”,而实现这个接口的类,也就是实现类需要说明“怎么做”。

class Killer1 implements Killer{

public void kill(Person p){

Qiang qiang= new Qiang("ak47");

qiang.fire(p);

}

}

class Killer2 implements Killer{

public void kill(Person p){

Bane bane= new Bane();

p.eat(bane);

}

}

public class Test{

public static void main(String[] args){

Killer jingKe= new Killer1();

Person yingZheng= new Person();

jingKe.kill(yingZheng);

}

}

接口可以把“做什么”和“怎么做”分离开来。这给Java带来了很多好处。虽然代码量增加了,可我们的程序的可维护性加强了。我们的程序是可以拆分的。就象电脑一样,可以拆分成很多组件。我一直在想,如果我的MP3耳机可以拆分就好了,那样在耳机只坏掉一个的时候就不用重新买一个了。

不过上面的例子看不到什么太大的好处。你可能会说,如果你

的目的是为了不修改代码,那么,如果我想使用Killer2来完成任务,还是需要修改main方法为:Killer jingKe= new Killer2();。没有错,

不过你可以通过一个工厂来完成上面的任务。也就是说,不通过new语句来获得Killer对象,而是通过工厂来获得Killer对象。

public class KillerFactory{

public static killer getKiller(){

return new Killer1();

}

public static Killer getKiller(String path) throws Exception{

Properties prop= new Properties();

prop.load(new FileInputStream(path));

String className= prop.getProperty("killer");

Class clazz= Class.forName(className);

return(Killer)clazz.newInstance();

}

}

代码确实增加了很多,可是这对后期的系统维修和系统升级带来了很多好处。

水龙头与出水管的关系,我们需要把水龙头安装到出水管上。如果有一天我们需要更换水龙头时,只需要把老的水龙头拆卸下来,把新的

水龙头安装到出水管上既可。如果水龙头与出水管是一体的,就是无法拆卸的怎么办呢?或是说出水管只能安装水龙头,而不能安装淋浴器,

这就使我们生活很不方便。我们可以理解为出水管的连接方法,连接的对象是“出水设备”,而这个“出水设备”是一个接口。而水龙头与淋

浴器都是这个接口的实现类。但是接口在哪里呢?它长什么样子?我们没看到。它是一个标准,连接处的内径与外径。螺丝抠的密度等。这就

和你的电脑上为什么可以连接USB设备一样。如果电脑和某一个USB设备电焊到一起,那么其它的USB设备就无法使用了。电脑使用的是实现了

USB接口的电子设备,而我们的U盘、MP3、移动硬盘及鼠标都是USB接口的实现类。

用Java写出来的程序也和我们现实生活中的设备一样。如电脑,我们希望电脑的所有部件都可以更换,如果主板上的内存插槽与内存条不

附。我们说,内存条没有实现某某接口。Java是完全面向对象的,而面向对象是我们最为熟悉的东东。面向对象并不简单,而是我们太熟悉它

了。所以我们学习Java会很方便。在现实社会中,所有的标准到了Java中都是接口。一盒香烟多少支烟,烟的长度等都是标准。一个光盘的大

小。Java中的JDBC就是一个标准,而各大数据库厂商及第三方厂商实现了这一标准。JDBC只说明了目的,没有说明怎么完成的目的。

面向对象就在我们眼前,不过我们有时不太注意它。希望你在今后学习Java时,多与现实社会联系。这样可以有利与你的理解。

代码量加大了,但对后期的维护与升级提供了方便。软件公司卖给客户的是class文件,而不是java文件。如果你的客户需要更换Killer对

象,只需修改资源文件既可。

下面我们来看一个定时器类。现在什么都是自动化的,如空调、电视、洗衣机等等。都要用到定时器这个类。对了,还有定时炸弹也要用

它。那我们可不可以只写一个定时器类,应用到所有的需要定时器的设备上呢?答案是肯定的,我们需要这个类。

好了,我们来分析一下定时器需要完成什么工作吧。定时器应该有启动、停止方法。定时器启动之后,每过一定时间就执行某个动作。其

中时间间隔为long型,而要执行的动作可能是输出一个字符串,也可能是打印作业。具体要干什么由使用定时器的用户来完成。而定义定时器

时,根本就不知道要干什么。

public class Timmer{

private long time;

private Action action;

public Timmer(){}

public Timmer(long time, Action action){

this.time= time;

this.action= action;

}

public void start(){

state= START;

if(th== null){

th= new Thread(){

public void run(){

while(state== START){

try{

Thread.sleep(time);

action.action();

} catch(Exception e){

}

}

}

};

}

th.start();

}

public void stop(){

state= STOP;

}

public void setTime(long time){

this.time= time;

}

public void setAction(Action action){

this.action= action;

}

public long getTime(){

return(this.time);

}

public Action getAction(){

return(this.action);

}

}

Action是一个接口,它只有一个方法,就是要完成的任务。我们在定时器启动时调用这个接口的方法。而这个Action接口的对象,代表一

个动作,这个动作就是用户要完成的动作。

public interface Action{

public void action();

}

public static void main(String[] args){

Timer t= new Timer(2000, new Action(){

public void action(){

System.out.println("Hello World!");

}

});

t.start();

javax.swing.JOptionPane.showMessageDialog(null,"点击确定按钮停止定时器");

t.stop();

System.exit(0);

}

这是一个典型的回调方法例子。在AWT中,java使用了大量的监听器。这些监听器都是回调方法。在XML解析器SAX中,也使用了回调方法来解析XML文档。

接口要比抽象类还要抽象。抽象类需要子类继承,而Java是单继承,所以抽象类被限制了。而接口不同,一个类可以实现多个接口。好比人类与程序员类之间的关系。可以说程序员是人类的子类,如果程序员是一个接口。用人类的子类来实现它就会更好。这个子类还可以去实现会计接口、音乐家接口等等。

在struts2.0、spring、hibernate等框架中,都大量使用接口。我们关心的是某个接口与另一个接口之间的关系。而不关心某个实现类与另一个接口实现类的关系。在客观世界中,我们交谈时都大量使用接口,只是我们没有注意罢了。如:我公司需要一个程序员(一个实现了程序员接口的对象)。上课时,讲师有一台计算机,用白板笔在白板上写字(计算机是接口,白板及白板笔也是接口)。讲师希望学生能学会所有的知识(讲师及学生都是接口)。

就说这么多了,还有什么不明白可以与我联系。QQ:51038648

我在北京中科院计算所培训中心做兼职java讲师。我的经验是,要想学好Java,一定要多打代码、吃透代码。如果不勤奋,就一定学不好。看来你是刚刚开始学习Java,你后面的路还很长,而且不是很好走。

java一般怎么学习呢

工资高不一定你就能够学会,如果谁都能学会那他工资还有这么高吗

如果实在想学,建议你先去网上找找视频看看Java了再去学

Java学习路线:

JavaSE->数据库->JDBC->前端基础->JQuery->JavaWEB->Spring->MyBatis->Maven->SpringBoot->SpringCloud->Redis->Git->Linux

整体教程目录:

项目源码:

微服务项目:

项目优化:

Linux:

阶段1 java语言基础

1-1-Java基础语法

1、第1节 java运行环境提取码:8ax6

2、第2节 HelloWorld案例提取码:us3j

3、第3节关键字&标识符提取码:13dl

4、第4节常量&变量提取码:6331

5、第5节数据类型转换提取码:9glo

6、第6节运算符提取码:ys2n

7、第7节方法入门提取码:b1ib

8、第8节 JDK9新特性-Jshell提取码:ounw

9、第9节选择结构-if语句-switch语句提取码:0d14

10、第10节循环结构-for-while-do..while提取码:k2ig

11、第11节开发工具-IDEA提取码:404i

12、第12节方法复习提取码:ulku

13、第13节方法重载提取码:wfkr

14、第14节数组提取码:p8ml

1-2-面向对象和封装

1、1_2_1_01_面向对象思想的概述提取码:599q

2、1_2_1_02_面向对象思想的举例提取码:lv2s

3、1_2_1_03_类和对象的关系提取码:7rs3

4、1_2_1_04_类的定义提取码:xvhx

5、1_2_1_05_对象的创建及其使用提取码:xsal

6、1_2_1_06_手机类练习提取码:lnho

7、1_2_1_07_一个对象的内存图提取码:wnaz

8、1_2_1_08_两个对象使用同一个方法的内存提取码:thet

9、1_2_1_09_两个引用指向同一个对象的提取码:3he6

10、1_2_1_10_使用对象类型作为方法的参提取码:73w4

11、1_2_1_11_使用对象类型作为方法的返提取码:gjmn

12、1_2_1_12_成员变量和局部变量的区别提取码:eqep

13、1_2_1_13_面向对象三大特征之封装性提取码:zlcz

14、1_2_1_14_private关键字的作用及使用提取码:4i77

15、1_2_1_15_练习使用private关键字定义提取码:dctu

16、1_2_1_16_this关键字的作用提取码:x68z

17、1_2_1_17_构造方法提取码:8xkz

18、1_2_1_18_定义一个标准的类提取码:opmf

1-3-Java语言高级

1、01-常用API_1提取码:alfe

2、02-继承与多态提取码:h5o7

3、03-常用API第二部分提取码:olnf

4、04-集合提取码:40ca

5、05-异常与多线程提取码:mu40

6、06-File类与IO流提取码:4bpt

7、07-网络编程提取码:s5ks

8、08-JDK8新特性提取码:jnbj

9、09-基础加强提取码:1ngz

10、10-MySQL提取码:30y4

11、11-JDBC提取码:15q7

阶段2 JavaWeb+旅游网

01 HTML和CSS

1、第1节概念介绍提取码:dal6

2、第2节基本标签提取码:4uyq

3、第3节表单标签提取码:h1ok

4、第4节 CSS概述提取码:ubyx

5、第5节 CSS_选择器提取码:zep7

6、第6节 CSS属性提取码:9l4h

7、第7节 CSS_案例-注册页面提取码:onc6

02 JavaScript

1、01 JavaScript_简介提取码:2efk

2、02 JavaScript基础语法提取码:bl89

3、03 JavaScript运算符提取码:v9sh

4、04 JavaScript特殊语法提取码:yj6p

5、05 JavaScript_语法_流程控制语提取码:tx9j

6、06 JavaScript_对象提取码:df4q

7、07 DOM和事件的简单学习提取码:ljt5

8、08 BOM对象提取码:jwwy

9、09 DOM对象提取码:ukah

10、10JavaScirpt中的事件提取码:ab1w

03 BootStrap

1、01快速入门提取码:5jhm

2、02Bootstrap_栅格系统提取码:1xuu

3、03Bootstrap_全局CSS样式提取码:fjka

4、04Bootstrap_组件和插件提取码:g5wp

5、05案例_旅游网提取码:jxy3

04 XML

1、01 xml基础提取码:jose

2、02 xml_约束提取码:q0xr

3、03 xml_解析提取码:bbsn

05 Tomcat

1、01web相关概念提取码:p2az

2、02 tomcat基本操作提取码:zqqx

3、03 tomcat_部署项目提取码:i4a2

06-Servlet和HTTP请求协议

1、01Servlet_快速入门提取码:ah8k

2、02Servlet_生命周期方法提取码:w7t9

3、03Servlet_3.0注解配置提取码:d8zy

4、04 IDEA与tomcat相关配置提取码:5rvl

5、05 Servlet_体系结构与urlpartten配置提取码:qf3i

6、06 HTTP请求协议提取码:5f7v

07-Request和Respons

1、01 Request原理和继承体系提取码:3hxr

2、02 Request_获取请求数据提取码:oxl7

3、03请求转发和request共享数据提取码:9xbq

4、04 Request_获取ServletContext提取码:yfaz

5、05 request登录案例提取码:owgj

6、06 HTTP响应协议提取码:xs8k

7、07 response之重定向提取码:i8de

8、08 response之相对路径和绝对路径提取码:6p8q

9、09 response之输出数据提取码:54fe

10、10 response之验证码提取码:uy06

11、11 ServletContext对象提取码:yopc

12、12文件下载提取码:szv9

08-Cookie和Session

1、第1节 Cookie快速入门提取码:ncss

2、第2节 Cookie_细节提取码:la7v

3、第3节 Cookie案例提取码:mamn

4、第4节 JSP改造Cookie案例提取码:fpkd

5、第5节 Session快速入门提取码:0tyf

6、第6节 Session细节提取码:obu1

7、第7节 Session之验证码案例提取码:fxtt

09-JSP,EL和JSTL

1、第1节 JSP基础语法提取码:7rvw

2、第2节 MVC提取码:ywmz

3、第3节 EL介绍和运算符提取码:5gxf

4、第4节 EL获取域中存储的数据提取码:yha0

5、第5节 JSTL常用标签提取码:mr92

10-综合案例(用户信息)

1、第1节登录功能提取码:d7v4

2、第2节添加删除修改功能提取码:40df

3、第3节删除选中功能提取码:jhlx

4、第4节分页查询功能提取码:8mxb

5、第5节复杂条件查询功能提取码:qj8m

11-Filter和Listener

1、第1节 Filter快速入门提取码:7qrm

2、第2节 Filter细节提取码:s2w9

3、第3节 Filter案例提取码:f53s

4、第4节监听器提取码:kjwy

12-Jquery

1、第1节 JQuery基础提取码:0uj1

2、第2节 JQuery选择器提取码:o85w

3、第3节 Jquery基础案例提取码:5u3t

4、第4节 JQuery动画和遍历提取码:ut21

5、第5节 JQuery事件绑定和切换提取码:e5sv

6、第6节 Jquery高级案例提取码:ytj4

13-Ajax和JSON

1、第1节原生JS方式实现Ajax提取码:xh70

2、第2节 JQuery方式实现Ajax提取码:woaa

3、第3节 JSON基础语法提取码:pqhj

4、第4节 JSON_解析器提取码:zbzx

14-Redis

1、第1节 Redis环境搭建提取码:poob

2、第2节 Redis命令操作提取码:bq6d

3、第3节 Redis持久化提取码:0x4x

4、第4节 Jedis代码操作提取码:bon3

5、第5节 Jedis连接池提取码:hu0n

6、第6节 redis案例提取码:cosn

15-Maven基础

1、第1节基本概念提取码:4fok

2、第2节 maven的安装和仓库种类提取码:gw1r

3、第3节 maven标准目录结构和常用命令提取码:3jn7

4、第4节 maven生命周期和概念模型图提取码:oqrb

5、第5节使用骨架创建maven的java工程提取码:k26p

6、第6节 maven工程servlet实例提取码:xdmw

16-旅游网

1、01准备工作提取码:uprl

2、02注册功能提取码:9pf5

3、03登陆和退出功能提取码:0hkk

4、04 BaseServlet抽取提取码:qswt

5、05分类数据展示功能提取码:649n

6、06旅游线路分页展示分页展示提取码:o6v6

7、07旅游线路查询提取码:pzjb

8、08旅游线路详情提取码:wtke

9、09旅游线路收藏提取码:3236

阶段3 1.Mybatis

1、01.Mybatis课程介绍及环境搭建提取码:6zwc

2、02.Mybatis入门案例提取码:2aoi

3、03.自定义Mybatis框架提取码:r9wc

4、04.自定义Mybatis框架基于注解开发提取码:1jzg

5、05.使用Mybatis完成CRUD提取码:d4b7

6、06.使用Mybatis完成DAO层的开发提取码:dzvr

7、07.Mybatis的连接池及事务提取码:ij3e

8、08.动态SQL提取码:yiys

9、09.Mybatis的多表操作提取码:dt9w

10、10.JNDI扩展知识提取码:u5fx

11、11.Mybatis的缓存提取码:ng54

12、12.Mybatis注解开发提取码:yh6z

阶段3 2.Spring

1、01.Spring框架简介提取码:va1x

2、02.程序间耦合提取码:s8cg

3、03.Spring的 IOC和 DI提取码:59of

4、04.Spring的常用注解提取码:tfw5

5、05.基于XML的IOC的案例1提取码:1gf9

6、06.Spring的新注解提取码:pjzs

7、07.银行转账案例提取码:um2b

8、08.面向切面编程 AOP提取码:4tv2

9、09.JdbcTemplate的基本使用提取码:vjxx

10、10.Spring中事务控制提取码:rx3v

阶段3 3.SpringMVC

1、01.SpringMVC概述及入门案例提取码:e2ty

2、02.参数绑定及自定义类型转换提取码:657g

3、03.SpringMVC常用注解提取码:emrc

4、04.SpringMVC返回值类型及响应数据类型提取码:bd9t

5、05.文件上传提取码:pzy7

6、06.异常处理及拦截器提取码:7a2y

7、07.SSM整合案例提取码:lzzd

阶段4 3.Spring Data JPA

1、01.JAP的引入提取码:o61r

2、02.JPA的入门案例提取码:ld9u

3、03.主键生成策略提取码:f8ri

4、04.JPA的基本操作提取码:yxcv

5、05.JPQL查询提取码:cxwq

6、06.spring data jpa简介提取码:678v

7、07.入门案例提取码:2u3l

8、08.执行过程分析提取码:upe4

9、09.spring data jpa查询提取码:smsc

10、10.动态查询提取码:qoxx

11、11.多表操作-一对多提取码:fai2

12、12.多表操作-多对多提取码:bvvg

13、13.对象导航查询提取码:ietq

阶段4 4.Spring Boot

1、01.spring boot介绍提取码:fzi8

2、02.spring boot入门提取码:bp25

3、03.spring boot原理分析提取码:8yer

4、04.spring boot配置文件提取码:wvoc

5、05.spring boot集成提取码:ywin

阶段4 5.Git

1、01.Git简介及安装使用提取码:a0kx

2、02.连接远程仓库提取码:kziq

3、03.Git分支提取码:5rm2

原文链接:https://zhuanlan.zhihu.com/p/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>

以下是对不同使用场景的说明:

@NonNull

private 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进行注解,这样就能强制调用方对空指针异常进行预防,让我们的程序更为健壮。

为什么javax不能解析和java一般怎么学习呢的问题分享结束啦,以上的文章解决了您的问题吗?欢迎您下次再来哦!

java的环境变量是什么意思?配置java环境变量的作用是什么爱新觉罗启笛 爱新觉罗启笛和启星