美文网首页
Lambda原来还可以这么用

Lambda原来还可以这么用

作者: 程序员大大 | 来源:发表于2020-08-04 23:49 被阅读0次

    Java8新特征之Lambda

    image

    ![Java前景如何?成为一名月入过万的Java工程师有多难?

    Java 语言经历了20多年的发展,在C、C++语言占据大半江山的情况下横空出世,杀出了一条血路,面临PHP、Python、Ruby等动态语言也毫不显怯,至今仍是最受欢迎的编程语言,没有之一,可以说 Java 是面向对象语言的后起之秀和典范。

    image

    Java一直坚挺,高薪前景

    企业,特别是中大型企业对 Java 工程师的需求仿佛从来没有厌倦,大量的 Java 技术人才缺口也给了 IT 行业从业者一个很好的选项:目前来看,精进自己的 Java 技术,就不愁没有工作。

    为何多年来企业对 Java 工程师的需求就没有衰退过,一直这么坚挺呢?听小编道来。

    首先 Java 具有功能强大和简单易用两个突出的优点,还具有可移植性、跨平台性、稳定性、安全性、分布式、多线程、动态性等特质,以致没有 Java 不能做的软件。这样的特质也是其他语言所无法比拟的,目前没有什么语言可以毫不心虚地说一句自己可以取代 Java。

    另外,二十多年的发展让 Java 语言在广泛的范围均有应用,安卓移动端的出现更是让 Java 如虎添翼。最后还不得不说一句,Java 的发展势头尽管相较几年前略有颓势,仍然没有发展到瓶颈,还有很大的发展空间。

    74%的人认为不难

    有人曾经做过统计,询问500多已经参加工作的 Java 开发者,“学习 java 是否困难?”有74%的人认为不难,说难学的仅占26%,那么这74%全部都是聪明人,智商比普通人高吗?显然不是的。

    说到底 Java,它只是一种语言,仅此而已。跟我们平时学习母语,英语并无不同,只是他的适用对象是计算机,手机等非生物,但基本的控制结构什么的,所有的语言都差不多。

    Java高薪前途光明

    Java 是一种可以撰写跨平台应用程序的面向对象的程序设计语言。具有卓越的通用性、高效性、和安全性。广泛应用于PC,移动电话和互联网,拥有全球最大的开发者社群。在全球云计算和互联网的背景下,java 具备更显著的优势就业前景。

    广阔的市场,光明的前景总会让人向往,很多人立志要学习 java,从事开发,走上高端大气的 IT 道路。

    最新技术学习资料(_) → lezijie007(程序员暗号999)

    只有聪明人才能学吗?

    但是,在学习之前,看到各种代码如看天书,又总会听到很多外行人宣扬着 java 有多难,绝不是平庸者的选择。很多人就会因此打退堂鼓,认为自己不够聪明,肯定学不来。那么,java 编程真的是聪明人才能玩的游戏吗?

    要抓住Java的本质

    学习 java 只要你掌握了编程的本质和逻辑关系,那么编程语言,开发平台,编译工具都不是问题。真正评判你的专业水平的还是你的程序设计思想,语言的机制本身并不会给程序带来多大的影响。

    而且,每个人的难易标准并不相同,习惯说不的人,总会放大困难,给自己设置障碍。

    不要活在别人的标准里

    李嘉诚说:“当我骑自行车时,别人说路途太远,根本不可能达到目的地,我没理,半道上我换成小轿车;当我开小轿车时,别人说,不要再往前开,前面就是悬崖峭壁没路了,我没理,继续往前开,开到悬崖峭壁我换飞机了,结果我去到了任何我想去的地方“。

    说到底,修行还是要靠自己,难不难何必让别人给你设立标准?只要你想做,下一秒就能开始。不要让你的梦想毁在别人的嘴里,因为别人不会对你的梦想负责。

    Lambda表达式(也称为闭包),它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理。很多语言(Groovy、Scala等)从设计之初就支持Lambda表达式。但是java中使用的是匿名内部类代替。最后借助强大的社区力量,找了一个折中的Lambda实现方案,可以实现简洁而紧凑的语言结构。

    1、匿名内部类到Lambda的演化

    匿名内部类,即一个没有名字的,存在于一个类或方法内部的类。当我们需要用某个类且只需要用一次,创建和使用和二为一时,我们可以选择匿名内部类,省掉我们定义类的步骤。

    匿名内部类会隐士的继承一个类或实现一个接口,或者说匿名内部类是一个继承了该类或者实现了该接口的子类匿名对象。下面看一个匿名内部类的例子:

    测试类中调用方法

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n9" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">package com.lotbyte.main;
    /*
    定义和使用匿名内部类
    */
    public class NoNameClass {
    public static void main(String[] args) {

    Model m = new Model(){
    @Override
    public void func() {
    System.out.println("方法的实现");
    }
    };
    m.func();
    }
    }
    // 需要被实现的接口
    interface Model{
    void func();
    }</pre>

    2、Lambda快速使用

    从某种意义上来说,Lambda表达式可以看作是匿名内部类对象的简写形式。最简单的Lambda表达式可以由 用逗号分隔的参数列表->符号和语句块组成。

    注意:此时匿名内部类只能实现接口,不能是继承抽象类

    例如将上面的例子做一个简化,使用Lambda的形式如下:

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n14" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public class NonameClassForLambda {
    public static void main(String[] args) {
    // Lambda方式简写,方法实现可以很简单
    Model1 md = ()-> System.out.println("hello");
    md.func();

    // 也可以是比较复杂的操作
    md = () -> {
    for (int i = 1; i <=5; i++) {
    System.out.println(i);
    }
    };
    md.func();
    }
    }
    // 接口
    interface Model1{
    void func();
    }</pre>

    以上是一个简单的Lambda的书写形式,()中是形参列表,没有则为空括号, ->为语法格式,之后则为方法的实现(一条语句可以直接书写,当有多条语句时,需要使用{}进行包裹)。从这可以看出在接口中必须只能存在一个抽象方法。

    注意:Lambda中必须有个接口

    3、Lambda的形式

    使用Lambda时,实现方法可以有参数,也可以有返回值,如果没指定参数类型,则由编译器自行推断得出。

    3.1、 无参带返回值

    生成[1,10]之间的任意整数

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n21" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">interface Model2{
    int func();
    }
    Model2 md2 = () -> {return (int)(Math.random()*10+1)};</pre>

    说明:Lambda的改写需要有对应的抽象方法,当没有参数时需要使用()占位,当表达式只有一行代码时,可以省略return{}

    以上的Lambda等价于:

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n24" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Model2 md2 = () -> (int)(Math.random()*10+1);</pre>

    3.2 、带参带返回值

    返回一个对数字描述的字符串

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n27" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">interface Model3{
    String func(int a);
    }
    Model3 md3 = (int a) -> {
    return "This is a number " + a;
    };</pre>

    说明:形参写在()内即可,参数的类型可以省略,此时将由编译器自行推断得出,同时还可以省略()

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n29" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">md3 = a -> "This is a number " + a;</pre>

    省略了参数类型,小括号,同时连带实现体的括号和return都省了。

    3.3 、带多个参数

    根据输入的运算符计算两个数的运算,并返回结果

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n33" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">interface Model4{
    String func(int a, int b, String oper);
    }
    Model4 md4 = (a, b, s) -> {
    String res = "";
    if("+".equals(s)){
    res = ( a+b ) + "";
    }else if("-".equals(s)){
    res = ( a-b ) + "";
    }else if("".equals(s)){
    res = ( a
    b ) + "";
    }else if("/".equals(s)){
    res = ( a/b ) + ""; // 暂不考虑除0的情况
    }else{
    res = "操作有失误";
    }
    return res;
    };
    System.out.println(md4.func(1,1,"+"));</pre>

    以上例子为多个参数的Lambda表达式,其中省略掉了每一个参数的类型,编译器自动推断。多条语句时实现体的{}不能省。

    最新技术学习资料(_) → lezijie007(程序员暗号999)

    4、Lambda作为参数

    在jdk8之前,接口可以作为方法参数传入,执行时必须提供接口实现类的实例。从java8开始,Lambda可以作为接口方法实现,当作参数传入,无论从形式上还是实际上都省去了对象的创建。使代码更加的紧凑简单高效。

    使用Lambda表达式需要有以下几步:

    1、定义接口,抽象方法的模板;

    2、在某方法中需要接口作为参数;

    3、调用方法时需要将抽象方法实现(此时我们使用Lambda表达式)并传入即可。

    4.1、定义接口

    在接口中,必须有且仅有一个抽象方法,以确定Lambda模板

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n46" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">// 无参无返回值的方法
    interface LambdaInterface1{
    void printString();
    }
    // 带参无返回值的方法
    interface LambdaInterface2{
    void printString(String str);
    }</pre>

    4.2、定义方法接收参数

    在某方法中需要使用接口作为参数

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n49" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">// 无参
    public static void testLambda(LambdaInterface1 lam1){
    lam1.printString();
    }

    // 带参
    public static void testLambda2(String s,LambdaInterface2 lam2){
    lam2.printString(s);
    }</pre>

    4.3、Lambda实现

    使用方法时需要用Lambda将抽象方法实现

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n52" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">// 无参Lambda作为参数
    testLambda(()->{
    System.out.println("可以简单,可以复杂");
    });
    // 带参Lambda作为参数
    testLambdaParam("hello",(a)->{
    System.out.println(a);
    });</pre>

    通过以上三步,能够完整地展示Lambda从和演变而来。此后在使用时,jdk中已经提供很多场景了,即前两部已经完成,我们更多的是实现第三步即可。

    5、forEach展示Lambda

    例如以ArrayList的遍历为例子,分析Lambda的使用方式。

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n56" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public static void main(String[] args) {
    List<String> strs = new ArrayList<String>(){
    {
    add("aaa");
    add("bbb");
    add("ccc");
    }
    };
    strs.forEach((str)-> System.out.println(str));
    }</pre>

    下面看看forEach的源码,定义中使用了接口Consumer作为参数,并调用了其方法:

    img

    Consumer中的抽象方法只有accept一个:

    img

    通过在forEach方法中调用Consumer的accept方法,并将每一个元素作为参数传入,使得accept方法可以对每一个元素进行操作,当我们使用Lambda实现accept时就变成了我们自己对每一个元素的处理了。我们只负责处理即可。

    6、Lambda中使用变量

    在Lambda中可以定义自己的局部变量,也可以使用外层方法的局部变量,还可以使用属性。这一点也不难理解,既然是一个方法的实现,只写了一个代码块,那么使用本身所属方法的局部变量和类的属性也并不过分。

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n64" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public static void main(String[] args) {
    List<String> strs = new ArrayList<String>(){
    {
    add("aaa");
    add("bbb");
    add("ccc");
    }
    };
    int j = 1;
    strs.forEach((str)->{
    int i = 0;
    System.out.println(str + " " + i + " " + j);
    });
    }</pre>

    注意:此时外部局部变量将自动变为final

    7、Lambda作为方法返回值

    例子:返回判断字符串是否为空

    <pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n68" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public class Demo004_2 {
    public static void main(String[] args) {
    System.out.println(testLambda().isEmpty("string"));
    }

    // 判断字符串是否为空
    public static AssertEmpty testLambda(){
    return (n)-> null==n||n.trim().isEmpty(n);
    }
    }

    interface AssertEmpty{
    boolean isEmpty(String str);
    }</pre>

    相关文章

      网友评论

          本文标题:Lambda原来还可以这么用

          本文链接:https://www.haomeiwen.com/subject/ktggrktx.html