还看不懂同事代码?快来补一波 Java 7 语法特性

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 还看不懂同事代码?快来补一波 Java 7 语法特性

前言


Java 平台自出现到目前为止,已经 20 多个年头了,这 20 多年间 Java 也一直作为最流行的程序设计语言之一,不断面临着其他新兴编程语言的挑战与冲击。Java 语言是一种静态强类型语言,这样的语言特性可以让 Java 编译器在编译阶段发现错误,这对于构建出一个稳定安全且健壮的应用来说,尤为重要。但是也因为这种特性,让 Java 开发似乎变得缺少灵活性,开发某些功能的应用时,代码量可能是其他语言的几倍。Java 开发的不足之处也体现越来越复杂的 JDK 上,越来越复杂的 JDK 让开发者完全理解的难度变的非常大。以至于开发者有时会重复实现一个 JDK 中已经提供了的功能。


为了跟上互联网应用编程发展的脚步, Java 从 9 版本开始调整了 JDK 发布的节奏,JDK 的每次更新都注重提高生产效率,提高 JVM 性能,推行模块化等,让开发者可以更多的专注于业务本身,而不是浪费过多的时间在语言特性上。Java 语言的更新要在语言的严谨性和灵活性上找到一个平衡点,毕竟灵活性可以减少编码的复杂度,而严谨性是构建复杂且健壮应用的基石。


Java 7 语言特性


Java 重要的更新版本是在 Java 5 版本,这个版本中增加了如泛型、增强 for、自动装箱拆箱、枚举类型,可变参数、注解等一系列重要功能,但是随后的 Java 6 中并没有增加新的重要的语言特性。Java 5 的发布是在 2004 年,已经很久远了,网上关于 Java 的教程也大多是基于 Java 6 的,也因此我准备从 Java 7 开始介绍每个 Java 版本的新特性。


下面所有代码的运行演示都是基于 Java 7 ,所以你如果尝试下面的代码,需要安装并配置 Jdk 1.7 或者已上版本。


1. switch String


在 Java 7 之前,switch 语法中只支持整数类型以及这些整数类型的封装类进行判断,在 Java 7 中,支持了 string 字符串类型的判断,使用起来非常的简单,但是实用性是很高的。


1.1. switch String 基本用法


编写一个简单的 switch 判断字符串的测试类。


public class SwitchWithString {
    public static void main(String[] args) {
        String gender = "男";
        System.out.println(gender.hashCode());
        switch (gender) {
            case "男":
                System.out.println("先生你好");
                break;
            case "女":
                System.out.println("女士你好");
                break;
            default:
                System.out.println("你好");
        }
    }
}


switch 判断字符串使用起来很简单,结果也显而易见会先输出 gender 变量的 hashCode,然后输出匹配结果“先生你好”。


30007
先生你好


在使用 switch string 时候,如果结合 Java 5 的枚举类,那么效果会更好,Java 7 之前使用枚举类要为每个值编数字代号,Java 7 之后可以直接定义字符串名称。


1.2. switch String 实现原理


但是这个支持只是编译器层面的支持, JVM 依旧是不支持的。在对字符串进行 switch 时,编译器会把字符串转换成整数类型再进行判断。为了验证上面说的只是编译器层面的支持,我们反编译(可以使用 Jad 反编译工具,也可以在 Idea 中双击编译生成的 class )生成的 class 文件,看到编译器把 switch string 转换成了字符串 hashCode 判断,为了防止 hashCode 冲突,又使用了 equals 再次判断。


public class SwitchWithString {
    public SwitchWithString() {
    }
    public static void main(String[] args) {
        String gender = "男";
        System.out.println(gender.hashCode());
        byte var3 = -1;
        switch(gender.hashCode()) {
        case 22899:
            if (gender.equals("女")) {
                var3 = 1;
            }
            break;
        case 30007:
            if (gender.equals("男")) {
                var3 = 0;
            }
        }
        switch(var3) {
        case 0:
            System.out.println("先生你好");
            break;
        case 1:
            System.out.println("女士你好");
            break;
        default:
            System.out.println("你好");
        }
    }
}


2. try-with-resource


