跟上 Java7:你忽略了的新特性

前言

Java7,代号「海豚(Dolphin)」,是 Java 历史上一次非常重大的版本更新,同时也是我入门学习 Java 所用的版本。本篇主要介绍几个很实用的 Java7 特性,文中若有用词不当或专业术语不准的现象,望见谅!

Java7 新特性:

1.二进制形式的字面值表示
2.在数值类型的字面值中使用下划线分隔符联接
3.创建泛型实例时自动类型推断
4.switch-case 语句支持字符串类型
5.新增 try-with-resources 语句
6.单个 catch 子句同时捕获多种异常类型
7.引入 java.util.Objects 工具类

二进制形式的字面值表示

由于继承 C 语言,Java 代码在传统上迫使程序员只能使用十进制,八进制或十六进制来表示数 (numbers)。Java SE 7 中,整数类型(byte、short、int 以及 long) 也可以使用二进制数系来表示。要指定一个二进制字面量,可以给二进制数字添加前缀 0b 或者 0B。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 一个 8 位的'byte'值:
byte aByte = (byte) 0b00100001;

// 一个 16 位的'short'值:
short aShort = (short) 0b1010000101000101;

// 几个 32 位的'int'值:[B 可以是大写或者小写]
int anInt1 = 0b10100001010001011010000101000101;
int anInt2 = 0b101;
int anInt3 = 0B101;

// 一个 64 位的'long'值. 注意 "L" 后缀:
long aLong = 0b1010000101000101101000010100010110100001010001011010000101000101L;

支持的数字字面量表示:

十进制:默认的
八进制:整数之前加数字 0 来表示
十六进制:整数之前加 “0x” 或“0X”
二进制(新加的):整数之前加 “0b” 或“0B”

在数值类型的字面值中使用下划线分隔符联接

如果 Java 源代码中有一个很长的数值字面量,开发人员在阅读这段代码时需要很费力地去分辨数字的位数,以知道其所代表的数值大小。在现实生活中,当遇到很长的数字的时候,我们采取的是分段分隔的方式。比如数字 500000,我们通常会写成 500,000,即每三位数字用逗号分隔。利用这种方式就可以很快知道数值的大小。这种做法的理念被加入到了 Java7 中,不过用的不是逗号,而是下划线“_”。

1
2
3
4
5
6
// 输出 56.34
System.out.println(5_6.3_4);
// 输出 8931
System.out.println(89_3___1);
// 输出 1500000
System.out.println(1_500_000);

注意:下划线只能出现在数字中间,前后必须是数字。所以“_100”、“0b_101“是不合法的,无法通过编译。

创建泛型实例时自动类型推断

只要编译器从上下文中能够推断出类型参数,你就可以使用一个空的类型参数集合 (<>) 代替调用一个泛型类的构造器所需要的类型参数。这对尖括号通常叫做 diamond。

1
2
3
4
5
// 举个例子, 考虑下面的变量声明:
Map<String, List<String>> myMap = new HashMap<String, List<String>>();

// 在 Java SE 7 中, 你可以使用一个空的类型参数集合 (<>) 代替构造器的参数化类型:
Map<String, List<String>> myMap = new HashMap<>();

注意:想要在泛型类初始化期间利用自动类型推断,你必须要指定 diamond。这个 <> 被叫做 diamond(钻石)运算符,Java 7 后这个运算符从引用的声明中推断类型。

switch-case 语句支持字符串类型

switch 语句可以使用原始类型或枚举类型。Java 引入了另一种类型,我们可以在 switch 语句中使用:字符串类型。

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
String input = "Monday";
String output;
switch (input) {
case "Monday":
output = "星期一";
break;
case "Tuesday":
output = "星期二";
break;
case "Wednesday":
output = "星期三";
break;
case "Thursday":
output = "星期四";
break;
case "Friday":
output = "星期五";
break;
case "Saturday":
output = "星期六";
break;
case "Sunday":
output = "星期日";
break;
default:
throw new IllegalArgumentException("无效的输入参数:" + input);
}

// 输出: 星期一
System.out.println(output);

新增 try-with-resources 语句

