java8和lamda表达式

一. 接口的默认方法和静态方法

使用两个新概念扩展了接口的含义:默认方法default和静态方法static。

default

  • 抽象方法需要实现,而默认方法不需要。
  • 实现类可以继承或者覆写default方法。
  • 静态方法不可以覆盖。
public interface MyInterface {
    double calculate(int a);

    default double sqrt(int a) {
        return Math.sqrt(a);
    }
    
    public static <T> void print(Iterable<T> iterable) {
        System.out.println(iterable);
    }
}

应用:在jdk1.8中,很多接口添加了新方法,比如:java.util.Collection的stream()、parallelStream()、forEach()和removeIf()。

二. Lambda表达式和函数式接口

1. 函数式接口

Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。
@FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。
“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。(因为默认方法不算抽象方法,所以你也可以给你的函数式接口添加默认方法)

  • JDK 8之前已有的函数式接口
    java.lang.Runnable
    java.util.concurrent.Callable
    java.security.PrivilegedAction
    java.util.Comparator
    java.io.FileFilter
    java.nio.file.PathMatcher
    java.lang.reflect.InvocationHandler
    java.beans.PropertyChangeListener
    java.awt.event.ActionListener
    javax.swing.event.ChangeListener

  • 新定义的函数式接口
    java.util.function中定义了几组类型的函数式接口以及针对基本数据类型的子类。
    Predicate— 传入一个参数,返回一个bool结果, 方法为boolean test(T t)
    Consumer— 传入一个参数,无返回值,纯消费。 方法为void accept(T t)
    Function
    Supplier— 无参数传入,返回一个结果,方法为T get()
    UnaryOperator— 一元操作符, 继承Function
    BinaryOperator— 二元操作符, 传入的两个参数的类型和返回类型相同, 继承BiFunction
    Java API的对函数式接口都已经标明了, 如

2. Lambda表达式

就是接口实现,接口接收对象的时候使用。
lambda语法是针对“回调接口”和“匿名内部类”作出的改进。
java对象都是重量级,对象只有一个方法的很多,比如接口。

Collections中添加的forEach方法,需要Consumer接口作为入参,接口如下:

@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
    default Consumer<T> andThen(Consumer<? super T> after) {
        Objects.requireNonNull(after);
        return (T t) -> { accept(t); after.accept(t); };
    }
}

匿名内部类方式:

Arrays.asList( "a", "b", "d" ).forEach(new Consumer<String>() {
        @Override
    public void accept(String s) {
        //TODO
    }
});
  • lambda的语法包括三部分
  1. 参数列表
  2. 箭头符号"->"
  3. 代码块。

完整的

public class LambdaTest {      
    public static void main(String... args) {  
        //这里有{}和return 以及 ;  
        Runnable r = () -> { System.out.println("hello world"); };  
          
        //这里不需要{}和return  
        java.util.Comparator<String> c = (String s1, String s2) -> s2.length()-s1.length();          
        r.run();  
        System.out.println(c.compare("s1", "12323"));  
    }  
}

自己实现lamda表达式

public class LambdaTest {  
    interface lambdaInterface {  
        public void me(String str);  
    }  
  
    public static void main(String... args) {  
        lambdaInterface li = (String s)->{System.out.println(s);};  
        li.me("hello world!");  
    }  
}

自动推导类型,可以省略类型

Collections.sort(asList("a", "b", "d"), new Comparator<T>() {
    @Override
    public int compare(T o1, T o2) {
        return 0;
    }
});

Collections.sort(names, (String a, String b) -> b.compareTo(a));
Collections.sort(names, (a, b) -> b.compareTo(a));

总结:

  1. 完整表达式:lambdaInterface li = (String s)->{System.out.println(s); return xxx};
  2. 无参数情况:() -> System.out.println("hello world");
  3. 参数自动推导:Collections.sort(names, (a, b) -> b.compareTo(a));
  4. 只有一行可以省略返回值:Collections.sort(names, (a, b) -> b.compareTo(a));

三. 方法引用

可以直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用。

  1. 构造器引用
    语法是Class::new,或者更一般的形式:Class::new。注意:这个构造器没有参数。
    final Car car = Car.create( Car::new ); final List< Car > cars = Arrays.asList( car );
  2. 静态方法引用
    语法是Class::static_method。注意:这个方法接受一个Car类型的参数。
    cars.forEach( Car::collide );
  3. 某个类的成员方法的引用
    语法是Class::method,注意,这个方法没有定义入参:
    cars.forEach( Car::repair );
  4. 实例对象的成员方法的引用
    语法是instance::method。注意:这个方法接受一个Car类型的参数:
    final Car police = Car.create( Car::new );
    cars.forEach( police::follow );
@FunctionalInterface
public interface Supplier<T> {
    T get();
}

class Car {
    //Supplier是jdk1.8的接口,这里和lamda一起使用了
    public static Car create(final Supplier<Car> supplier) {
        return supplier.get();
    }

    public static void collide(final Car car) {
        System.out.println("Collided " + car.toString());
    }

    public void follow(final Car another) {
        System.out.println("Following the " + another.toString());
    }

    public void repair() {
        System.out.println("Repaired " + this.toString());
    }
}

四. Lambdas更多

只有一个方法的接口,不算默认方法
@FunctionalInterface标注下

lambdas实例化函数式接口方式,代替接口实现

//1. 左边指定类型,右边return代码块
(int x, int y) -> { return x + y; }
//2. 左边推导类型,右边返回值
(x, y) -> x + y
//3. 左边单一参数,右边返回值	
x -> x * x
//4. 左边没有输入,右边返回值
() -> x
//5. 左边推导类型,右边没有返回值
x -> { System.out.println(x); }

方法引用

//1. 静态方法引用
String::valueOf
//2. 非静态方法引用
Object::toString
//3. 继承的函数引用
x::toString
//4. 构造函数引用
ArrayList::new

函数引用是labbda的简写

String::valueOf		x -> String.valueOf(x)
Object::toString	x -> x.toString()
x::toString			() -> x.toString()
ArrayList::new		() -> new ArrayList<>()
posted @ 2016-08-09 12:59  zhangshihai1232  阅读(238)  评论(0)    收藏  举报