Java 不同于 C++,需要开发者自己管理每一块内存,大多时候 Java 虚拟机都可以很好的帮我们进行资源管理,但是也有时候需要手动释放一些资源,比如数据库连接、磁盘文件连接、网络连接等。换句话说,只要是资源数量有限的,都需要我们手动的进行释放。


2.1. try-catch-finally


在操作有限资源的时候,可能会出现各种异常,不管是读取阶段还是在最后关闭资源的过程中,都有可能出现问题,我们通常会使用下面的方式 try-catch-finally 保证资源的释放。


像下面这样。


/**
 * 释放资源
 *
 * @author www.codingme.net
 */
public class TryCatachFinally {
    /**
     * 异常处理
     *
     * @param args
     */
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream("jdk-feature-7.iml");
        } catch (FileNotFoundException e) {
            throw e;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    throw e;
                }
            }
        }
    }
}


看看这恶心的代码结构,为了捕获异常,我们写了一个 catch,为了能保证释放资源,我们又写了 finally 进行资源释放,在资源释放时为了捕捉 close 时抛出的异常,我们又写了一个 try-catch。最后看着这复杂的代码,如果有人告诉你这段代码有 bug,那你一定不会相信。但是确实是这样,看起来严密的代码逻辑,当 try 中的代码逻辑和 close 方法同时产生异常的时候,try 中的异常信息会丢失。


可以看这里例子。


package net.codingme.feature.jdk7;
import java.io.IOException;
/**
 * 释放资源
 *
 * @author www.codingme.net
 */
public class TryCatachFinallyThrow {
    /**
     * 异常处理
     *
     * @param args
     */
    public static void main(String[] args) throws Exception {
        read();
    }
    public static void read() throws Exception {
        FileRead fileRead = null;
        try {
            fileRead = new FileRead();
            fileRead.read();
        } catch (Exception e) {
            throw e;
        } finally {
            if (fileRead != null) {
                try {
                    fileRead.close();
                } catch (Exception e) {
                    throw e;
                }
            }
        }
    }
}
class FileRead {
    public void read() throws Exception {
        throw new IOException("读取异常");
    }
    public void close() throws Exception {
        System.out.println("资源关闭");
        throw new IOException("关闭异常");
    }
}


很明显代码里 readclose 方法都会产生异常,但是运行程序发现只能收到 close 的异常信息。


资源关闭
Exception in thread "main" java.io.IOException: 关闭异常
  at net.codingme.feature.jdk7.FileRead.close(TryCatachFinallyThrow.java:51)
  at net.codingme.feature.jdk7.TryCatachFinallyThrow.read(TryCatachFinallyThrow.java:33)
  at net.codingme.feature.jdk7.TryCatachFinallyThrow.main(TryCatachFinallyThrow.java:20)


异常信息丢失了,可怕的是你以为只是 close 时发生了异常而已。


2.2. try-autocloseable


上面的问题在 Java 7 中其实已经提供了新的解决方式,Java 7 中对 try 进行了增强,可以保证资源总能被正确释放 。使用增强 try 的前提是 try 中的类实现了 AutoCloseable 接口,在 Java 7 中大量的需要释放资源的操作其实都已经实现了此接口了。


image.png


AutoCloseable 实现类


实现了 AutoCloseable 的类,在增强 try中使用时,不用担心资源的关闭,在使用完毕会自动的调用 close方法,并且异常不会丢失


让我们编写的模拟资源操作的类实现 AutoCloseable 接口,然后时候增强 try 看看效果。


package net.codingme.feature.jdk7;
/**
 * 自动关闭
 *
 * @author www.codingme.net
 */
public class AutoCloseResource {
    public static void main(String[] args) throws Exception {
        try (Mysql mysql = new Mysql();
             OracleDatabase oracleDatabase = new OracleDatabase()) {
            mysql.conn();
            oracleDatabase.conn();
        }
    }
}
class Mysql implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("mysql 已关闭");
    }
    public void conn() {
        System.out.println("mysql 已连接");
    }
}
class OracleDatabase implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("OracleDatabase 已关闭");
    }
    public void conn() {
        System.out.println("OracleDatabase 已连接");
    }
}


测试类 Mysql 和 OracleDatabase 都是实现了 AutoCloseable,运行查看结果。


mysql 已连接
OracleDatabase 已连接
OracleDatabase 已关闭
mysql 已关闭


