Fork me on GitHub

NumberFormatException(数字格式异常)

1
2
3
4
5
6
7
8
public class ExceptionTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字:");
int num = Integer.parseInt(scanner.next()); //解析控制台输入的整数
System.out.println(num);
}
}

scanner要求输入数字,并通过Integer.parseInt将参数转换为一个整数,再输出这个整数。

如果输入123,屏幕会输出123,但如果用户输入的不是数字,比如doge,屏幕会输出:

1
2
3
4
5
6
Exception in thread "main" java.lang.NumberFormatException: For input string: "doge"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at com.example.restservice.ExceptionTest.main(ExceptionTest.java:9)

出现异常NumberFormatException。

对于屏幕输出中的异常栈信息,开发者是可以理解的,但普通用户无法理解。
我们需要给用户一个更为友好的信息,告诉用户,ta应该输入的是数字。要做到这一点,我们需要自己“捕获”异常。

“捕获”是指使用try/catch关键字,捕获异常后的示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ExceptionTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字:");
String input = scanner.next();
try {
int num = Integer.parseInt(input); //解析控制台输入的整数
System.out.println(num);
} catch (NumberFormatException e) {
System.err.println("参数"+input+"不是有效的数字,请输入数字。");
}
}
}

使用try/catch捕获并处理了异常,try后面的大括号{}内包含可能抛出异常的代码,括号后的catch语句包含能捕获的异常和代理代码。

catch后面括号内是异常信息,包括异常类型和变量名,这里是NumberFormatException e。大括号{}内是处理代码,这里输出一个更为友好的提示信息。

捕获异常后,程序就不会异常退出了,但try语句内异常点之后的其他代码就不会执行了,执行完catch内的语句后,程序会继续执行catch大括号外的代码。

异常是相对于return的一种退出机制,可以由系统触发,也可以由程序通过throw语句触发。异常可以通过try/catch语句进行捕获并处理,如果没有捕获,则会导致程序退出并输出异常栈信息。

NullPointerException(空指针异常)

1
2
3
4
5
6
7
public class ExceptionTest {
public static void main(String[] args) {
String s = null;
s.indexOf("a"); //查找a在字符串s中首次出现的位置
System.out.println("end");
}
}

运行上面的代码,屏幕输出结果为:

1
2
Exception in thread "main" java.lang.NullPointerException
at com.example.restservice.ExceptionTest.main(ExceptionTest.java:4)

当运行s.indexOf(“a”)时,java系统发现s的值为null,没有办法继续执行,这时就启用异常处理机制:

首先 ,创建一个异常对象——类NullPointerException的对象,然后查找看谁能处理这个异常。在上面的代码中,没有代码能处理这个异常,java就启用默认处理机制,打印异常栈信息到屏幕,并退出程序。

java的默认异常处理机制是退出程序,异常发生点后的代码都不会执行。

枚举的典型场景

实际应用中,枚举经常会有关联的实例变量和方法。

举个栗子,假设Size的枚举值可能有关联的缩写和中文名称,可能需要静态方法根据缩写返回对应的枚举值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public enum Size {
SMALL("S","小号"),
MEDIUM("M","中号"),
LARGE("L","大号");

private String abbr;
private String title;

private Size(String abbr,String title) {
this.abbr = abbr;
this.title = title;
}

public String getAbbr() {
return abbr;
}

public String getTitle() {
return title;
}

//根据abbr返回枚举值,比如输入M返回MEDIUM
public static Size fromAbbr(String abbr) {
for (Size size : Size.values()) {
if (size.getAbbr().equals(abbr)) {
return size;
}
}
return null;
}
}

枚举值的定义需要放在最上面,枚举值写完之后,要以分号结尾,然后才能写其他代码

枚举的基本实现原理

实际上,枚举类型会被Java编译器转换为一个对应的类,这个类继承了Java API中的java.lang.Enum类。

Enum类有两个实例变量name和ordinal,在构造方法中需要传递,name(),toString(),ordinal(),compareTo(),equals()方法都是由Enum类根据其实例变量name和ordinal实现的。

values和valueOf方法是编译器给每个枚举类型自动添加的。

枚举类型Size转换后的普通类的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public final class Size extends Enum<Size> {	//final,不能被继承
public static final Size SMALL = new Size("SMALL",0);
public static final Size MEDIUM = new Size("MEDIUM",1);
public static final Size LARGE = new Size("LARGE",2);

private static Size[] VALUES =
new Size[]{SMALL,MEDIUM,LARGE};

//私有构造方法,接受name和ordinal,传递给父类。不能在外部创建新的实例。
private Size(String name, int ordinal){
super(name, ordinal);
}

public static Size[] values(){
Size[] values = new Size[VALUES.length];
System.arraycopy(VALUES, 0,
values, 0, VALUES.length);//要复制的源数组VALUES,从源数组0的位置开始复制,目标数组为values,目标数组的下标位置是0,要复制的长度是VALUES的长度
return values;
}

public static Size valueOf(String name){
return Enum.valueOf(Size.class, name);
}
}

