Java Lambda详解
Lambda表达式是JDK 8开始后的一种新语法形式。
作用:简化匿名内部类的代码写法
简化格式
(匿名内部类被重写方法的形参列表) -> {
	重写方法
}
Lambda表达式只能简化函数式接口的匿名内部类的写法形式
什么是函数式接口?
- 首先必须是接口、其次接口中有且仅有一个抽象方法的形式
 - 通常会在接口上加上一个@FunctionalInterface注解,标记该接口必须是满足函数式接口
 
如何使用Lambda?
我们将根据下面三个问题来帮助大家理解和使用Lambda
背景:我们自定义了一个man的类,创建了一个man的List。
class man {
    public int age;
    public char sex;
    public double socre;
    public man(int age, char sex, double score) {
        this.age = age;
        this.sex = sex;
        this.score = score;
    }
}
问题一
现需要对这个list根据人的年龄进行排序
要实现排序的功能,可以直接调用List对象自带的sort方法完成,但是需要man先实现Comparator的接口并重写compare方法,编译器才能比较两个不同man的大小。但是要更改原始类的代码,会比较麻烦,如果以后要对人的分数进行排序,那就又要更改的类的源码,这样操作很不方便。
sort(Comparator<? super E> c)方法可以直接传入一个Comparator对象,我们可以直接改写compare方法就可以实现比较。
第一种写法
public class lambdaTry {
    public static void main(String[] args) {
        List<man> humans = new ArrayList<>();
        humans.add(new man(19, 'g', 98.0));
        humans.add(new man(18, 'b', 95.0));
        humans.add(new man(20, 'b', 96.0));
        humans.add(new man(17, 'g', 97.0));
        humans.sort(new Comparator<man>() {
            @Override
            public int compare(man o1, man o2) {
                return o1.age - o2.age;
            }
        });
    }
}
第二种写法
Lambda
我们知道Lambda是用来简化函数式接口的匿名内部类,且Comparator满足函数式接口的两个条件:
- 首先必须是接口、其次接口中有且仅有一个抽象方法的形式
 - @FunctionalInterface注解
 
@FunctionalInterface
public interface Comparator<T> {
	int compare(T o1, T o2);
    ...
}
因此我们可以对上述的源码进行改写成Lambda格式
public class lambdaTry {
    public static void main(String[] args) {
        List<man> humans = new ArrayList<>();
        humans.add(new man(19, 'g', 98.0));
        humans.add(new man(18, 'b', 95.0));
        humans.add(new man(20, 'b', 96.0));
        humans.add(new man(17, 'g', 97.0));
        humans.sort((man o1, man o2) -> {
                return o1.age - o2.age;
        });
    }
}
改写过后代码简洁了很多。但是还可以继续简写。
Lambda表达式的省略写法
- 参数类型可以不写
 - 如果只有一个参数,参数类型可以省略,同时()也可以省略
 - 如果Lambda表达式的方法块中代码只有一行,可以省略大括号,同时省略分号。
 - 在条件三的基础上,如果这行代码是return语句,必须省略return。
 
第三种写法
Lambda简写
可以看到,此表达式满足省略写法的条件,可以继续简写成如下格式。只需要一行语句就能完成
public class lambdaTry {
    public static void main(String[] args) {
        List<man> humans = new ArrayList<>();
        humans.add(new man(19, 'g', 98.0));
        humans.add(new man(18, 'b', 95.0));
        humans.add(new man(20, 'b', 96.0));
        humans.add(new man(17, 'g', 97.0));
        humans.sort((o1, o2) -> o1.age - o2.age);
    }
}
问题二
将List转换为数组
我们知道List接口有一个方法toArray方法可以实现将其转换为数组。
JDK11之后,提供了这样的一个方法,提供了一个函数式接口来让我们转换
default <T> T[] toArray(IntFunction<T[]> generator) {
    return toArray(generator.apply(0));
}
IntFunction函数式接口是从JDK8之后实现的,内部只有一个apply抽象方法,是一个标准的函数式接口
@FunctionalInterface
public interface IntFunction<R> {
    R apply(int value);
}
我们可以直接用lambda,完成数组的转换
public class lambdaTry {
    public static void main(String[] args) {
        List<man> humans = new ArrayList<>();
        humans.add(new man(19, 'g', 98.0));
        humans.add(new man(18, 'b', 95.0));
        humans.add(new man(20, 'b', 96.0));
        humans.add(new man(17, 'g', 97.0));
		// 原本写法
        // man[] mans = humans.toArray(new IntFunction<man[]>() {
        //     @Override
        //     public man[] apply(int value) {
        //         return new man[value];
        //     }
        // });
        // lambda写法
        man[] mans = humans.toArray(value -> new man[value]);
        // 实际上用不上这样的写法,只是为了举例说明
        // man[] mans = humans.toArray(new man[0]);
        // man[] mans = humans.toArray(man[]::new);
        // 上面两种写法都可以,传值进去的size为0不影响实际的转换,具体可以看ArrayList的toArray重写方法
    }
}
问题三
输出年龄大于18的男同学的成绩
可以用forEach方法快捷实现,forEach方法来自于Iterable接口
default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}
再看Consumer接口,也是一个函数式接口
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
    ...
}
具体实现
public class lambdaTry {
    public static void main(String[] args) {
        List<man> humans = new ArrayList<>();
        humans.add(new man(19, 'g', 98.0));
        humans.add(new man(18, 'b', 95.0));
        humans.add(new man(20, 'b', 96.0));
        humans.add(new man(17, 'g', 97.0));
        // humans.forEach(new Consumer<>() {
        //     @Override
        //     public void accept(man man) {
        //         if (man.age >= 18 && man.sex == 'g') {
        //             System.out.println(man.score);
        //         }
        //     }
        // });
        humans.forEach(man -> {
            if (man.age >= 18 && man.sex == 'g') {
                System.out.println(man.score);
            }
        });
    }
}
有时Lambda还可以继续简写成方法引用(method reference)
方法引用
方法引用通过方法的名字来指向一个方法。
方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
方法引用使用一对冒号 ::
主要分为四种:
构造器引用
Class::newman[] mans = humans.toArray(man[]::new);
静态方法引用
Class::static_method打印每个man(需要在man内重写toString)
humans.forEach(System.out::println)
特定类的任意对象的方法引用
Class::method特定对象的方法引用
instance::method
Java Lambda详解的更多相关文章
- Java集合详解3:一文读懂Iterator,fail-fast机制与比较器
		
<Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...
 - Java 集合详解 | 一篇文章解决Java 三大集合
		
更好阅读体验:Java 集合详解 | 一篇文章搞定Java 三大集合 好看的皮囊像是一个个容器,有趣的灵魂像是容器里的数据.接下来讲解Java集合数据容器. 文章篇幅有点长,还请耐心阅读.如只是为了解 ...
 - Java内部类详解
		
Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...
 - 黑马----JAVA迭代器详解
		
JAVA迭代器详解 1.Interable.Iterator和ListIterator 1)迭代器生成接口Interable,用于生成一个具体迭代器 public interface Iterable ...
 - C++调用JAVA方法详解
		
C++调用JAVA方法详解 博客分类: 本文主要参考http://tech.ccidnet.com/art/1081/20050413/237901_1.html 上的文章. C++ ...
 - Java虚拟机详解----JVM常见问题总结
		
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
 - [转] Java内部类详解
		
作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...
 - Java面向对象详解
		
Java面向对象详解 前言:接触项目开发也有很长一段时间了,最近开始萌发出想回过头来写写以前学 过的基础知识的想法.一是原来刚开始学习接触编程,一个人跌跌撞撞摸索着往前走,初学的时候很多东西理解的也懵 ...
 - java 乱码详解_jsp中pageEncoding、charset=UTF -8"、request.setCharacterEncoding("UTF-8")
		
http://blog.csdn.net/qinysong/article/details/1179480 java 乱码详解__jsp中pageEncoding.charset=UTF -8&quo ...
 
随机推荐
- Invoke and BeginInvoke
			
原博客地址:http://www.cnblogs.com/worldreason/archive/2008/06/09/1216127.html 写的真的很好! 在Invoke或者BeginInvok ...
 - 结合AngularJS实现拖拽
			
最近项目中要实现,左侧树向右侧树中元素的拖拽功能,开始在网上看了好多ng-drag等等操作,都没有实现预想的效果,偶然发现一篇博客,然后根据博客改编,实现了自己想要的效果.下面简单的分析一下实现过程. ...
 - ArcMap进行天空开阔度(SVF)分析
			
这里的SVF并不是生物学或医学的(Stromal Vascular Fraction),而是指GIS中的(Sky View Factor,SVF),即为(城市)天空开阔度. 城市天空开阔度(Sky V ...
 - 机器学习之BP神经网络
			
import random import math #神经元的定义 class Neuron: def __init__(self,bias): self.bias = bias self.weigh ...
 - Java 反射的用法 有关Class类的解释
			
package com.imooc.test;public class ClassDemo1 { public static void main(String[] args) { Foo fool = ...
 - Three.js 火焰效果实现艾尔登法环动态logo 🔥
			
声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 <艾尔登法环>是最近比较火的一款游戏,观察可以发现它的 Log ...
 - mybatis——逆向工程中  where (条件1)and (条件2 or 条件3 or 条件4)
			
where (条件1)and (条件2 or 条件3 or 条件4) = where (条件1 and 条件2)or (条件1 and 条件3) or (条件1 and 条件4) 结果 是这样的 WH ...
 - Objective-C 基础教程第七章,深入理解Xcode
			
目录 Object-C 基础教程第七章,深入理解Xcode 0x00 前言 0x01 创建工程界面 0x02 主程序界面 ①顶部 Top Test(测试) Profile(动态分析) Analyze( ...
 - 采用二进制文件方式安装loki和promtail
			
1. 下载二进制文件 官方下载地址:https://github.com/grafana/loki/releases 下载如图所示的这俩文件,Grafana采用yum方式安装 cd /usr/loca ...
 - JSON.parse()和JSON.stringfy()区别
			
JSON.parse() 用于从一个json格式字符串解析出json类型的数据,如: 注意事项:json格式字符串必须是写在一排的,且括号外面用单引号,里面的每一个字符串用双引号 JSON.strin ...