Java 中某些资源是需要手动关闭的,如 InputStream,Writes,Sockets,Sqlclasses 等。这个新的语言特性允许 try 语句本身申请更多的资源,这些资源作用于 try 代码块,并自动关闭。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 传统的资源关闭方式[为了确保外部资源一定要被关闭, 通常关闭代码被写入 finally 代码块中, 当然我们还必须注意到关闭资源时可能抛出的异常]
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(new File("test"));
System.out.println(inputStream.read());
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}

// try-with-resource 语法
try (FileInputStream inputStreamForResource = new FileInputStream(new File("test"))) {
System.out.println(inputStreamForResource.read());
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}

那什么是 try-with-resource 呢?简而言之,当一个外部资源的句柄对象(比如 FileInputStream 对象)实现了 AutoCloseable 接口,将外部资源的句柄对象的创建放在 try 关键字后面的括号中,当这个 try-catch 代码块执行完毕后,Java 会确保外部资源的 close 方法被调用。

单个 catch 子句同时捕获多种异常类型

在 Java7 中,catch 代码块得到了升级,用以在单个 catch 块中处理多个异常。如果你要捕获多个异常并且它们包含相似的代码,使用这一特性将会减少代码重复度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Java 7 之前的版本:
try {
// 具体的处理代码
} catch (InstantiationException e) {
// 捕获异常的处理方式
} catch (IllegalAccessException e) {
// 捕获异常的处理方式
} catch (ClassNotFoundException e) {
// 捕获异常的处理方式
}

// 在 Java 7 中,我们可以用一个 catch 块捕获所有这些异常:
try {
// 具体的处理代码
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
// 捕获异常的处理方式
}

引入 java.util.Objects 工具类

引入 java.util.Objects 工具类,用于封装一些平时使用频度很高或容易出错的操作。

(1)Objects.equals(Object a, Object b):有别于 Object.equals(Object a, Object b),这个方法可以避免空指针异常。

1
2
3
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}

(2)Objects.deepEquals(Object a, Object b):Object.equals(Object a, Object b) 用于比较两个对象的引用是否相同,而 deepEquals() 却扩展成了可以支持数组。

1
2
3
4
5
6
7
8
public static boolean deepEquals(Object a, Object b) {
if (a == b)
return true;
else if (a == null || b == null)
return false;
else
return Arrays.deepEquals0(a, b);
}

(3)Objects.hashCode(Object o):和 Object.hashCode(Object o) 类似,只是在对象为 null 时返回的散列值为 0 而已。

1
2
3
public static int hashCode(Object o) {
return o != null ? o.hashCode() : 0;
}

(4)Objects.hash(Object… values):生成对象的散列值,包括数组。

1
2
3
public static int hash(Object... values) {
return Arrays.hashCode(values);
}

(5)Objects.toString(Object o):归根结底,其内部最终调用了对象的 toString() 方法。只是额外多了空指针判断而已。

1
2
3
4
5
6
7
public static String toString(Object o) {
return String.valueOf(o);
}

public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}

(6)Objects.compare(T a, T b, Comparator< ? super T> c):用于比较两个对象。

1
2
3
public static <T> int compare(T a, T b, Comparator<? super T> c) {
return (a == b) ? 0 : c.compare(a, b);
}

(7)Objects.requireNonNull(T obj):在对象为空指针时,抛出特定 message 的空指针异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}

public static <T> T requireNonNull(T obj, String message) {
if (obj == null)
throw new NullPointerException(message);
return obj;
}

public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
if (obj == null)
throw new NullPointerException(messageSupplier.get());
return obj;
}

(8)Objects.isNull(Object obj) / Objects.nonNull(Object obj):这两个方法用于判断对象为 null 和对象不为 null。通常情况下,我们不会直接使用这两个方法,而是使用比较操作符 == 和 !=。这两个方法主要用在 jdk8 开始支持的流计算里面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static <T> T requireNonNull(T obj) {
if (obj == null)
throw new NullPointerException();
return obj;
}

public static <T> T requireNonNull(T obj, String message) {
if (obj == null)
throw new NullPointerException(message);
return obj;
}

public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {
if (obj == null)
throw new NullPointerException(messageSupplier.get());
return obj;
}

参考博文

[1]. A look at Java 7’s new features

谢谢你长得那么好看,还打赏我!😘
0%