枚举类型本质上也是类,但由于编译器自动做了很多事情,它的使用也就更为简洁、安全和方便。

枚举的好处

枚举的优点:

  • 定义枚举的语法更为简洁。
  • 枚举更为安全,一个枚举类型的变量,它的值要么为null,要么为枚举值之一,不可能为其他值。
  • 枚举类型自带很多遍历方法(如values,valueOf,toString等),易于使用。

枚举的基本用法

枚举是一种特殊的数据,它的取值是有限的,可以枚举出来的。

基本用法

举个栗子,为表示衣服的尺寸,需要定义一个枚举类型Size。Size包括三个尺寸,小/中/大。

1
2
3
public enum Size {
SMALL, MEDIUM, LARGE
}

枚举使用enum关键字来定义,Size包括三个值,分别表示小、中、大。值一般是大写的字母,多个值之间以逗号分隔

枚举类型可以定义为一个单独的文件,也可以定义在其他类内部。

使用Size:

1
Size size = Size.MEDIUM;

Size size声明了一个变量size,它的类型是Size,size=Size.MEDIUM将枚举值MEDIUM赋值给size变量。

1
2
3
Size size = Size.SMALL;
System.out.println(size.toString()); //输出SMALL
System.out.println(size.name()); //输出SMALL

枚举变量的toString方法返回其字面值(SMALL),所有枚举类型也有一个name方法,返回值与toString一样。

枚举值是有顺序的,可以比较大小。

枚举类型都有一个方法**int ordinal()**,表示枚举值在声明时的顺序,从0开始。

枚举类型都实现了Java API中的Comparable接口,都可以通过方法compareTo与其他枚举值比较ordinal的大小。

1
2
3
4
5
Size size = Size.SMALL;
System.out.println(size.ordinal()); //输出0
size = Size.MEDIUM;
System.out.println(size.ordinal()); //输出1
System.out.println(Size.SMALL.compareTo(Size.MEDIUM)); //输出-1,表示SMALL小于MEDIUM

枚举类型都有一个静态的valueOf(String)方法,可以返回字符串对应的枚举值。

1
System.out.println(Size.SMALL==Size.valueOf("SMALL")); //输出true

枚举类型都有一个静态的values方法,返回一个包括所有枚举值的数组,顺序与声明时的顺序一致。

1
2
3
for(Size size : Size.values()) {
System.out.println(size);
}

屏幕输出三行,分别是SMALL,MEDIUM,LARGE。

程序的编译与连接

从java源代码到运行的程序,有编译连接两个步骤。

编译是将源代码文件变成一种字节码,后缀是.class的文件。一般由javac(编译器)命令完成编译。

连接是在运行时动态执行的,.class文件不能直接运行,运行的是java虚拟机。虚拟机解析.class文件,转换为机器能识别的二进制代码,然后运行。所谓连接就是根据引用到的类加载相应的字节码并执行。

程序打包

可见性范围从小到大是:

private < 默认(包) < protected < public

为方便使用第三方代码,也为了方便我们写的代码给其他人使用,所以需要对代码进行打包

打包的一般不是源代码,而是编译后的代码,打包将多个编译后的文件打包为一个文件,方便其他程序调用。

在java中,编译后的一个或多个包的java class文件可以打包为一个文件,java中打包命令为jar,打包后的文件后缀为.jar,一般称之为jar包

打包方式:

首先到编译后的java class文件根目录,然后运行”jar -cvf <包名>.jar <最上层报名>”的命令打包

内部类的定义

一个类可以放在另一个类的内部,称为内部类。相对而言,包含它的类称为外部类。

一般而言,内部类与包含它的外部类有比较密切的关系,而与其他类关系不大,定义在类内部,可以实现对外部完全隐藏,可以有更好的封装性,代码实现上也往往更为简洁

内部类只是Java编译器的概念,对于java虚拟机而言,它是不知道内部类的。每个内部类最后都会被编译为一个独立的类,生成一个独立的字节码文件。

内部类可以方便地访问外部类的私有变量,可以声明为private从而实现对外完全隐藏,相关代码写在一起,写法也更为简洁。

java中主要有四种内部类:

  • 静态内部类
  • 成员内部类
  • 方法内部类
  • 匿名内部类

抽象类和接口

抽象类和接口有类似之处,它们都不能用于创建对象,接口中的方法其实都是抽象方法。如果抽象类中只定义了抽象方法,那抽象类和接口就更像了。

但抽象类和接口根本上是不同的,一个类可以实现多个接口,但只能继承一个类。

抽象类和接口是配合关系,它们经常一起使用,接口声明能力,抽象类提供默认实现,实现全部或部分方法,一个接口经常有一个对应的抽象类。

(感觉不会经常用的样子……)

  • Copyrights © 2021 Silver Shaded
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信