Java 8是Java自Java 5(发布于2004年)之后的最重要的版本。这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特性。
Lambda表达式和函数式接口
['læmdə] 朗姆蹬..
jdk8之前,各种的匿名内部类,大把大把拖沓的代码,程序毫无美感可言!既然java中一切皆为对象,那么,就类似于某些动态语言一样,函数也可以当成是对象,代码块也可以当成是对象啊,随着函数式编程的概念越来越深入人心,java中CODE=OBJECT的这一天终于到来了!
ambda的语法 包含3个部分:
(1)括弧包起来的参数 ,参数可以写类型,也可以不写
(2)一个箭头
(3)方法体,可以是单个语句,也可以是语句块 , 方法可以有返回,也可以无返回,如果有多个语句,还要返回值,需要加上return
lambda的定义:
lambda是方法的实现
lambda是延迟执行的
首先看一个用Runable的实现:
public static void main(String args[]){
Runnable r = ()->System.out.println("hello,lambda");
r.run();
}
为了配合lambda,jdk8引入了一个新的定义叫做:函数式接口(Functional interfaces)。
函数式接口
函数式接口的定义:
是一个接口
只有一个待实现的方法
jdk8开始,接口可以有default方法,所以,函数式接口也是可以有default方法的,但是,只能有一个未实现的方法。 与此对应,新引入了一个注解: @FunctionalInterface
这个注解只是起文档的作用,说明这个接口是函数式接口,编译器并不会使用这个注解来决定一个接口是不是函数式接口。
不管加不加@FunctionalInterface这个注解,下面的接口都是函数式接口:
interface Something {
public String doit(Integer i); //只有一个未实现的方法
}
函数式接口如何与lambda结合使用的呢?,只含有一个接口方法的函数式接口可以隐式转换为Lambda表达式。java.lang.Runnable和java.util.concurrent.Callable是函数式接口的最佳例子。在实践中,函数式接口非常脆弱:只要某个开发者在该接口中添加一个函数,则该接口就不再是函数式接口进而导致编译失败。为了克服这种代码层面的脆弱性,并显式说明某个接口是函数式接口,Java 8 提供了一个特殊的注解@FunctionalInterface(Java 库中的所有相关接口都已经带有这个注解了),举个简单的函数式接口的定义:
@FunctionalInterfacepublic interface Functional {
void method();
}
不过有一点需要注意,[默认方法和静态方法]是不会破坏函数式接口的定义,因此如下的代码是合法的。
@FunctionalInterfacepublic interface FunctionalDefaultMethods {
void method();
default void defaultMethod() {
}
}
列如:
public void test2(){
HaveArgs notArgs = (String x,Integer xx)->{
System.out.println(x);
System.out.println(xx);
};
notArgs.doSomething("good",32);
}
默认方法
类似抽象类里的公用方法
为什么不能用默认方法来重载equals,hashCode和toString?
接口不能提供对Object类的任何方法的默认实现。这意味着从接口里不能提供对equals,hashCode或toString的默认实现。
这刚看起来挺奇怪的,但考虑到一些接口实际上是在文档里定义他们的equals行为的。List接口就是一个例子了。因此,为什么不允许这样呢?
Brian Goetz在这个问题上的冗长的回复里给出了4个原因。我这里只说其中一个,因为那个已经足够说服我了:
它会变得更困难来推导什么时候该调用默认的方法。如果一个类实现了一个方法,那总是优先于默认的实现的。所有接口实例都对equals/hashCode/toString的非默认实现,一个在接口上这些的默认版本都是没用的,它也不会被编译。
Optional
Java应用中最常见的bug就是[空值异常]在Java 8之前,[Google Guava]引入了Optionals类来解决NullPointerException,从而避免源码被各种null检查污染,以便开发者写出更加整洁的代码。Java 8也将Optional加入了官方库。
Optional仅仅是一个容易:存放T类型的值或者null。它提供了一些有用的接口来避免显式的null检查。
Optional< String > fullName = Optional.ofNullable( null );
System.out.println( "Full Name is set? " + fullName.isPresent() );
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) );
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );
如果Optional实例持有一个非空值,则isPresent()方法返回true,否则返回false;orElseGet()方法,Optional实例持有null,则可以接受一个lambda表达式生成的默认值;map()方法可以将现有的Opetional实例的值转换成新的值;orElse()方法与orElseGet()方法类似,但是在持有null的时候返回传入的默认值。
Streams
Stream 的创建需要指定一个数据源,比如 java.util.Collection的子类,List或者Set, Map不支持。Stream的操作可以串行执行或者并行执行。
过滤age>12的元素,并输出:
listperson.stream()
.filter((it) -> it.getAge() >= 21)
.forEach((it) ->
System.out.println("Have a beer, " + it.getFirstName()));
Date/Time
Java 8中新的时间和日期管理API深受Joda-Time影响,并吸收了很多Joda-Time的精华。新的java.time包包含了所有关于日期、时间、时区、Instant(跟日期类似但是精确到纳秒)、duration(持续时间)和时钟操作的类。新设计的API认真考虑了这些类的不变性(从java.util.Calendar吸取的教训),如果某个实例需要修改,则返回一个新的对象。
Clock 时钟
Clock类提供了访问当前日期和时间的方法,Clock是时区敏感的,可以用来取代 System.currentTimeMillis() 来获取当前的微秒数。某一个特定的时间点也可以使用Instant类来表示,Instant类也可以用来创建老的java.util.Date对象。
Clock clock = Clock.systemDefaultZone();
long millis = clock.millis();
Instant instant = clock.instant();
Date legacyDate = Date.from(instant); // legacy java.util.Date
...
Annotation 注解
在Java 8中支持多重注解
以上特性可以满足java日常开发了,其他特性个人觉得可以直接引入scala开发包,使用scala.
网友评论