在面试中经常会问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);