Lambda


一、概述

 

1、什么是Lambda表达式

//1.不需要参数,返回值为5
() -> 5 //2.接收一个参数(数字类型),返回其2倍的值
x -> 2 * x //3.接收2个参数(数字),并返回他们的差值
(x,y)-> x-y //4.接收2个int类型整数,返回他们的和
(int x, int y) -> x+y //5.接受一个String对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) ->System.out.print(s)

  

3.什么是函数式接口

  在对上面进行举例说明之前,必须先来理解一下函数式接口,因为Lambda是建立在函数式接口的基础上的

  记住!

  (1)只包含一个抽象方法的接口,称为函数式接口

public class Lambda01 {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程1开启"+":"+Thread.currentThread().getName());
}
}).start(); new Thread(() -> System.out.println("线程2开启"+":"+Thread.currentThread().getName())).start();
Runnable runnable1= new Runnable(){
@Override
public void run() {
System.out.println("线程3开启"+":"+Thread.currentThread().getName());
}
};
Runnable runnable2=()-> System.out.println("线程4开启"+":"+Thread.currentThread().getName());
runnable1.run();
runnable2.run(); }
}
/*输出结果
* Hello world !
* Hello world !
* Hello world !
* Hello world !
*/

通过上面案例可以看出:通过Lambda表达式看去舒服清爽多了,2而通过匿名内部类代码总是不够整洁。

public class TestArray {

    public static void main(String[] args) {
String[] players = {"zhansgan", "lisi", "wangwu", "zhaoliu", "wangmazi"}; // 1.1 使用匿名内部类根据 surname 排序 players
Arrays.sort(players, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return (s1.compareTo(s2));
}
}); // 1.2 使用 lambda 排序,根据 surname
Arrays.sort(players, (String s1, String s2) -> s1.compareTo(s2)); //================================================================================================ // 2.1 使用匿名内部类根据 name lenght 排序 players
Arrays.sort(players, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return (s1.length() - s2.length());
}
}); // 2.2使用Lambda,根据name length
Arrays.sort(players, (String s1, String s2) -> (s1.length() - s2.length())); //================================================================================================== // 3.1 使用匿名内部类排序 players, 根据最后一个字母
Arrays.sort(players, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
return (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1));
}
}); // 3.2 使用Lambda,根据最后一个字母
Arrays.sort(players, (String s1, String s2) -> (s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1)));
}
}

通过上面例子我们再来思考为什么Lambda表达式需要函数式接口?其实很简单目的就是为来保证唯一。

你的Runnable接口只要一个抽象方法,那么我用() -> System.out.println("Hello world !"),就只能代表run方法,如果你下面还有一个抽象方法,那我使用Lambda表达式,

那鬼才知道要调用哪个抽象方法呢。

二、方法引用

  首先注意:方法引用,不是方法调用!方法引用,不是方法调用!方法引用,不是方法调用!

  函数式接口的实例可以通过lambda表达式、方法引用、构造方法引用来创建,方法引用是lambda表达式的语法糖,任何用方法引用的地方都可由lambda表达式来替换,

  但是并不是所有的lambda表达式都可以用方法引用来替换

  举例

  这就是一个打印集合所有元素的例子,value ->System.out.println(value)是一个Consumer函数式接口,这个函数式接口可以通过方法引用来替换

public class TestArray {

    public static void main(String[] args) {
List<String> list = Arrays.asList("xuxiaoxiao", "xudada", "xuzhongzhong");
list.forEach(value -> System.out.println(value));
}
/* 输出:
* xuxiaoxiao
* xudada
* xuzhongzhong
*/
}

2、分类

类别 使用形式
静态方法引用 类名 :: 静态方法名
实例方法引用 对象名(引用名) :: 实例方法名
类方法引用 类名 :: 实例方法名
构造方法引用 类名 :: new

(1)静态方法引用

public class Apple {

    private String name;
private String color;
private double weight; public Apple(String name, String color, double weight) {
this.name = name;
this.color = color;
this.weight = weight;
} public static int compareByWeight(Apple a1, Apple a2) {
double diff = a1.getWeight() - a2.getWeight();
return new Double(diff).intValue();
} //还有getter setter toString
}

有一个苹果的List,现在需要根据苹果的重量进行排序。List 的 sort 函数接收一个 Comparator 类型的参数,Comparator 是一个函数式接口,接收两个参数,

返回一个int值。Apple的静态方法compareByWeight正好符合Comparator函数式接口,所以可以使用:

Apple::compareByWeight 静态方法引用来替代lambda表达式

public class LambdaTest {

