Java8新特性总结
刚毕业入职新公司,发现公司项目代码主要是以Java8为基础,其中用到了一些之前版本没有的特性,特此总结一下日常开发中使用比较多的Java8的新特性。
- lambda 表达式
- Stream 接口
- Date/Time API
- *接口的默认方法与静态方法
- Java虚拟机(JVM)的新特性
lambda 表达式
之前学过python,其语法就支持lambda表达式,通过lambda表达式,可以简化很多的语法。而Java8开始,Java也支持了lambda表达式。
示例1 使用lambda实现Runnable接口
//java8之前版本
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Before Java8, too much code for too little to do");
}
}).start();
//java8 lambda表达式实现
new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();
之前版本采用匿名类实现Runnable接口,使用lambda表达式后如上所示,使代码简洁了很多。
示例2 使用lambda对列表进行迭代
对集合类中的元素经常进行遍历迭代操作,而使用lamdba语法能够使得迭代操作的语法更简单。
//java8以前对集合进行迭代
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
System.out.println(feature);
}
示例3 Java 8中使用lambda表达式的Map和Reduce示例
//java8以后
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
features.forEach(n -> System.out.println(n));
// 使用Java 8的方法引用更方便,方法引用由::双冒号操作符标示,
features.forEach(System.out::println);
// 不使用lambda表达式为每个订单加上12%的税
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
for (Integer cost : costBeforeTax) {
double price = cost + .12*cost;
System.out.println(price);
}
// 使用lambda表达式
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);
Stream 接口
很多人对Stream的概念不是很理解,Java里对Stream的定义是“A sequence of elements supporting sequential and parallel aggregate operations.”可以看出,Stream是元素的集合,可以支持顺序和并行的操作。基于这一点,我们可以把Stream理解为一个高级迭代器。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序。
以前我们利用集合完成排序,取值操作可能需要的代码
List<Transaction> groceryTransactions = new Arraylist<>();
for(Transaction t: transactions){
if(t.getType() == Transaction.GROCERY){
groceryTransactions.add(t);
}
}
Collections.sort(groceryTransactions, new Comparator(){
public int compare(Transaction t1, Transaction t2){
return t2.getValue().compareTo(t1.getValue());
}
});
List<Integer> transactionIds = new ArrayList<>();
for(Transaction t: groceryTransactions){
transactionsIds.add(t.getId());
}
而通过Stream API
List<Integer> transactionsIds = transactions.parallelStream().
filter(t -> t.getType() == Transaction.GROCERY).
sorted(comparing(Transaction::getValue).reversed()).
map(Transaction::getId).
collect(toList());
它就像一个高级迭代器,可以在迭代的同时帮助我们完成我们需要的过滤排序的操作,极大地简化了我们的代码。
Date/Time API
让我们用例子来看一下新版API主要类的使用方法。第一个是Clock类,它通过指定一个时区,然后就可以获取到当前的时刻,日期与时间。Clock可以替换System.currentTimeMillis()与TimeZone.getDefault()。
// Get the system clock as UTC offset
final Clock clock = Clock.systemUTC();
System.out.println( clock.instant() );
System.out.println( clock.millis() );
控制台输出
2014-04-12T15:19:29.282Z
1397315969360
LocaleDate与LocalTime。LocaleDate只持有ISO-8601格式且无时区信息的日期部分。相应的,LocaleTime只持有ISO-8601格式且无时区信息的时间部分。LocaleDate与LocalTime都可以从Clock中得到。
// Get the local date and local time
final LocalDate date = LocalDate.now();
final LocalDate dateFromClock = LocalDate.now( clock );
System.out.println( date );
System.out.println( dateFromClock );
// Get the local date and local time
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now( clock );
System.out.println( time );
System.out.println( timeFromClock );
控制台输出
2014-04-12
2014-04-12
11:25:54.568
15:25:54.568
LocaleDateTime把LocaleDate与LocaleTime的功能合并起来,它持有的是ISO-8601格式无时区信息的日期与时间。
// Get the local date/time
final LocalDateTime datetime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now( clock );
System.out.println( datetime );
System.out.println( datetimeFromClock );
控制台输出
2014-04-12T11:37:52.309
2014-04-12T15:37:52.309
在我们日常开发过程中,经常要计算两个时间戳之间的时间,我们之前可能需要自己写逻辑计算,在java8中通过Duration类,我们可以快速得到两个时间戳之间的天数间隔。
// Get duration between two dates
final LocalDateTime from = LocalDateTime.of( 2014, Month.APRIL, 16, 0, 0, 0 );
final LocalDateTime to = LocalDateTime.of( 2015, Month.APRIL, 16, 23, 59, 59 );
final Duration duration = Duration.between( from, to );
System.out.println( "Duration in days: " + duration.toDays() );
System.out.println( "Duration in hours: " + duration.toHours() );
控制台输出
Duration in days: 365
Duration in hours: 8783
接口的默认方法与静态方法
java8之前,接口中的所有方法都必须是抽象方法,并且一个类实现接口时,也必须实现其中的所有方法,否则其必须为抽象类。java8中,新增了接口的默认方法和静态方法
public interface MyInter {
default void df(){ //声明一个接口的默认方法
System.out.println("i'am default f");
sf(); //调用本接口的类方法
} static void sf(){ //声明一个接口的类方法
System.out.println("i'am static f");
}
}
public class Man implements MyInter{ //Man类实现MyInter接口
}
public class Test extends Man{
public static void main(String[] args) {
Man man=new Man();
man.df(); //通过man对象调用MyInter接口的默认方法df()
}
}
如上所示,默认方法可以通过实现类实例化的对象调用,而静态方法只能在本接口中调用或者在实现类中实现。
Java虚拟机(JVM)的新特性
PermGen空间被移除了,取而代之的是Metaspace(JEP122)。JVM选项-XX:PermSize与-XX:MaxPermSize分别被-XX:MetaSpaceSize与-XX:MaxMetaspaceSize所代替。
总结了一些常用的Java8的新特性,听说Java9也快要来了,果然coding这一行要不停的学习啊~