1.for-each和枚举
for vs for-each
- for-each 从JDK5.0开始引入
- for-each 语法更简洁
- for-each 避免越界错误
- for 可以删除元素,for-each不可以删除/替换元素
- for-each遍历的时候,是不知道当前元素的具体位置索引
- for-each只能正向遍历,不能反向遍历
- for-each不能同时遍历2个集合
- for和for-each性能接近
枚举类型
- 枚举变量:变量的取值只在一个有限的集合内
- Java5推出enum类型
- enum关键字声明枚举类,且都是Enum的子类(但不需写extends)
- enum内部有多少个值,就有多少个实例对象
- 不能直接new枚举类对象
1 | public enum Size { |
- 除了枚举的内容,还可以添加属性/构造函数/方法
- 构造函数只能是package-private(default)或者private,内部调用
1 | enum Fruit |
- 所有的enum类型都是Enum的子类,也继承了相应方法
- ordinal()返回枚举值所在的索引位置, 从0开始
- compareTo()比较两个枚举值的索引位置大小
- toString()返回枚举值的字符串表示
- valueOf()将字符串初始化为枚举对象
- values()返回所有的枚举值
1 | enum Day |
2.不定项参数和静态导入
不定项参数
- JDK 5提供了不定项参数(可变参数)功能
- 类型后面加3个点,如int…/double…/String…/
- 可变参数,本质上是一个数组
1 | public static void print(String... args) { |
- 一个方法只能有一个不定项参数,且必须位于参数列表的最后
1 | //错误:一个方法不可以有多个可变参数 |
- 重载的优先级规则1:固定参数的方法,比可变参数优先级更高
1 | //当只有一个参数时,本方法优先级更高 |
- 重载的优先级规则2:调用语句,同时与两个带可变参数的方法匹配,则报错
1 | //错误:一个调用语句不能同时有2个带可变参数的方法适配 |
静态导入
- import 导入程序所需要的类
1 | import static java.lang.Math.pow; |
- import static 导入一个类的静态方法和静态变量(JDK5引入)
- 少使用 * 通配符,不滥用,最好具体到静态变量或方法
- 静态方法名具有明确特征,如有重名,需要补充类名
3.自动拆装箱,多异常并列,数值类型赋值优化
自动装箱和拆箱(auto-boxing/auto-unboxing)
- 从JDK5.0开始引入,简化基本类型和对象转换的写法
- 基本类型:boolean/byte/char/int/short/long/float/double
- 对象:Boolean/Byte/Character/Integer/Short/Long/Float/Double
1 | Integer obj1 = 5; //自动装箱 |
注意事项
- 装箱和拆箱是编译器的工作,在class中已经添加转化。虚拟机没有自动装箱和拆箱的语句
- ==:基本类型是内容相同,对象是指针是否相同(内存同一个区域)
- 基本类型没有空值,对象有null,可能触发NullPointerException
- 当一个基础数据类型与封装类进行 ==、+、-、* 、/运算时,会将封装类进行拆箱,对基础数据类型进行运算
- 谨慎使用多个非同类的数值类对象进行运算
多异常并列
- 多个异常并列在一个catch中
- 从JDK7.0开始引入,简化写法
1 | try { |
- 多个异常之间不能有(直接/间接)继承关系,如果有,则报错
1 | try { |
数值类型赋值优化
- Java 7的新语法:整数类型用二进制数赋值
- 避免二进制计算
- byte/short/int/long
1 | byte a1 = (byte) 0b00100001; |
- Java 7的新语法:在数值字面量(literal)中使用下划线
- 增加数字的可读性和纠错功能
- short/int/long/float/double
- 下划线只能出现数字中间,前后必须有数字
- 允许在二/八/十/十六进制的数字中使用
1 | int a3 = 0b0111_1011_0001; //二进制, 0b开头 |
4.接口方法
- Java 8推出接口的默认方法/静态方法(都带实现的),为Lambda表达式提供支持
接口的默认方法
- 以default关键字标注,其他的定义和普通函数一样
- 规则1:默认方法不能重写Object中的方法
- 规则2:实现类可以继承/重写父接口的默认方法
- 规则3:接口可以继承/重写父接口的默认方法
- 规则4:当父类和父接口都有(同名同参数)默认方法,子类继承父类的默认方法,这样可以兼容JDK7及以前的代码
- 规则5:子类实现了2个接口(均有同名同参数的默认方法),那么编译失败,必须在子类中重写这个default方法
1 | public interface NewAnimal { |
接口的静态方法
- 该静态方法属于本接口的,不属于子类/子接口
- 子类(子接口)没有继承该静态方法,只能通过所在的接口名来调用
1 | public interface StaticAnimal { |
接口的私有方法
- Java 9推出,带实现
- 解决多个默认方法/静态方法的内容重复问题
- 私有方法属于本接口,只在本接口内使用,不属于子类/子接口
- 子类(子接口)没有继承该私有方法,也无法调用
- 静态私有方法可以被静态/默认方法调用,非静态私有方法被默认方法调用
1 | public interface PrivateAnimal { |
接口 vs 抽象类
- 相同点(截止至Java 12以前,接口和抽象类对比)
- 都是抽象的,都不能被实例化,即不能被new
- 都可以有实现方法
- 都可以不需要继承者实现所有的方法
- 不同点(截止至Java 12以前,接口和抽象类对比) 、
- 抽象类最多只能继承一个,接口可以实现多个
- 接口的变量默认是public static final,且必须有初值,子类不能修改;而抽象类的变量默认是default,子类可以继承修改
- 接口没有构造函数,抽象类有构造函数
- 接口没有main函数,抽象类可以有main函数
- 接口有public/default/private 的方法,抽象类有public/private/protected/不写关键字的(default)的方法
5.try-with-resource和Resource Bundle文件加载
try-with-resource
- JDK7提供try-with-resource,比try-catch-finally更简便
- 资源要求定义在try中。若已经在外面定义,则需要一个本地变量
- JDK9不再要求定义临时变量,可以直接使用外部资源变量
1 | String line; |
- try-with-resource原理
- 资源对象必须实现 AutoCloseable接口,即实现close方法
1 | public class MyTryWithResourceTest { |
ResourceBundle文件加载
- Java 8及以前,ResourceBundle默认以ISO-8859-1方式加载Properties文件
- 需要利用native2ascii工具(JDK自带)对文件进行转义
- JDK9及以后, ResourceBundle默认以UTF-8方式加载Properties文件
- JDK9及以后,已经删除native2ascii工具
- 新的Properties文件可以直接以UTF-8保存
- 已利用native2ascii工具转化后的文件,不受影响。即ResourceBundle 若解析文件不是有效的UTF-8,则以ISO-8859-1方式加载
6.var类型和switch
var类型
- Java以前一直是一种强类型的程序语言
- 每个变量在定义时就确定了类型
- 类型固定了,就不能更改
- Java 10推出var:局部变量推断
- 避免信息冗余
- 对齐了变量名
- 更容易阅读
- 本质上还是强类型语言,编译器负责推断类型,并写入字节码文件。因此推断后不能更改!!!
- var的限制
- 可以用在局部变量上,非类成员变量
- 可以用在for/for-each循环中
- 声明时必须初始化
- 不能用在方法(形式)参数和返回类型
- 大面积滥用会使代码整体阅读性变差
- var只在编译时起作用,没有在字节码中引入新的内容,也没有专门的JVM指令处理var
switch
- 支持的类型:byte/Byte, short/Short, int/Integer, char/Character, String(7.0), Enum枚举(5.0)
- 不支持long/float/double
- 多分支合并,采用->直接连接判定条件和动作(JDK12支持)
1 | public static int judgeMonthDay12(String month) { |
- switch直接在表达式赋值(JDK12支持)
1 | public static void testSwitchReturn() { |