    public static void main(String[] args) {

        Apple apple1 = new Apple("红富士", "Red", 280);
Apple apple2 = new Apple("冯心", "Yello", 470);
Apple apple3 = new Apple("大牛", "Red", 320);
Apple apple4 = new Apple("小小", "Green", 300); List<Apple> appleList = Arrays.asList(apple1, apple2, apple3, apple4); //lambda 表达式形式
//appleList.sort((Apple a1, Apple a2) -> {
// return new Double(a1.getWeight() - a2.getWeight()).intValue();
//}); //静态方法引用形式(可以看出引用方法比上面的更加简单
appleList.sort(Apple::compareByWeight); appleList.forEach(apple -> System.out.println(apple)); }
}
输出:
Apple{category='红富士', color='Red', weight=280.0}
Apple{category='小小', color='Green', weight=300.0}
Apple{category='大牛', color='Red', weight=320.0}
Apple{category='冯心', color='Yello', weight=470.0}

注意:Apple.compareByWeight是方法的调用,而Apple::compareByWeight方法引用,这两者完全不是一回事。

(2)实例方法引用

这个compareByWeight是一个实例方法

public class AppleComparator {

    public int compareByWeight(Apple a1, Apple a2) {
double diff = a1.getWeight() - a2.getWeight();
return new Double(diff).intValue();
}
}

下面的例子通过实例对象的方法引用 comparator::compareByWeight 来代替lambda表达式

public class LambdaTest {

    public static void main(String[] args) {

        Apple apple1 = new Apple("红富士", "Red", 280);
Apple apple2 = new Apple("冯心", "Yello", 470);
Apple apple3 = new Apple("哈哈", "Red", 320);
Apple apple4 = new Apple("小小", "Green", 300); List<Apple> appleList = Arrays.asList(apple1, apple2, apple3, apple4); //lambda 表达式形式
//appleList.sort((Apple a1, Apple a2) -> {
// return new Double(a1.getWeight() - a2.getWeight()).intValue();
//}); //实例方法引用
AppleComparator comparator = new AppleComparator();
appleList.sort(comparator::compareByWeight); appleList.forEach(apple -> System.out.println(apple)); }
}
输出:
Apple{category='红富士', color='Red', weight=280.0}
Apple{category='小小', color='Green', weight=300.0}
Apple{category='哈哈', color='Red', weight=320.0}
Apple{category='冯心', color='Yello', weight=470.0}

通过上面两个例子可以看到,静态方法引用和实例方法引用都是比较好理解的。

(3)类方法引用

一般来说,同类型对象的比较,应该当前调用方法的对象与另外一个对象进行比较,好的设计应该像下面:

public class Apple {

    private String category;
private String color;
private double weight; public Apple(String category, String color, double weight) {
this.category = category;
this.color = color;
this.weight = weight;
}
//这里和上面静态方式唯一区别就是这个参数就一个,需要实例对象调这个方法
public int compareByWeight(Apple other) {
double diff = this.getWeight() - other.getWeight();
return new Double(diff).intValue();
} //getter setter toString
}

还是之前List排序的例子,看看使用类方法引用如何写:

public class LambdaTest {

    public static void main(String[] args) {

        Apple apple1 = new Apple("红富士", "Red", 280);
Apple apple2 = new Apple("黄元帅", "Yello", 470);
Apple apple3 = new Apple("红将军", "Red", 320);
Apple apple4 = new Apple("国光", "Green", 300); List<Apple> appleList = Arrays.asList(apple1, apple2, apple3, apple4); //lambda 表达式形式
//appleList.sort((Apple a1, Apple a2) -> {
// return new Double(a1.getWeight() - a2.getWeight()).intValue();
//}); //这里是类方法引用
appleList.sort(Apple::compareByWeight); appleList.forEach(apple -> System.out.println(apple)); }
}
输出:
Apple{category='红富士', color='Red', weight=280.0}
Apple{category='国光', color='Green', weight=300.0}
Apple{category='红将军', color='Red', weight=320.0}
Apple{category='黄元帅', color='Yello', weight=470.0}

这里使用的是:类名::实例方法名。首先要说明的是,方法引用不是方法调用。compareByWeight一定是某个实例调用的,就是lambda表达式的第一个参数,然后lambda

表达式剩下的参数作为 compareByWeight的参数,这样compareByWeight正好符合lambda表达式的定义。

或者也可以这样理解:

(Apple a1, Apple a2) -> { return new Double(a1.getWeight() - a2.getWeight()).intValue(); }

int compareByWeight(Apple other) 需要当前对象调用,然后与另外一个对象比较,并且返回一个int值。可以理解为lambda表达式的第一个参数 a1 赋值给当前对象, 然后 a2

赋值给 other对象,然后返回int值。

(4)构造方法引用

public class ConstructionMethodTest {

    public String getString(Supplier<String> supplier) {
return supplier.get();
} public static void main(String[] args) { ConstructionMethodTest test = new ConstructionMethodTest(); //lambda表达式形式
System.out.println(test.getString(() -> { return new String();})); //构造方法引用形式
System.out.println(test.getString(String::new)); }
}

getString 方法接收一个Supplier类型的参数,Supplier 不接收参数,返回一个String。lambda表达式应该这样写:

() -> { return new String();}
替换成方法引用的形式如下: 实际上调用的是String 无参构造方法
String::new

