Java 8于14年发布到如今已经有5年时间了,通过时间的磨练,毫无疑问,Java 8是继Java 5(发布于2004年)以后的又一个很是最重要的版本。由于Java 8里面出现了很是多新的特征,这些特征主要包含语言、编译器、库、工具和JVM等方面,具体以下:html
以上最值得咱们学习的应该就是Lambda表达式、Stream API和新的日期处理类。并非说其余的就不用去学了,仍是要去了解一下的,而这三个对咱们来讲很重要因此必须学习。java
Lambda表达式本质上是一个匿名函数(方法),它没有方法名,没有权限修饰符,没有返回值声明。看起来就是一个箭头(->)从左边指向右边。咱们能够把Lambda表达式理解为一段能够传递的代码(将代码像数据同样进行传递),它的核心思想是将面向对象中的传递数据变成传递行为。Lambda表达式的出现就是为了简化匿名内部类,让匿名内部类在方法中做为参数的使用更加方便(这里我的理解,可能有误!)。因此使用Lambda表达式可让咱们的代码更少,看上去更简洁,代码更加灵活。而Lambda表达式做为一种更紧凑的代码风格,使得Java的语言表达能力获得了提高。但也有它的缺点所在,若是Lambda表达式用的很差的话,调试运行和后期维护很是的麻烦。express
Lambda表达式在Java语言中引入了一个新的语法元素和操做符。这个操做符为"->",该操做符被称为Lambda操做符或箭头操做符,它将Lambda分为两个部分:数组
Java8中的Lambda表达式的基本语法为:app
(params) -> expression
(params) -> statement
(params) -> { statements }dom
上面只是基本的语法而已,因此看起来比较的简单,其中的具体使用方法有不少,以下:编辑器
①、无参数,无返回值 void。
() -> System.out.print(“Lambda…”) ;ide②、有一个参数,但无返回值 void 。函数
(String s) -> System.out.print(“Lambda…”) ;工具
③、有参数,可是参数数据类型省略,由编译器推断,称为‘类型推断’。
(s) –> System.out.print(“Lambda…”) ;
④、若只有一个参数,方法的括号能够省略,若是多个参数则必须写上 。
s–> System.out.print(“Lambda…”) ;
⑤、有参数,且有返回值,若是显式返回语句时就必须使用花括号“{}”。
(s,t) –> s+t ;
或
(s,t) –> {return s+t;};
⑥、若是有两个或两个以上的参数,而且有多条语句则须要加上“{}”,一条执行语句能够省略。
(s,t) –> {
System.out.print(s) ;
System.out.print(t) ;
return s+t;
};
因此到目前为止,咱们对Lambda表达式有了基本的认识,而前面讲了那么多的理论,就是为了接下来的快乐时光(写代码),用几个简单的例子来让咱们好好理解一下Lambda表达式的使用:
public class LambdaTest { public static void main(String[] args) { //一、建立线程举例 //普通写法 Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("Ordinary Writing"); } }); thread.start(); //Lambda写法。无参无返回void Thread thread1 = new Thread(() -> System.out.println("Lambda Writing")); thread1.start(); //二、排序举例 //普通写法,默认升序 List<Integer> list = Arrays.asList(26, 65, 13, 79, 6, 123); Collections.sort(list,new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2); } }); System.out.println(list.toString()); //Lambda表达式写法。有参有返回,“类型推断” Collections.sort(list,(o1,o2)-> Integer.compare(o1,o2)); System.out.println(list.toString()); //三、遍历list集合 //普通写法 list.forEach(new Consumer<Integer>() { @Override public void accept(Integer integer) { System.out.println(integer); } }); //Lambda表达式写法。遍历List集合,forEach方法中的参数是Consumer<? super T> action //其中Consumer是Java8新的新出现的函数式接口,下面会讲到函数式接口 list.forEach(alist-> System.out.println(alist));//只有一个参数可省略括号 } }
注意:要使用Lambda表达式的前提是函数式接口,因此接下来学习一下函数式接口。
函数式接口(Functional Interface)也是Java8中的新特征。
函数式接口就是只能有一个抽象方法,同时能够有多个非抽象方法的接口(Java8中接口能够定义普通方法)。
这样接口就能够被隐式转换为Lambda表达式。
若是咱们须要自定义一个函数式接口,就须要用到Java 8提供的一个特殊的注解@FunctionalInterface,该注解会检查它是不是一个函数式接口,简单的举个定义函数式接口的例子,代码以下:
//定义函数式接口注解 @FunctionalInterface public interface MyInterface { //抽象方法 void method(); //void method1();不能再定义 //默认方法,必须用default修饰 default void defaultMethod(){ System.out.println("默认方法..."); } //静态方法方法 static void staticMethod(){ System.out.println("静态方法..."); } }
上面的例子能够很容易的转换成以下Lambda表达式:
MyInterface myInterface = () -> System.out.println("MyInterface...");
我须要注意的一点是,接口中的默认方法和静态方法并不会破坏函数式接口的定义,既不会影响到Lambda表达式。同时也正由于Lambda表达式的引入,因此函数式接口也变得流行起来。
其实早在Java8以前就有不少接口是函数式接口,只是在Java8才正式提出之一特性,例如:
除了以上这些,在Java 8中还增长了一个新的包:java.util.function。它们里面包含了经常使用的函数式接口,该包下定义的函数式接口很是多,这里只列举比较重要的四个,以下:
(博客园的表格编辑器真的无力吐槽,实在太垃圾了,而后从其余编辑器编辑好了在截图过来!)
如下是这四个函数式接口的简单举例,理解Lambda表达式以后很容易写出来:
public class FunctionInterfaceTest { public static void main(String[] args) { //Consumer<T> : void accept(T t); Consumer<Integer> consumer = (a) -> System.out.println("消费型接口..."+a); consumer.accept(1000); //Function<T, R> : R apply(T t); Function<String,String> function = (b) -> b; Object apply = function.apply("函数型接口..."); System.out.println(apply); //Predicate<T> : boolean test(T t); Predicate predicate = (c) -> c.equals(10); boolean test = predicate.test(10); System.out.println("判定型接口..."+test); //Supplier<T> : T get(); Supplier supplier=()->(int)(Math.random() * 50); Object o = supplier.get(); System.out.println("供给型接口..."+o); } }
除了上面的这些基本的函数式接口,java.util.function包下还提供了一些针对多个参数的函数式接口,例如BiFunction<T,U,R>,它接收类型为T和U的对象,而后返回R对象。后面还有BiConsumer<T,U>、BiPredicate<T,U>等。一样还提供一些针对基本数据类型的特化函数式接口,例如XXXFunction:表示只接收XXX数据类型、XXXToXXXFunction:接收前一个XXX类型,而后返回后一个XXX类型、ToXXXFunction:表示返回值为XXX类型等等不少这样的类。(其中XXX只能是Int、Double和Long这三个基本数据类型)
若是有须要学习这些API的,能够自行去java.util.function包下查看学习,这里很少作描述。
经过上面Lambda表达式的学习,若是你认为Lambda表达式已经让代码够简洁了,那么这里还有一个更加简洁的方法——方法引用。
简单来讲,方法引用就是进一步的简化Lambda表达式声明的一种语法糖。也正是由于方法引用实在太简洁了,因此学习方法引用前必需要对Lambda表达式很是的熟悉,不然学习方法引用会有点吃力。
方法引用使用操做符 “::” 将对象或类的名字和方法名分隔开来。方法引用有不少种,它们的语法以下(注意后面是不要写括号的):
在使用方法引用时要注意一点:引用的函数一定与定义的接口形参和返回值类型一致。
先用System.out.println()简单举例:
//System.out.println()简单举例 @Test public void test() { Consumer<String> consumer = (str) -> System.out.println(str); consumer.accept("Lambda表达式"); PrintStream out = System.out; Consumer consumer1 = out::println; consumer1.accept("方法引用"); }
其中Consumer中的accept(T t)方法中是一个参数,返回值是void,PrintStream中的println(Object x)也是一个参数,返回值也是void 。
①、静态方法引用。语法格式:ClassName::staticMethodName。
//一、静态方法用——ClassName::staticMethodName @Test public void test1() { //Lambda表达式 BiFunction<Double, Double, Double> biFunction = (x, y) -> Math.max(x, y); System.out.println(biFunction.apply(11.1, 22.2)); System.out.println("-------------"); //方法引用 BiFunction<Double, Double, Double> biFunction1 = Math::max; System.out.println(biFunction1.apply(33.3, 44.4)); //另一组例子,其中c1与c2是同样的 Comparator<Integer> c1 = (x, y) -> Integer.compare(x, y); Comparator<Integer> c2 = Integer::compare; }
②、实例上的实例方法引用。语法格式:instanceName::methodName。
//二、实例上的实例方法引用——instanceName::methodName @Test public void test2(){ Consumer<String> consumer = (str) -> System.out.println(str); Consumer consumer1 = System.out::println; Person person = new Person("唐浩荣", 20, "China"); Supplier supplier = () -> person.getName(); Supplier supplier1 = person::getName; }
③、类上的实例方法引用。语法格式:ClassName::methodName 。
//三、类上的实例方法引用——ClassName::methodName public void test3(){ BiPredicate<String, String> biPredicate = (x, y) -> x.equals(y); BiPredicate<String, String> biPredicate1 = String::equals; Function<Person, String> fun = (p) -> p.getName(); Function<Person, String> fun2 = Person::getName; }
④、父类上的实例方法引用。语法格式:super::methodName。
//四、父类上的实例方法引用——super::methodName @Test public void test4(){ Person person=new Person(); Supplier supplier = () -> super.toString(); Supplier supplier1 =super::toString; }
⑤、构造方法引用。语法格式:ClassName::new。
//五、构造方法引用——ClassName::new @Test public void test5() { Function<String, String> function = (n) -> new String(n); String apply = function.apply("Lambda构造方法"); System.out.println(apply); Function<String, String> function1 = String::new; String apply1 = function.apply("构造方法引用"); System.out.println(apply1); }
⑥、数组构造方法引用:TypeName[]::new。
//六、数组构造方法引用——TypeName[]::new @Test public void test6() { Function<Integer, Integer[]> function = (n) -> new Integer[n]; //Integer integer[]=new Integer[20]; Integer[] apply = function.apply(3); apply[0] = 1; for (Integer integer : apply) { System.out.println(integer); } System.out.println("-----------------"); Function<Integer, Integer[]> function1 = Integer[]::new; Integer[] apply1 = function1.apply(5); apply1[0] = 11; apply1[1] = 22; for (Integer integer : apply1) { System.out.println(integer); } }