简单总结一下JDK1.7和1.8的新特性,总体上点到为止,想深入的话还需继续深究其中的原理。
JDK1.7
1. 二进制变量的表示,支持将整数类型用二进制来表示
所有整数int、short、long、byte都可以用二进制表示,表示的方法就是在二进制数字前面加上0b
byte num1 = 0b00001001; //1个字节8位
short num2 = 0b0010000101000101; //2个字节16位
int num3 = 0b10100001010001011010000101000101;; //4个字节32位
long num4 = 0b0010000101000101101000010100010110100001010001011010000101000101L;//8个字节64位
System.out.println(num1);
System.out.println(num2);
System.out.println(num3);
System.out.println(num4);
输出结果:
9
8517
-1589272251
2397499697075167557
2.Switch语句支持String类型。
在1.6的版本switch的参数中只支持byte、short、char、int、long以及他们的包装类(自动拆箱和自动装箱的支持下),然后在jdk1.7支持了String作为参数。
String str = "1";
switch (str){
case "1":
System.out.println("NO.1");
break;
case "2":
System.out.println("NO.2");
break;
case "3":
System.out.println("NO.3");
break;
default:
System.out.println("fail");
}
输出结果:
NO.1
3. Try-with-resource语句
- 实现java.long.AutoCloseable接口的资源都可以放到try中
- 跟final里面的关闭资源类似;
- 按照声明逆序关闭资源;
- Try块抛出的异常Throwable.getSuppressed获取。
- 如果try代码块和try-with-resources语句同时抛出异常,这个方法将会最终抛出try代码块里面的异常,try-with-resources语句里面抛出的异常被压抑了。
public static void writeToFileZipFileContents(String zipFileName,
String outputFileName)
throws java.io.IOException {
java.nio.charset.Charset charset =
java.nio.charset.StandardCharsets.US_ASCII;
java.nio.file.Path outputFilePath =
java.nio.file.Paths.get(outputFileName);
// Open zip file and create output file with
// try-with-resources statement
try (
java.util.zip.ZipFile zf =
new java.util.zip.ZipFile(zipFileName);
java.io.BufferedWriter writer =
java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
) {
// Enumerate each entry
for (java.util.Enumeration entries =
zf.entries(); entries.hasMoreElements();) {
// Get the entry name and write it to the output file
String newLine = System.getProperty("line.separator");
String zipEntryName =
((java.util.zip.ZipEntry)entries.nextElement()).getName() +
newLine;
writer.write(zipEntryName, 0, zipEntryName.length());
}
}
}
在这个例子中,try-with-resources语句包含了两个用分号隔开的声明:ZipFile和BufferedWriter。当代码块中代码终止,不管是正常还是异常,BufferedWriter和ZipFile对象的close方法都会自动按声明的相反顺序调用。
下面的例子用try-with-resources语句自动关闭一个java.sql.Statement对象:
public static void viewTable(Connection con) throws SQLException {
String query = "select COF_NAME, SUP_ID, PRICE, SALES, TOTAL from COFFEES";
try (Statement stmt = con.createStatement()) {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
String coffeeName = rs.getString("COF_NAME");
int supplierID = rs.getInt("SUP_ID");
float price = rs.getFloat("PRICE");
int sales = rs.getInt("SALES");
int total = rs.getInt("TOTAL");
System.out.println(coffeeName + ", " + supplierID + ", " +
price + ", " + sales + ", " + total);
}
} catch (SQLException e) {
JDBCTutorialUtilities.printSQLException(e);
}
}
4.Catch支持多个异常
public static void main(String[] args) throws Exception {
try {
testthrows();
} catch (IOException | SQLException ex) {
throw ex;
}
}
public static void testthrows() throws IOException, SQLException {
}
5.数字类型的下划线表示 更友好的表示方式
不过要注意下划线添加的一些标准,下划线不允许出现在开头和结尾。
long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi = 3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;
//float pi1 = 3_.1415F; // Invalid; cannot put underscores adjacent to a decimal point
//float pi2 = 3._1415F; // Invalid; cannot put underscores adjacent to a decimal point
//long socialSecurityNumber1= 999_99_9999_L; // Invalid; cannot put underscores prior to an L suffix
//int x1 = _52; // This is an identifier, not a numeric literal
int x2 = 5_2; // OK (decimal literal)
//int x3 = 52_; // Invalid; cannot put underscores at the end of a literal
int x4 = 5_______2; // OK (decimal literal)
//int x5 = 0_x52; // Invalid; cannot put underscores in the 0x radix prefix
//int x6 = 0x_52; // Invalid; cannot put underscores at the beginning of a number
int x7 = 0x5_2; // OK (hexadecimal literal)
//int x8 = 0x52_; // Invalid; cannot put underscores at the end of a number
int x9 = 0_52; // OK (octal literal)
int x10 = 05_2; // OK (octal literal)
//int x11 = 052_; // Invalid; cannot put underscores at the end of a number
6.泛型实例的创建可以通过类型推断来简化
可以去掉后面new部分的泛型类型,只用<>就可以了。
新特性之前:
List strList = new ArrayList();
List<String> strList = new ArrayList<String>();
List<Map<String, List<String>>> strList5 = new ArrayList<Map<String, List<String>>>();
新特性:
List<String> strList2 = new ArrayList<>();
List<Map<String, List<String>>> strList3 = new ArrayList<>();
List<String> list = new ArrayList<>();
7.在可变参数方法中传递非具体化参数,改进编译警告和错误
Heap pollution 指一个变量被指向另外一个不是相同类型的变量。例如
List l = new ArrayList<Number>();
List<String> ls = l; // unchecked warning
l.add(0, new Integer(42)); // another unchecked warning
String s = ls.get(0); // ClassCastException is thrown
Jdk7:
public static <T> void addToList (List<T> listArg, T... elements) {
for (T x : elements) {
listArg.add(x);
}
}
你会得到一个warning
warning: [varargs] Possible heap pollution from parameterized vararg type
要消除警告,可以有三种方式
1.加 annotation @SafeVarargs
2.加 annotation @SuppressWarnings({"unchecked", "varargs"})
3.使用编译器参数 –Xlint:varargs;
JDK8的新特性
JDK8新特性1.接口内允许非抽象方法
Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法。
public interface JDK8Interface {
// static修饰符定义静态方法
static void staticMethod() {
System.out.println("接口中的静态方法");
}
// default修饰符定义默认方法
default void defaultMethod() {
System.out.println("接口中的默认方法");
}
}
2. Lambda 表达式
λ表达式有三部分组成:参数列表,箭头(->),以及一个表达式或语句块。
(x, y) -> { return x + y; } ;
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式:
Collections.sort(names, (String a, String b) -> {
return b.compareTo(a);
});
//或者是这样写,可以直接省略掉大括号{}和return关键字。
Collections.sort(names, (a, b) -> b.compareTo(a));
为什么lambda表示式可以这样随意的使用?
lambda表达式是如何和java系统的类型进行对应的?每个lambda表达式都对应一个指定的类型,这个指定的类型是由接口确定的。
功能性接口,它必须且恰好只包含一个抽象方法声明。被指定接口类型所对应的lambda表达式刚好和这个接口的抽象方法想匹配。因为默认方法不是抽象的,因此你可以在你的功能性接口中添加多个默认方法。
我们可以将任意的接口用作lambda表示式,只要该接口仅仅包含一个抽象方法。为了确保你定义的接口达到要求,你可以在接口上添加@FunctionInterface注解。编译器可以检测到该注解并判断你的接口是否满足条件,如果 你定义的接口包含多个抽象方法时,编译器便会报错。
例如:下面就是一个功能性接口
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
进行lambda表示式使用:
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted); // 123
3.方法与构造函数引用
Java 8 允许你使用 :: 关键字来传递方法或者构造函数引用,上面的代码展示了如何引用一个静态方法,我们也可以引用一个对象的方法.
前部分的示例在使用静态方法引用的情况下可以被进一步的简化:
Converter<String, Integer> converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted); // 123
java8可以让你通过关键字::来传递方法和构造函数的引用。上面的示例展示了如何引用一个静态方法。我们同样也可以引用对象方法。
class Something {
String startsWith(String s) {
return String.valueOf(s.charAt(0));
}
}
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted); // "J"
现在我们将看到关键字::如何为构造函数工作。首先我们定义一个拥有不同构造函数的bean类:
class Person {
String firstName;
String lastName;
Person() {}
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
接下来我们定义一个用来创建类person的工厂接口:
interface PersonFactory<P extends Person> {
P create(String firstName, String lastName);
}
不使用通常的手动实现工厂类,我们通过使用构造函数将所有的工作联合在一起:
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");
网友评论