确认在发生异常时候异常信息不会丢失,写一个有异常的模拟测试类进行测试。


package net.codingme.feature.jdk7;
import java.io.IOException;
/**
 * 释放资源
 *
 * @author www.codingme.net
 */
public class AutoCloseThrow {
    public static void main(String[] args) throws Exception {
        try (FileReadAutoClose fileRead = new FileReadAutoClose()) {
            fileRead.read();
        }
    }
}
class FileReadAutoClose implements AutoCloseable {
    public void read() throws Exception {
        System.out.println("资源读取");
        throw new IOException("读取异常");
    }
    @Override
    public void close() throws Exception {
        System.out.println("资源关闭");
        throw new IOException("关闭异常");
    }
}


运行查看异常信息。


资源读取
资源关闭
Exception in thread "main" java.io.IOException: 读取异常
  at net.codingme.feature.jdk7.FileReadAutoClose.read(AutoCloseThrow.java:23)
  at net.codingme.feature.jdk7.AutoCloseThrow.main(AutoCloseThrow.java:14)
  Suppressed: java.io.IOException: 关闭异常
    at net.codingme.feature.jdk7.FileReadAutoClose.close(AutoCloseThrow.java:29)
    at net.codingme.feature.jdk7.AutoCloseThrow.main(AutoCloseThrow.java:15)


自动关闭,异常清晰,关闭异常存在于 Suppressed ,称为抑制异常,后续文章会详细介绍。


3. try-catch


在 Java 7 之前,一个 catch 只能捕获一个异常信息,当异常种类非常多的时候就很麻烦,但是在 Java 7 中,一个 catch 可以捕获多个异常信息,每个异常捕获之间使用 | 分割,


package net.codingme.feature.jdk7;
import java.io.IOException;
/**
 * 多异常捕获
 */
public class TryCatchMany {
    public static void main(String[] args) {
        try (TxtRead txtRead = new TxtRead()) {
            txtRead.reader();
        } catch (IOException | NoSuchFieldException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class TxtRead implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("资源释放");
    }
    public void reader() throws IOException, NoSuchFieldException {
        System.out.println("数据读取");
    }
}


需要注意的是,一个 catch 捕获多个异常时,不能出现重复的异常类型,也不能出现一个异常类型是另一个类的子类的情况。


4. 二进制


Java 7 开始,可以直接指定不同的进制数字。


