2009 年 4 月 20 日, Java 的亲生父亲 Sun 被养父 Oracle 以 74 亿美元收购, 这在当时可是一件天大的事. 有不少同学都担心 Java 的前途, 我当时傻不啦叽地也很担心: 自己刚学会如何通过记事本编写 Java 代码, 然后通过 cmd 打印 Hello World 呢, 这一下难道白学了?
但其实这种担心是多余的, 因为 Java 并不会陪葬, 毕竟行业内有太多基于 Java 的软件系统在运行, Java 牵扯了太多人的饭碗. 10 年过去了, Java 果然没有陪葬, 我仍然坚守在 Java 的阵线上.
2011 年 7 月 7 日, 代号「海豚(Dolphin)」的 Java 7 首次推出, 这也是 Java 历史上一次非常重要的版本更新. 同时推出了非常多实用的新特性, 比如说创建泛型实例时自动类型推断, switch-case 语句支持字符串类型, 新增 try-with-resources 语句等等.
这么多年过去了, Java 7 的 "新" 特性显然都变成老古董了 -- 它们似乎也不需要我再赘述了, 但好像不是这样的. 前几天我发了一篇文章, 用到了其中一个新特性, 竟然有同学表示从来没见过这个新特性, 特意在交流群里 @我, 要我说清楚怎么回事(代码折叠了, 随后贴出来).
当时我就在想啊, 原来技术从来没有 "新与旧" 之说, 只有知不知道. 所以借此机会, 我就再来 "赘述" 一下 Java 7 的那些最经常使用的新特性吧.
01, 数值中可使用下划线分隔符联接
之前图片中的代码没有展示全, 现在我把具体的代码贴出来.
- try {
- AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);
- Future<Integer> result = channel.read(ByteBuffer.allocate(100_000), 0);
- } catch (IOException e) {
- e.printStackTrace();
- }
其中 100_000 就是读者要我解释清楚的那个特性: 在数值类型的字面值中使用下划线分隔符联接.
人脑不总是很善于记住很长串的数字, 所以在处理长串数字时会采用分割法, 比如说电话号码要用一个分隔符 "-" 隔开, 银行卡号会每隔四位有一个空格等等.
数字中没有用逗号 (,) 和中划线 (-) 作为分隔符, 是因为它们可能会引发歧义, 取而代之的是下划线 (_). 这个不起眼的特性, 让我们开发人员在处理数字上轻松多了, 毕竟 100_000 比 100000 (忍不住查了一遍 0 的个数, 害怕多写或者少写) 辨识度高得多.
下划线 (_) 位置并不固定, 你可以随意摆放, 举例如下:
- int a = 100_000, b = 100000, c = 10_0000;
- System.out.println(a==b); // true
- System.out.println(b==c); // true
- System.out.println(a==c); // true
需要注意的是, 下划线仅仅能在数字中间, 编译器在编译的时候自己主动删除数字中的下划线. 反编译后的代码如下所示:
- int a = 100000;
- int b = 100000;
- int c = 100000;
- System.out.println(a == b);
- System.out.println(b == c);
- System.out.println(a == c);
02, switch-case 语句支持字符串类型
我们都知道, switch 是一种高效的判断语句, 比起 if/else 真的是爽快多了. 示例如下:
- String wanger = "王二";
- switch (wanger) {
- case "王二":
- System.out.println("王三他哥哥王二");
- break;
- case "王三":
- System.out.println("王二他弟弟王三");
- break;
- default:
- System.out.println("王二他妹妹王六");
- break;
- }
switch-case 语句在处理字符串的时候, 会先将 switch 括号中的字符串和 case 后的字符串转成 hashCode, 所以字符串不能为 null, 否则会抛出 NullPointerException. 反编译后的代码如下所示:
- String wanger = "王二";
- switch (wanger.hashCode()) {
- case 936926 :
- if (wanger.equals("王三")) {
- System.out.println("王二他弟弟王三");
- return;
- }
- break;
- case 937057 :
- if (wanger.equals("王二")) {
- System.out.println("王三他哥哥王二");
- return;
- }
- }
- System.out.println("王二他妹妹王六");
03,try-with-resources 语句
try-with-resources 的基本设想是把资源 (socket, 文件, 数据库连接) 的作用域限定在代码块内, 当这块代码执行完后, 资源会被自动释放.
在此之前, 资源的释放需要在 finally 中主动关闭, 不管 try 中的代码是否正常退出或者异常退出. 就像下面这样:
- BufferedReader in = null;
- try {
- in = new BufferedReader(new FileReader("cmower.txt"));
- int charRead;
- while ((charRead = in.read()) != -1) {
- System.out.printf("%c", (char) charRead);
- }
- } catch (IOException ex) {
- ex.printStackTrace();
- } finally {
- try {
- if (in != null)
- in.close();
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- }
这样的代码看起来就像老太婆的裹脚布, 又臭又长; 有了 try-with-resources 之后, 情况大有改观, 不信你看:
- try (BufferedReader in = new BufferedReader(new FileReader("cmower.txt"));) {
- int charRead;
- while ((charRead = in.read()) != -1) {
- System.out.printf("%c", (char) charRead);
- }
- } catch (IOException ex) {
- ex.printStackTrace();
- }
是不是清爽多了! 把需要释放的资源放在 try 后的 () 中, 连 finally 也不需要了. 不过, 需要注意的是, 上面的代码还需要优化, 应该为每一个资源声明独立的变量, 否则的话, 某些特殊的情况下, 资源可能无法正常关闭.
- try (FileReader fr = new FileReader("cmower.txt");
- BufferedReader in = new BufferedReader(fr);) {
- int charRead;
- while ((charRead = in.read()) != -1) {
- System.out.printf("%c", (char) charRead);
- }
- } catch (IOException ex) {
- ex.printStackTrace();
- }
try-with-resources 特性依赖于一个新定义的接口 AutoCloseable, 需要释放的资源必须要实现这个接口.
不过, try-with-resources 在本质上仍然使用了 finally 去释放资源, 只不过这部分工作不再由开发者主动去做 -- 从反编译后的结果可以看得出来:
- try {
- Throwable var1 = null;
- Object var2 = null;
- try {
- FileReader fr = new FileReader("cmower.txt");
- try {
- BufferedReader in = new BufferedReader(fr);
- int charRead;
- try {
- while ((charRead = in.read()) != -1) {
- System.out.printf("%c", (char) charRead);
- }
- } finally {
- if (in != null) {
- in.close();
- }
- }
04, 创建泛型实例时自动类型推断
在这个特性出现之前, 有关泛型变量的声明略显重复, 示例如下:
Map<String, ArrayList<String>> wanger = new HashMap<String, ArrayList<String>>();
这样的代码简直太长了, 很多重复的字符, 难道编译器不能推断出泛型的类型信息吗? Java 7 实现了这个心愿.
- Map<String, List<String>> wanger = new HashMap<>();
- List<String> chenmo = new ArrayList<>();
- wanger.put("chenmo", chenmo);
这个看似简单的特性省去了不少敲击键盘的次数.
05, 最后
除了上面我列出的这 4 个常用的新特性, Java 7 还有一些其他的特性, 比如说 multi-catch, 可以在一个 catch 语句中捕获多个异常; 比如说对集合 (Collections) 的增强支持, 可以直接采用 [],{} 的形式存入对象, 采用 [] 的形式按照索引, 键值来获取集合中的对象等等.
但总体上, 我列出的那 4 个特性最为常用, 其学习的意义更大. 如果你觉得漏掉了某些更为常用的特性, 欢迎你在文末提出来.
来源: https://www.cnblogs.com/qing-gee/p/11262262.html