java8-lambda表达式

为什么要使用java8:

Java 几个重大版本 :
Java 从 1995 年发布到现在,也走过 18 年了,个人认为,其中几个 java 版本都肩负着重大使命,影响甚远;
jdk1.0 1995 年 5 月 23 日诞生,Oak 语言改名为 Java,并提出“Write Once ,Run anywhere”;
jdk1.2 1999 年 6 月发布,将 java 划分为 J2SE,J2ME,J2EE 三大平台;
Jdk1.4 主要是性能提升,在 2000 年时候 JAVA 成为世界上最流行的电脑语言,跟这个版本离不开关系,估计国内还有大量 的 java 应用是运行在此版本上;
Jdk5 诞生于 2004 年,他的使命就是易用,加入 1. 泛型 2 自动装箱/拆箱 3 for-each 4 static import 5 变长参数等,
为了表示该版本的重要性,J2SE1.5 更名为 Java SE 5.0;
Jdk8 将在 2014 年 3 月份发布,迄今为止,可能是最大更新的 java 版本,也是令人期待的一个版本,在 Java 中引入闭包概念 对 Java 程序开发方法的影响甚至会大于 Java5 中引入的泛型特征对编程方式带来的影响。

可以看出,jdk 8 跟 jdk 5 之间,整整相差 10 年,这 10 年期间,相继发布 jdk 6、7 都是改动不大,这也说明,java 发展确 实有点缓慢了,以致曾经的跟随者.net 在某方面超越了 java,还有基于 jvm 上的动态语言崛起,比如 Groovy、Scala 等 。java8是迄今为止java历史上最大的改变。
java语言有个最大的问题:语言本身的语法像旧社会妇女的裹脚布又臭又长。java8(主要是 lambda 表达式)很好的解决了这个问题

lambda表达式

示例

示例1:比较我们想选出绿苹果的列表,或选出重量大于150克的苹果:
java7:

public class Apple {
    private Integer weight = 0;
    private String color = "";
}
List inventory = new ArrayList<>();
inventory.addAll(Arrays.asList(new Apple(80,"green"), new Apple(155, "green"), new Apple(120, "red")));


public static List filterGreenApples(List inventory){
    List result = new ArrayList<>();
    for (Apple apple: inventory){
        if ("green".equals(apple.getColor())) {
            result.add(apple);
        }
    }
    return result;
}

public static List filterHeavyApples(List inventory){
    List result = new ArrayList<>();
    for (Apple apple: inventory){
        if (apple.getWeight() > 150) {
            result.add(apple);
        }
    }
    return result;
}

java8:

public static List filterApples(List inventory, Predicate p){
    List result = new ArrayList<>();
    for(Apple apple : inventory){
        if(p.test(apple)){
            result.add(apple);
        }
    }
    return result;
}       
List greenApples2 = filterApples(inventory, (Apple a) -> "green".equals(a.getColor()));
List heavyApples2 = filterApples(inventory, (Apple a) -> a.getWeight() > 150);

如果把判断语句抽成公共方法,如下:

public static boolean isGreenApple(Apple apple) {
    return "green".equals(apple.getColor()); 
}

public static boolean isHeavyApple(Apple apple) {
    return apple.getWeight() > 150;
}
List greenApples = filterApples(inventory, FilteringApples::isGreenApple);
List heavyApples = filterApples(inventory, FilteringApples::isHeavyApple);

示例2:按重量从小到大排序:

java7:

实现一:
static class AppleComparator implements Comparator {
    public int compare(Apple a1, Apple a2){
        return a1.getWeight().compareTo(a2.getWeight());
    }
}
inventory.sort(new AppleComparator());
实现二:匿名类实现
inventory.sort(new Comparator() {
    public int compare(Apple a1, Apple a2){
        return a1.getWeight().compareTo(a2.getWeight()); 
}});

inventory.sort(new Comparator() {
    public int compare(Apple a1, Apple a2){
        return a1.getWeight().compareTo(a2.getWeight()); 
}});

java8:

inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));
inventory.sort(Comparator.comparing(Apple::getWeight));
多条件排序:
inventory.sort((a1, a2) -> {
    if (a1.getWeight().equals(a2.getWeight())) {
        return a1.getColor().compareTo(a2.getColor());
    } else {
        return a1.getWeight().compareTo(a2.getWeight());
    }
});
inventory.sort(Comparator.comparing(Apple::getWeight).thenComparing(Apple::getColor));