  1. 二进制指定数字值,只需要使用 0b 或者 OB 开头。
  2. 八进制指定数字值,使用 0 开头。
  3. 十六进制指定数字值,使用 0x 开头。


/**
 * 二进制
 *
 * @author www.codingme.net
 */
public class Binary {
    public static void main(String[] args) {
        // 二进制
        System.out.println("------2进制-----");
        int a = 0b001;
        int b = 0b010;
        System.out.println(a);
        System.out.println(b);
        // 八进制
        System.out.println("------8进制-----");
        int a1 = 010;
        int b1 = 020;
        System.out.println(a1);
        System.out.println(b1);
        // 十六进制
        System.out.println("------16进制-----");
        int a2 = 0x10;
        int b2 = 0x20;
        System.out.println(a2);
        System.out.println(b2);
    }
}


输出结果。


------2进制-----
1
2
------8进制-----
8
16
------16进制-----
16
32


5. 数字下划线


Java 7 开始支持在数字定义时候使用下划线分割,增加了数字的可读性。


/**
 * 数字下环线
 *
 * @author www.codingme.net
 */
public class NumberLine {
    public static void main(String[] args) {
        int a = 1_000;
        int b = 1_0__0_0_0_____00;
        System.out.println(a);
        System.out.println(b);
    }
}


得到结果。


1000
1000000


6. 结束语


虽然 Java 7 早在 2011 年就已经发布了,但是据我发现,使用到 Java 7 开始的新特性新语法的并不多,所以我的 JDK 新特性系列文章计划从 Java 7 开始,一直介绍到目前已经发布的 Java 13,以后 Java 新版本更新的同时,这个新特性系列文章也会持续更新。


此去山高水远,愿能一路坚持,愿你我一路同行。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3天前
|
设计模式 Java
Java设计模式:组合模式的介绍及代码演示
组合模式是一种结构型设计模式,用于将多个对象组织成树形结构,并统一处理所有对象。例如,统计公司总人数时,可先统计各部门人数再求和。该模式包括一个通用接口、表示节点的类及其实现类。通过树形结构和节点的通用方法,组合模式使程序更易扩展和维护。
Java设计模式:组合模式的介绍及代码演示
|
3天前
|
Java 程序员 API
Java中的Lambda表达式:简化代码的秘密武器
在Java 8中引入的Lambda表达式是一种强大的编程工具,它可以显著简化代码,提高可读性。本文将介绍Lambda表达式的基本概念、优势以及在实际开发中的应用。通过具体示例,您将了解如何使用Lambda表达式来简化集合操作、线程编程和函数式编程。让我们一起探索这一革命性的特性,看看它是如何改变Java编程方式的。
15 4
|
3天前
|
Java 开发者
探索Java中的Lambda表达式:简化你的代码
【8月更文挑战第49天】在Java 8的发布中,Lambda表达式无疑是最令人兴奋的新特性之一。它不仅为Java开发者提供了一种更加简洁、灵活的编程方式,而且还极大地提高了代码的可读性和开发效率。本文将通过实际代码示例,展示如何利用Lambda表达式优化和重构Java代码,让你的编程之旅更加轻松愉快。
|
5天前
|
机器学习/深度学习 人工智能 安全
python和Java的区别以及特性
Python:适合快速开发、易于维护、学习成本低、灵活高效。如果你需要快速上手,写脚本、数据处理、做点机器学习,Python就是你的首选。 Java:适合大型项目、企业级应用,性能要求较高的场景。它类型安全、跨平台能力强,而且有丰富的生态,适合更复杂和规模化的开发。
14 3
|
7天前
|
SQL JavaScript 前端开发
基于Java访问Hive的JUnit5测试代码实现
根据《用Java、Python来开发Hive应用》一文,建立了使用Java、来开发Hive应用的方法,产生的代码如下
28 6
|
6天前
|
Java 开发者
探索Java中的Lambda表达式:简化代码,提升效率
【9月更文挑战第14天】本文旨在揭示Java 8中引入的Lambda表达式如何革新了我们编写和管理代码的方式。通过简洁明了的语言和直观的代码示例,我们将一起走进Lambda表达式的世界,了解其基本概念、语法结构以及在实际编程中的应用。文章不仅会展示Lambda表达式的魅力所在,还会指导读者如何在日常工作中有效利用这一特性,以提高编码效率和程序可读性。
|
12天前
|
安全 Java API
Java 18 概述:新特性一览
Java 18 作为 Java 平台的最新版本,引入了多项令人振奋的新特性和改进,包括模式匹配、记录类型、流库改进、外部函数与内存 API 以及并发处理增强。这些新功能不仅提升了开发者的生产力,还显著增强了 Java 的性能和安全性。本文将详细介绍 Java 18 的主要新特性,并通过代码示例帮助读者更好地理解和应用这些功能。
|
12天前
|
并行计算 Java 开发者
探索Java中的Lambda表达式:简化代码,提升效率
Lambda表达式在Java 8中引入,旨在简化集合操作和并行计算。本文将通过浅显易懂的语言,带你了解Lambda表达式的基本概念、语法结构,并通过实例展示如何在Java项目中应用Lambda表达式来优化代码,提高开发效率。我们将一起探讨这一现代编程工具如何改变我们的Java编码方式,并思考它对程序设计哲学的影响。
|
存储 算法 Java
Java8语法最佳实践-什么是对象(上)
计算机革命起源机器。编程语言就像是那台机器。它不仅是我们思维放大的工具与另一种表达媒介,更像是我们思想的一部分。语言的灵感来自其他形式的表达,如写作,绘画,雕塑,动画和电影制作。编程语言就是创建应用程序的思想结构。
155 0
Java8语法最佳实践-什么是对象(上)
|
存储 安全 Java
Java8语法最佳实践-什么是对象(下)
计算机革命起源机器。编程语言就像是那台机器。它不仅是我们思维放大的工具与另一种表达媒介,更像是我们思想的一部分。语言的灵感来自其他形式的表达,如写作,绘画,雕塑,动画和电影制作。编程语言就是创建应用程序的思想结构。
95 0