jdk1.7/jdk1.8新特性
在面試中經常會問jdk1.6,jdk1.7,jdk1.8的區別:
最近面試的時候的面試官問我jdk8的新特性:
我回答了幾個,他提問到:為什麼defualt沒有被推廣,有什麼弊端。
我很蒙圈,在這裡新增下回答:
我目前還不知道
jdk1.7新增特性:
1 switch 支援string
jdk1.6: int,short,char,byte,Enum
jdk1.7: string,int,short,char,byte,Enum
2 泛型自動判斷
ArrayList al1 = new ArrayList(); // Old
ArrayList al2 = new ArrayList<>(); // New
3 新的整數字面表達方式 - “0b"字首和”_"連數符
byte b1 = 0b00100001; // New
byte b2 = 0x21; // Old
byte b3 = 33; // Old
System.err.println(b1); //33
這裡有一些其它的不能在數值型字面值上用下劃線的地方:
1 在數字的開始或結尾
2 在浮點型數字的小數點前後
3 F或L下標的前面
4 該數值型字面值是字串型別的時候
int a4 = 5_______2; // 有效的
4.在單個catch程式碼塊中捕獲多個異常,以及用升級版的型別檢查重新丟擲異常
1.6
catch (IOException ex) { logger.error(ex); throw new MyException(ex.getMessage()); catch (SQLException ex) { logger.error(ex); throw new MyException(ex.getMessage()); }catch (Exception ex) { logger.error(ex); throw new MyException(ex.getMessage()); }
1.7
catch (IOException | SQLException | Exception ex) {
logger.error(ex);
throw new MyException(ex.getMessage());
可以不用重新指定異常型別
static class FirstException extends Exception { } static class SecondException extends Exception { } public void rethrowException(String exceptionName) throws Exception { try { if (exceptionName.equals("First")) { throw new FirstException(); } else { throw new SecondException(); } } catch (Exception e) { //下面的賦值沒有啟用重新丟擲異常的型別檢查功能,這是Java 7的新特性 // e=new ThirdException(); throw e; } }
5.try-with-resources語句
1.7之前,須在finnally中手動關閉資源
/**
* JDK1.7之前我們必須在finally塊中手動關閉資源,否則會導致資源的洩露
* @author Liao
*
*/
public class PreJDK7 {
public static String readFirstLingFromFile(String path) throws IOException {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(path));
return br.readLine();
} catch (IOException e) {
e.printStackTrace();
} finally {//必須在這裡關閉資源
if (br != null)
br.close();
}
return null;
}
}
1.7
/**
* JDK1.7之後就可以使用try-with-resources,不需要
* 我們在finally塊中手動關閉資源
* @author Liao
*/
public class AboveJDK7 {
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
}
jdk1.8新增特性:
1.8新特性
1.8主要是簡化寫法
1. default關鍵字
在1.8以前介面內的方法只能是抽象方法,在1.8可以新增default修飾的方法,且實現類不能繼承該方法。
優勢:若需要新增一個統一的方法,以前需要在每一個實現類中繼承,現在只需要在介面類增加一個defualt方法即可。
介面類
public interface interFaceClass {
void myFuncation();
default void mydefualtFuncation(){
System.err.println("this is a defualt funcation");
};
}
實現類
public class implementClass implements interFaceClass {
@Override
public void myFuncation() {
// TODO Auto-generated method stub
}
}
測試類
public static void main(String[] args) {
interFaceClass test = new implementClass();
test.mydefualtFuncation(); //this is a defualt funcation
}
2. 時間類:
localdate
jdk1.8提供了新的API解決之前版本關於獲取時間上繁瑣及SimpleDateFormat的執行緒不安全.總體來看新的API提供了許多便捷的方法獲取想要的時間。
localdate
localtime
localdatetime
zonedatetime
為方便使用和記憶,我在下面的例子中逐一獲取並對比;
測試時間是 2018-09-30
1.7
Date date = new Date();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//獲取當前時間
date.getDate();// 30
System.out.println(date);// Sun Sep 30 09:51:04 CST 2018
//按格式獲取當前時間
System.out.println(df.format(date)); // 2018-09-30 09:51:04
//獲取前一天時間
Calendar cal=Calendar.getInstance();
cal.add(Calendar.DATE, -1);
Date yesterday = cal.getTime();
System.out.println(df.format(yesterday )); // 2018-09-29 09:51:04
//獲取指定時間
String dateOfBirthString= "2017-10-11";
Date dateOfBirth = new SimpleDateFormat("yy-MM-dd").parse(dateOfBirthString);
System.out.println(df.format(dateOfBirth )); // 2017/10/11 00:00:00
//比較兩個時間是否相同
boolean flag = dateOfBirth.equals(dateTody);
System.out.println("flag: "+flag);// flag; false
//比價兩個時間的差
//太麻煩了我就不寫了
//將日期轉化為字串
String dateString1 = dateTody.toString;
String dateString2 = df.format(dateTody);
1.8
// 獲取當前時間
LocalDate dateTody = LocalDate.now();
LocalTime timeNow=LocalTime.now();
System.out.println(dateTody+" "+ timeNow);// 2018-09-30 10:36:45.260
int year = dateToday.getYear();
int month = dateToday.getMonthValue();
int day = dateToday.getDayOfMonth();
// 按格式獲取當前時間
DateTimeFormatter formatters = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
String text = dateToday.format(formatters);
System.err.println(text);//2018年09月30日
//獲取前一天時間
LocalDate yestoday = dateToday.minusDays(1);
System.err.println(yestoday );//2018-09-29
//獲取指定時間
LocalDate dateOfBirth = LocalDate.of(2017, 10, 11);
System.err.println(dateOfBirth );//2017-10-11
//比較兩個時間是否相同
Boolean flag = dateToday.equals(dateOfBirth);
//比價兩個時間的差
long dy=( dateToday.toEpochDay() - dateOfBirth.toEpochDay() );
System.err.println("相差:"+dy);//相差:354
//將日期轉化為字串
dateToday.toString();
//比較時用的方法:
//一年以後
LocalDate lastYear = dateToday.plus(1,ChronoUnit.YEARS);
System.err.println(lastYear);//2019-09-30
// 取本月第1天:
LocalDate firstDayOfThisMonth1=dateToday.withDayOfMonth(1);
LocalDate firstDayOfThisMonth = dateToday.with(TemporalAdjusters.firstDayOfMonth()); // 2018-04-01
// 取本月第2天:
LocalDate secondDayOfThisMonth = dateToday.withDayOfMonth(2); // 2018-04-02
// 取本月最後一天,再也不用計算是28,29,30還是31:
LocalDate lastDayOfThisMonth = dateToday.with(TemporalAdjusters.lastDayOfMonth()); // 2018-04-30
// 取下一天:
LocalDate firstDayOfNextMonth = lastDayOfThisMonth.plusDays(1); // 變成了2018-05-01
// 取2017年1月第一個週一:
LocalDate firstMondayOf2017 = LocalDate.parse("2017-01-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)); // 2017-01-02
3 lamdba 表示式
“Lambda表示式”是一個匿名函式,是jdk1.8重要的新特性
首先了解下內部類的使用和優點:內部類可以訪問外部類,但只有外圍的外部類才能訪問該內部類,內部類可以使得該類實現多繼承,
匿名內部類是唯一一種沒有構造器的類,且不能有靜態變數
這是一個內部類呼叫
建立靜態內部類物件的一般形式為: 外部類類名.內部類類名 xxx = new 外部類類名.內部類類名()
建立成員內部類物件的一般形式為: 外部類類名.內部類類名 xxx = 外部類物件名.new 內部類類名()
public class outerClass {
int a=1;
class innerClass{
int a=2;
void Printable(){
int a =3;
System.err.println(a);
System.err.println(this.a);
System.err.println(outerClass.this.a);
}
}
public static void main(String[] args) {
outerClass out1 = new outerClass();
outerClass.innerClass inner2 = out1.new innerClass();
inner2.Printable();
}
}
}
public abstract class Person {
abstract void f();
}
Person 是一個抽象類是不能被例項化的,但是我們通過匿名內部類就可以實現對其的向下轉型
public class Test {
public static void main(String[] args) {
Person p = new Person() {
@Override
void f() {
// TODO Auto-generated method stub
System.err.println("我是匿名內部類");
}
};
p.f();
}
}
上面等效於
Person person=new child();
person.f(); //child是Person 子類
使用lamdba實現上面的匿名內部類(Person 必須是介面)
Person p2 =() -> System.err.println("我是匿lambda");
p2.f();
使用lamdba實現對陣列的遍歷
List<String> list = Arrays.asList("我是1","我是2");
for ( String a : list) {
System.err.println(a);
}
list.forEach( a -> System.err.println("我是lambda"+a) );// 一句話搞定
list.forEach(System.out :: println); //println無法寫引數
看了上面的例子我們再來解釋下lambda表示式,由編譯器推斷並幫你轉換包裝為常規的程式碼,因此你可以使用更少的程式碼來實現同樣的功能。
基本語法
(parameters) -> expression
或
(parameters) ->{ statements; }
變數作用域
lambda 表示式只能引用標記了 final 的外層區域性變數,這就是說不能在 lambda 內部修改定義在域外的區域性變數,否則會編譯錯誤。
String ab=" 我是變數";
Person p = new Person() {
@Override
public void f() {
// TODO Auto-generated method stub
System.err.println("我是匿名內部類"+ab); //匿名內部類一樣會報錯
}
};
p.f();
Person p2 =() -> System.err.println("我是匿lambda"+ab);
p2.f();
ab="123131231"; // 當ab變數不賦值時上述方法均不會報錯,但是改變值之後就都報錯了,需要將ab設定為final型別防止出現編譯錯誤
對陣列排序(對下列方法使用lambda改造)
String[] players = {"Rafael Nadal", "Novak Djokovic",
"Stanislas Wawrinka", "David Ferrer",
"Roger Federer", "Andy Murray",
"Tomas Berdych", "Juan Martin Del Potro",
"Richard Gasquet", "John Isner"};
// 1.1 使用匿名內部類根據 name 排序 players
Arrays.sort(players, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return (s1.compareTo(s2));
}
});
lambda
Arrays.sort(players,(s1,s2)->s1.compareTo(s2));//一句話搞定,注意lambda針對的是匿名內部類
4 函式式介面
@FunctionalInterface
java 8提供 @FunctionalInterface作為註解,這個註解是非必須的,只要介面符合函式式介面的標準(即只包含一個方法的介面),虛擬機器會自動判斷, 但 最好在介面上使用註解@FunctionalInterface進行宣告,以免團隊的其他人員錯誤地往介面中新增新的方法。
5 Stream()
//排序
String[] players = {"a", "e", "d", "c"};
// 1.1 使用匿名內部類根據 name 排序 players
Arrays.sort(players, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
// TODO Auto-generated method stub
return (s1.compareTo(s2));
}
});
for (String string : players) {
System.err.println(string);
}
Arrays.sort(players,(s1,s2)->s1.compareTo(s2));
//steam()
List <Integer> steamtest = Arrays.asList(1,2,50,30);
//對元素操作
List<Integer > getList = steamtest.stream().map(a->a*2).collect(Collectors.toList());
getList.forEach(System.out::println);
//排序
List<Integer > getsortList = steamtest.stream().sorted((a1,a2)->a1.compareTo(a2)).collect(Collectors.toList());
getsortList.forEach(System.out::println);
//過濾
List<Integer > getFilterList =steamtest.stream().filter(s-> (s>=2)).collect(Collectors.toList());
getFilterList.forEach(System.out::println);
//生成陣列
Integer[] atest = steamtest.stream().toArray(Integer[]::new);
//對元素疊加計算
int value = steamtest.stream().reduce(0, (acc,item)->acc+item).intValue();
System.err.println(value);