java代码(1)---Java8 Lambda的更多相关文章

  1. Java学习笔记--Java8 Lambda表达式

    Java Lambda表达式入门:http://blog.csdn.net/renfufei/article/details/24600507 lambda内容的介绍:http://swiftlet. ...

  2. JAVA8 Lambda初体验

    import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.u ...

  3. 【Java学习笔记之三十一】详解Java8 lambda表达式

    Java 8 发布日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表达式,它将允许我们将行为传到函数里.在Java 8之前 ...

  4. java代码之美(10)---Java8 Map中的computeIfAbsent方法

    Map中的computeIfAbsent方法 Map接口的实现类如HashMap,ConcurrentHashMap,HashTable等继承了此方法,通过此方法可以在特定需求下,让你的代码更加简洁. ...

  5. java代码之美(14)---Java8 函数式接口

    Java8 函数式接口 之前写了有关JDK8的Lambda表达式:java代码之美(1)---Java8 Lambda 函数式接口可以理解就是为Lambda服务的,它们组合在一起可以让你的代码看去更加 ...

  6. java代码之美(15)---Java8 Function、Consumer、Supplier

    Java8 Function.Consumer.Supplier 有关JDK8新特性之前写了三篇博客: 1.java代码之美(1)---Java8 Lambda 2.java代码之美(2)---Jav ...

  7. java代码(15) ---java8 Function 、Consumer 、Supplier

    Java8 Function.Consumer.Supplier 有关JDK8新特性之前还有三篇博客: 1,java代码(1)---Java8 Lambda 2,java代码(2)---Java8 S ...

  8. java代码(14) --Java8函数式接口

    Java8函数式接口 之前有关JDK8的Lambda表达式 Java代码(1)--Java8 Lambda 函数式接口可以理解就是为Lambda服务的,它们组合在一起可以让你的代码看去更加简洁 一.概 ...

  9. java代码(10) ---Java8 Map中的computeIfAbsent方法

    Map中的computeIfAbsent方法 一.案例说明 1.概述 在JAVA8的Map接口中,增加了一个computeIfAbsent,此方法签名如下: public V computeIfAbs ...

  10. Java8 Lambda表达式和流操作如何让你的代码变慢5倍

    原文出处:ImportNew 有许许多多关于 Java 8 中流效率的讨论,但根据 Alex Zhitnitsky 的测试结果显示:坚持使用传统的 Java 编程风格——iterator 和 for- ...

随机推荐

  1. C#实现局域网聊天 通讯 Socket TCP 多人

    程序分别为服务端与客户端,服务端创建套接字使用多线程侦听多客户端请求 代码需要引用System.Net:和System.Net.Socket:这两个类 分享源码demo:https://pan.bai ...

  2. 【SMB源码解析系列】——002.RESET中断

    跟随代码结尾处的中断向量,我们可以看到RESET中断所在地址为Start标签处. 这部分代码比较简单,从字面便可基本理解. 1.(682~683)状态寄存器设置,sei指令用于禁用IRQ中断,SMB中 ...

  3. VS2019 使用

    下载 官网下载:链接 安装 1.点击下载程序,会显示这个界面 2.点击“继续”,等待安装程序安装完成 4.安装程序下载安装验证完毕,将会提示进入这个界面 5.为了方便起见,这里仅展示安装C++功能,在 ...

  4. 【原创】Linux信号量机制分析

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  5. AIRAC

    AIRAC是国际上划定的,以28天为一个周期的航行资料定期生效制. 2020年比较特殊,共有14个周期,分别是: 2001 2020/01/02 2020/01/29 2002 2020/01/30 ...

  6. Nginx服务器的安装和卸载

    Nginx的安装 安装Nginx之前,需要先获取Nginx的安装文件.我们可以在http://nginx.org/en/download.html获取各个版本的Nginx安装文件.大家可以按照自己的需 ...

  7. 解惑求助-关于NetCore2.2中间件响应的问题

    背景介绍:基于netcore2.2开发api接口程序,自定义了一个异常捕获中间件,用于捕获未经处理的异常以及状态码404.500等访问(设计的出发点就是,出现了非200的响应,我这边全部会进行处理成2 ...

  8. Create First Application

    Node.js创建第一个应用 Node.js开发的目的就是为了用JavaScript编写Web服务器程序, 在使用Node.js时,不仅仅是在实现一个应用,同时还实现了整个HTTP服务器.在创建Nod ...

  9. (一) Vue在创建的时候 入口文件 及相关的路由配置(及子路由配置)

    1. 首先明确一点  在书写之前尽量保持相关的文件知道含义 比如 components 啥的 知道是要放什么东西 在这里介绍一下   由于 vue 不是系统学习 所以很多的创建方式可能不一样  就是有 ...

  10. Java 面向对象基础

    面向对象的基础 局部变量和成员变量区别: 1)定义的位置不同    成员变量直接定义在class中    局部变量在某个{}中或者再某个方法中 2)在内存中的位置不同    对象的成员变量会在内存中的 ...