JAVA8-用lamda表达式和增强版Comparator进行排序 - CSDN博客

Lambda表达式格式

可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。这个定义够大的,让我们慢慢道来。
匿名——我们说匿名,是因为它不像普通的方法那样有一个明确的名称:写得少而想得多!
函数——我们说它是函数,是因为Lambda函数不像方法那样属于某个特定的类。但和方法一样,Lambda有参数列表、函数主体、返回类型,还可能有可以抛出的异常列表。
传递——Lambda表达式可以作为参数传递给方法或存储在变量中。
简洁——无需像匿名类那样写很多模板代码。

java8-lambda表达式_第1张图片
Lambda表达式构成.png

Lambda表达式:包括参数列表、箭头、Lambda的主体,其中Lambda主体可以包括多行,这个时候必须用大括号把它括起来。

实现基础
默认方法
类型推断

函数式接口:

函数式接口定义且只定义了一个抽象方法。
函数式接口很有用,因为抽象方法的签名可以描述Lambda表达式的签名。函数式接口的抽象方法的签名称为函数描述符。所以为了应用不同的Lambda表达式,你需要一套能够描述常见函数描述符的函数式接口。JavaAPI中已经有了几个函数式接口:Comparable、Runnable和Callable。

Runnable r1 = () -> System.out.println(" Hello World 1"); // 使 用 Lambda
Runnable r2 = new Runnable() { // 使 用 匿 名 类
    public void run() {
        System.out.println(" Hello World 2");
    }
};

java8在java.util.function包中引入了新的函数式接口:
Java 8 中 的 常 用 函 数 式 接 口

java8-lambda表达式_第2张图片
Java 8 中 的 常 用 函 数 式 接 口.png

Lambdas 及 函 数 式 接 口 的 例 子

java8-lambda表达式_第3张图片
Lambdas 及 函 数 式 接 口 的 例 子.png

原始类型特化:是为了避免原始类型和引用类型之间的装箱拆箱

使用示例:

java.util.function.Function接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象。如果你需要定义一个Lambda,将输入对象的信息映射到输出,就可以使用这个接口(比如提取苹果的重量,或把字符串映射为它的长度)。在下面的代码中,我们向你展示如何利用它来创建一个map方法,以将一个String列表映射到包含每个String长度的Integer列表。

@FunctionalInterface
public interface Function {
    R apply(T t);
}
public static  List map(List list, Function f) {
    List result = new ArrayList<>();
    for (T s : list) {
        result.add(f.apply(s));
    }
    return result;
}
// [7, 2, 6]
List l = map(Arrays.asList(" lambdas", " in", " action"), (String s) -> s.length());
// Lambda 是 Function 接 口 的 apply 方 法 的 实 现

方法引用

Lambda的一种快捷写法,针对单一方法的Lambda的语法糖,可读性更好

java8-lambda表达式_第4张图片
方法引用.png

主要分三类:
1、静态方法的方法引用:Integer::parseInt
2、实例方法的引用:String::length
3、外部对象的引用:service::getByName

第2、3的区别是,第2类是lambda参数的类是操作的类,第三种是lambda操作的类是外部已存在的类,参数只操作类的参数。


java8-lambda表达式_第5张图片
方法引用示例.png

lambda实现原理

lambda表达式里面,会把lambda表达式在本类中生成一个以lambda$+数字的方法。关键点:该方法不一定是static的方法,是static还是非static,取决于lambda表达式里面是否引用了this。这就是为什么lambda表达式里面的this指向的是本地,因为他在本类里面创建了一个方法,然后把lambda表达式里面的代码放进去。

package jdk8.lambda;
/***
 * lambda表达式的this
/*
public class LambdaDemo {
    private String name = "Demo";
    public void test() {
        // lambda实现
        new Thread(() -> {
            System.out.println("这里的this指向当前的ThisDemo类:" + this.name);
        }).start();
    }
}

javap -s -v LambdaDemo.class

java8-lambda表达式_第6张图片
javap 执行结果.jpg

说说javap命令 - 每天一点 - 博客园
java8 lambda表达式原理 - CSDN博客
Java8学习笔记(4) — Lambda表达式实现方式 - CSDN博客

你可能感兴趣的:(java8-lambda表达式)