java8——lambda expression

来源:互联网 发布:网络招生技巧 编辑:程序博客网 时间:2024/06/08 18:02

几点总结:

  1. 一个lambda表达式是一个带有参数的代码块
  2. 当你想要代码块在以后某个时间点执行时,可以使用lambda表达式
  3. lambda表达式可以被转换为函数式接口
  4. lambda表达式可以在闭包作用域中有效地访问final变量
  5. 方法和构造器引用可以引用方法或构造器,但无需调用他们(?)
    ===

1.1 为什么要使用lambda

先来看看类似的用法:

class Worker implements Runnable{    @Override    public void run() {        for (int i = 0; i < 5; i++) {            doWork();    }}Worker w = new Worker();new Thread(w).start;

上述这段代码的关键在于,run方法中包括了你希望在另一线程中执行的代码。

class LengthComparator implements Comparator<String>{  public int compare(String first, String second){    return Integer.compare(first.length(). second.length());  }}Arrays.sort(strings, new LengthComparator());

你给sort方法传递了一段需要比较元素的代码,并不需要关心其如何在被整合的代码中实现。

tip:上面的比较,并没有简单地使用x-y这种比较式,防止当x与y符号相反时,极端情况下的溢出

Thread thread1 = new Thread(new Runnable() { // 匿名实现类,会得到提示可以转换成lambda表达式            @Override            public void run() {            ......            }        },"thread1");

总结:使用lambda是为了更好地实现向其他代码传递一段代码,以及简化编写。

1.2 lambda表达式的语法

(String first, String second) -> Integer.compare(first.length(), second.length())

参数,箭头,以及一个表达式(或代码块,如下)
指定了必须传给代码的所有变量

(String first, String second) -> {            if (first.length() < second.length()) return -1;            else if (first.length() > second.length()) return 1;            else return 0;        }
  1. 没有参数,括号中可以为空
  2. 一个参数,可以省略括号
  3. 可以省略参数类型,如果可以从上下文中推倒
  4. 不需要为lambda表达式写返回类型

1.3函数式接口
对于只包含一个抽象方法的接口,可以通过lambda表达式来创建该接口的对象。

Arrays.sort(strings, (a, b) -> Integer.compare(a.length(), b.length()));

接口Comparator中,除了compare方法,还有一个equals方法也没有方法体,但它不是抽象方法,默认实现是Object类中的equals。同时,java8中,接口可以声明非抽象的方法(default关键字)

@FunctionalInterface,包含此注解的接口,都是函数式接口。当我们编写函数式接口时,也可加上此注解,编译器会检查是否符合要求。

最后,应注意检查lambda表达式中的方法是否会抛出异常。

1.4方法引用
调用已存在的方法
几种格式:
对象::实例方法
类::静态方法
类::实例方法
super::实例方法(引用父类)

//使用lambda表达式和类的静态方法Arrays.sort(persons, (o1, o2) -> Person.compareByAge(o1,o2));//使用方法引用//引用的是类的静态方法Arrays.sort(persons, Person::compareByAge);
//使用lambda表达式//对象的实例方法Arrays.sort(persons,(a,b)->provider.compareByAge(a,b));//使用方法引用//引用的是对象的实例方法Arrays.sort(persons, provider::compareByAge);
//使用lambda表达式和类型对象的实例方法Arrays.sort(stringsArray,(s1,s2)->s1.compareToIgnoreCase(s2));//使用方法引用//引用的是类型对象的实例方法Arrays.sort(stringsArray, String::compareToIgnoreCase);

1.5构造器引用

方法名是new,对象::new
对于拥有多个构造器的类,选用哪个构造器取决于上下文。
1.6 变量作用域

public static void repeat(String text){        Runnable r = () -> {            System.out.print(text);            text = "aaa" // error!        };        new Thread(r).start();    }

lambda表达式可以捕获闭合作用域中的变量值。但不能改变已捕获变量(传入变量)的值。非lambda表达式同样不可以。所以,获取的变量必须是final或者表现为final(即不能修改)。
注:不可变约束只作用于局部变量上,如果是一个实例变量或者内部类的静态变量,如在Runnable中定义的变量,即可被改变。

1.8中,内部类可以捕获闭合作用域的值,操作要求同上。

1.7默认方法
即之前提到过的接口中加了default关键字的方法。
实现了该接口的类可以选择保留原实现或者重写。

Q: 当一个接口定义了一个默认方法,而另一个接口或父类又定义了同名的方法,jdk会怎么处理?

1.如果是父类中发生重复,则选择父类中的方法。
2.如果是两个接口中发生冲突,则必须在实现中覆盖该方法来解决冲突。

1.8接口中的静态方法
在java8中,可以为接口添加静态方法。

===

练习部分:

原创粉丝点击