前言
我们都知道,Java是一门不断更新的语言!!如果我们不能够掌握其中的新特性(有些特性对于提高开发效率是真的赞),那么将止步于此!
特性介绍
JDK1.5
1)自动拆箱与装箱
我们知道,Java是一个面向对象的语言,但其中的八大基本数据类型就不是对象。为了解决这个问题,Java很早就给我们提供了相应的包装类:Boolean,Byte,Short,Integer,Long,Float,Double,Character。这八个代表其基本的数据类型boolean,byte,short,int,long,float,double,char
但是,在JDK1.5之前,一只存在着基本数据类型与包装类的类型转换问题,方法十分繁琐。JDK1.5引入了相应的方法和机制,在底层帮助我们进行类型转换。
//JDK1.5以前完成装箱
int a = 1;
Integer b = new Integer(a);
//JDK1.5以后完成装箱
int c = 1;
Integer d = c;//实质底层调用Integer.valueOf()方法
//JDK1.5以前完成拆箱
Integer e = new Integer(1);
int f = e.intValue();
//JDK1.5以后完成拆箱
Integer g = new Integer(1);
int h = g;//实质底层调用intValue()方法
2)枚举
我们知道,我们的项目中经常会需要一些常量,我们会把它定义为XXXConst.java,用来保存所有的常量值。有些情况是可以的。但是,一旦常量值过多,就会出现管理不当、添加重复常量、代码冗余等等问题。JDK1.5提出了枚举的概念,实质上就是将常量分类化,这样极大的提高开发效率(虽然如此,但是枚举高级特性不建议使用,将使程序复杂度大大提高!)
public class Const {
//JDK1.5之前定义一组常量
public static final String TIGER = "TIGER";
public static final String CAT = "CAT";
public static final String DOG = "DOG";
public static final String RABBIT = "RABBIT";
public static final Integer N = 0;
public static final Integer Y = 1;
}
常量无外乎都是String类型,个别的会有boolean、int等其他基本类型,所以JDK1.5枚举常量类定义如下:
package com.jwang.test;
//JDK1.5之后定义枚举类
public enum Animal {
//其默认为String类型
TIGER,CAT,DOG,RABBIT
}
package com.jwang.test;
public enum Num {
//通过构造器创建整型常量,一般都为String常量
N(1),Y(2);
private int num;
private Num(int num) {
this.num = num;
}
@Override
public String toString() {
return String.valueOf(num);
}
}
调用枚举常量的方法不再赘述。
3)静态导入
我们知道,java.lang.Math包中的方法和属性是用来做数学运算的,其中全部都是静态方法和属性。在JDK1.5之前,我们都是Math.XXX来进行调用,如果使用的方法多了,那么将是极大的烦人!
package com.jwang.test;
//静态导入
import static java.lang.Math.*;
public class Test{
public static void main(String[] args) {
//JDK1.5之前需要加上Math
System.out.println(Math.max(1, 2));
//JDK1.5以后无需麻烦,直接静态导入
System.out.println(max(1, 2));
}
}
4)可变参数
我们知道,有时候我们写出来的方法形参是不固定的,可能有一个,可能有多个。典型的例子就是计算若干个数的和。如果在JDK1.5之前,你可能想到重载啊,数组啊,递归啊等等等等,但是JDK1.5完美的解决了这个问题。
JDK1.5引入可变参数实例代码:
//JDK1.5之后完成若干数的和运算
public static int getSum2(int ... a){
int sum = 0;
for (int i = 0; i < a.length; i++) {
sum += a[i];
}
return sum;
}
5)泛型
我们知道,在JDK1.5之前,定义集合类如List的定义是没有指定任何类型的,其默认为Object类型,如果我们用作其他类型的话,需要做许多强制转换的操作,显然这与我们关心的主要逻辑不符。JDK1.5提出泛型的概念解决了这一问题。简单的说,泛型就是为集合容器类加入了一个标签,其告诉编译器这个集合里装的是什么类型。
//JDK1.5之前List定义
List list1 = new ArrayList();
list1.add("1");
//需要强制转换
String a = (String) list1.get(0);
//JDK1.5以后List定义
List<String> list2 = new ArrayList<String>();
list2.add("1");
String b = list2.get(0);
6)foreach循环
我们知道,在JDK1.5以前,十分流行的循环方法就是最著名的for循环语句了。但是,有些时候我们是无需关注其下标值的,那么这个时候下标就显得十分多余,JDK1.5提出了新的循环方法改善这一问题。
String [] strs = {"a","b","c"};
//JDK1.5之前for循环
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
//JDK1.5以后for循环
for (String str : strs) {
System.out.println(str);
}
以上为JDK1.5的新特性,特别的:我们不是非要用新特性,在某些必要的条件下,必须要用老的方式进行编码!
JDK1.6
说起JDK1.6,没什么跟我们相关的新特性的更新,大家自行百度读一下就好了,我不在赘述。
JDK1.7
1)二进制的书写
在JDK1.7以前,Java中只能表示诸如八进制、十进制、十六进制的数字,二进制迟迟无法展示。但是在JDK1.7,完美的解决了这一问题
//JDK1.7之前的表示法只有八进制、十进制、十六进制
System.out.println(011);//八进制:9 (0开头的)
System.out.println(11);//十进制:11
System.out.println(0x11C);//十六进制:284 (0x开头的)
//JDK1.7之后新增二进制表示法
System.out.println(0b101);//二进制:5 (0b开头的)
2)数字常量使用下划线
我们知道,JDK1.7之前定义一个大数字,需要写很多位数,阅读起来十分的不方便。JDK1.7帮我们解决了这个问题,引入了位数分隔符下划线“_”的概念,使得数字浅显易懂!
//JDK1.7之前定义整型变量
long a = 13213324123124144L;
//JDK1.7之后定义整型变量使用“_”分隔方便阅读
long b = 132_133_241_231_241_44L;
3)switch语句可以使用字符串作为变量
在JDK以前,我们一般不适用switch语句,因为它有一个局限性,那就是不能用字符串作为判断的标准!其只能使用byte、short、char、int或者枚举进行判断,十分的不友好!但是在JDK1.7圆满的解决了这个问题。
//JDK1.7使用字符串作为判断条件
String key = "a";
switch (key) {
case "a":
System.out.println("a");
break;
case "b":
System.out.println("b");
break;
default:
System.out.println("b");
break;
}
4)实例创建的类型推断
在JDK1.5以后,我们知道,集合类的定义使用了泛型极大的增加了程序的编写效率!但是,我们都是这样写的如:
List<String> list2 = new ArrayList<String>();
大家有没有觉得,后面的泛型String设置的有些多余,前面都已经指定了啊!JDK1.7完美解决了这个问题,提出了类型推断的概念
//JDK1.7之前定义集合类的方法
List<String> list1 = new ArrayList<String>();
Map<String, Object> map1 = new HashMap<String, Object>();
//JDK1.7之后定义集合类的方法,增加类型自动推断
List<String> list2 = new ArrayList<>();
Map<String, Object> map2 = new HashMap<>();
5)try-with-resources 资源的自动管理
在JDK1.7之前,我们使用IO流操作的时候,最烦的就是最后要关闭各种流的连接!!但是JDK1.7使用了try-with-resources自动管理定义的资源类,无需我们手动关闭!
//JDK1.7之前使用资源类
FileInputStream in = null;
try {
in = new FileInputStream("F:\test.txt");
//后续操作
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//JDK1.7之后使用资源类
try (
//资源定义,定义后无需考虑关闭
FileInputStream in = new FileInputStream("F:\test.txt");
){
//后续操作
} catch (IOException e) {
e.printStackTrace();
}
特别的:资源类必须实现了AutoCloseable
或者Closeable
接口才能使用该特性!
6)优化异常捕捉的代码
我们知道,在JDK1.7之前,如果一段代码的异常过多,那么我们try-catch语句块将会十分的复杂!JDK1.7完美的解决了这一问题!
//JDK1.7以前捕获多个异常
try {
File file = new File("ss");
file.createNewFile();
Connection connection = DriverManager.getConnection("ss");
} catch (IOException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
//JDK1.7以后捕获多个异常
try {
File file = new File("ss");
file.createNewFile();
Connection connection = DriverManager.getConnection("ss");
} catch (IOException | SQLException e) {
e.printStackTrace();
}
以上就是JDK1.7的新特性!
JDK1.8
1)接口的默认方法
我们知道,在JDK1.8以前,我们定义的接口中有且只有抽象方法,不能添加其实现!JDK1.8为我们提供了相应的扩展功能,使得我们可以在接口中写入扩展方法!
//JDK1.8之前只允许定义抽象方法
public int add(int a,int b);
//JDK1.8允许定义扩展方法 使用default关键字
public default void play1() {
System.out.println("JDK1.8新特性!");
}
//JDK1.8允许静态扩展方法 使用static关键字
public static void play2() {
System.out.println("JDK1.8新特性!");
}
这样的话,实现该接口的子类可以直接使用该方法!
2)Lambda 表达式
我们知道,定义一个接口之后,如果想要引用,就必须实现该接口的抽象方法!当接口只有一个抽象方法时,使用匿名实现类显得十分复杂繁琐,程序可读性差!JDK1.8提出了Lambda表达式的概念,使得原本多余的代码更加简洁易懂!
比如:数字集合类实现倒排序
//JDK1.8之前实现集合倒排序
List<Integer> result = new ArrayList<>();
result.add(2);
result.add(3);
result.add(1);
Collections.sort(result, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
for (Integer a : result) {
System.out.println(a);
}
//JDK1.8之后实现数字集合倒排序
List<Integer> result = new ArrayList<>();
result.add(2);
result.add(3);
result.add(1);
Collections.sort(result, (o1,o2)-> o2 - o1);
for (Integer a : result) {
System.out.println(a);
}
发现没,你甚至只需要这一行简要的代码,就实现了数字集合的倒排序!!是不是觉得异常方便!
特别的:Lambda表达式仅适用于仅仅只包含一个抽象方法的接口!
3)函数式接口
上面提到的,仅仅包含一个抽象方法的接口就是函数式接口,它其实是和Lambda表达式配套的!JDK1.8允许使用@FunctionalInterface 注解标注一个函数式接口,该接口只有一个抽象方法!
//JDK1.8允许使用该注解标注函数式接口
@FunctionalInterface
interface MyTest{
public void play();
}
4)方法与构造函数引用
我们知道,通过Lambda表达式可以简化函数式接口的匿名实现类的编写,提高代码阅读效率!但是在某些情况下,比如实现代码已经有相关方法实现的时候,我们还可以做到更短!!
- 类::静态方法名
package com.jwang.test;
public class Test {
public static void main(String[] args) {
//传统Lambda表达式写法
MyTest test1 = s -> Integer.parseInt(s);
//使用方法引用
MyTest test2 = Integer::parseInt;
}
}
interface MyTest{
public Integer play(String s);
}
- 对象::实例方法名
package com.jwang.test;
public class Test{
public static void main(String[] args) {
A a2 = new B()::getInt;
System.out.println(a2.parseInt("2"));
}
}
@FunctionalInterface
interface A {
public Integer parseInt(String s);
}
class B {
public Integer getInt(String a){
return Integer.parseInt(a);
}
}
- 类::实例方法名
注意:若lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时可以使用!
package com.jwang.test;
public class Test{
public static void main(String[] args) {
C c = String::equals;
System.out.println(c.isEquals("a", "a"));
}
}
@FunctionalInterface
interface A {
public Integer parseInt(String s);
}
@FunctionalInterface
interface B {
public C getC();
}
@FunctionalInterface
interface C {
public boolean isEquals(String a,String b);
}
- 类::new
该表达式返回一个类的构造器的引用
package com.jwang.test;
public class Test{
public static void main(String[] args) {
B b = C::new;
System.out.println(b.getC().getInt("2"));
}
}
@FunctionalInterface
interface A {
public Integer parseInt(String s);
}
@FunctionalInterface
interface B {
public C getC();
}
class C {
public Integer getInt(String a){
return Integer.parseInt(a);
}
}
5)新的时间类
除了之前的Date、Calendar以外,JDK1.8提供了新的实践类简化程序编写:LocalDate/LocalTime/LocalDateTime
该处大家参考下API自行先去理解,博主也正在消化中,惭愧之至!