JAVA8-lambda表达式1:什么是lambda表达式

目录

导言

起源

尝试一下

什么是Lambda表达式


导言

这几天貌似互联网动作很大,阿里巴巴投资ofo,美团打车要上线,阿里收购饿了么,美团收购摩拜...而朋友圈,更是被一篇鸡血文刷屏,大意是80后的摩拜创始人在公司收购后拿到15,相较之下,而同龄人都是失败者,甚至不配活在这个世上了...

就在想,80尾巴出生的我,是什么生活呢?按照这个逻辑,无疑是loser,也即将面临中年危机,那怎么办?

好好学好java吧!升职加薪,晚饭加鸡腿比较实际点,如果还被这种文章鼓动,要想发财,要想暴富,马上辞职,背上包包,告别家人,奔赴北上深杭,估计多半会春夏秋冬,造福房东!

起源

Lambda表达式是JAVA8引进,可以称之为函数式编程。这在其它语言很常见,比如javascript;但在JAVA中却是一个很大的改动。那什么是函数式编程呢?根本不重要,我们需要的更简单的api,以更容易写出稳定的代码,理解的集合操作,提高计算机的利用率...

尝试一下

只做一点简单的事情。假设有一个集合List,将它的元素打印出来

原来的方式

/**
 * @author kobe_t
 * @date 2018/4/7 14:41
 */
public class Chapter1 {

    @Test
    public void test() {
        List list = Arrays.asList("a", "b", "c");
        // 方式1
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        //方式2
        for (String e : list) {
            System.out.println(e);
        }
    }
}

方式1是jdk1.5之前循环方式,迭代时,可以通过下标获取元素;

方式2是jdk1.5的新特性,它其实是java的语法糖实现,也是俗称外部迭代,相比方式1,它写法更为简便

现在我们有了方式3,叮叮叮!那就是Lambda

List list = Arrays.asList("a", "b", "c");
        // 方式1
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        //方式2
        for (String e : list) {
            System.out.println(e);
        }

        // 方式3
        list.forEach(l -> System.out.println(l));// 方式3
        list.forEach(l -> System.out.println(l));

看见了没,一行代码搞定!再也没有for() {}, 这种样板代码了,Lambda使我们理聚焦于业务代码,告诉它想得到什么,而不用去自己实现各种细节,只要传递我们的行为!

什么是Lambda表达式

再看一下上面的代码

list.forEach(l -> System.out.println(l));

JAVA8-lambda表达式1:什么是lambda表达式_第1张图片

再进去看下这个方法

咦,有个Consumer,是什么东西呢,看看

/*
 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package java.util.function;

import java.util.Objects;

/**
 * Represents an operation that accepts a single input argument and returns no
 * result. Unlike most other functional interfaces, {@code Consumer} is expected
 * to operate via side-effects.
 *
 * 

This is a functional interface * whose functional method is {@link #accept(Object)}. * * @param the type of the input to the operation * * @since 1.8 */ @FunctionalInterface public interface Consumer { /** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t); /** * Returns a composed {@code Consumer} that performs, in sequence, this * operation followed by the {@code after} operation. If performing either * operation throws an exception, it is relayed to the caller of the * composed operation. If performing this operation throws an exception, * the {@code after} operation will not be performed. * * @param after the operation to perform after this operation * @return a composed {@code Consumer} that performs in sequence this * operation followed by the {@code after} operation * @throws NullPointerException if {@code after} is null */ default Consumer andThen(Consumer after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; } }

Ok,其中一个方法,一个默认方法。所以有了这样一个定义

只有一个抽象方法的接口,就是函数式接口

比如用于线程的Runable接口

        // Lambda方式
        Runnable runnable = () -> {};

        // 匿名内部类
        Runnable runnable2 = new Runnable() {
            @Override
            public void run() {
                
            }
        };

上面2种方式,创建Runnable接口;以前匿名内部类方式,发现了代码量多,关键是不能很好的表达程序的意图,而用Lambda方式,很简单;那么怎么识别Lambda表达式

// 形式1
        Runnable runnable1 = () -> {
            System.out.println("Hello");
            System.out.println("World");
        };
        // 形式2
        ActionListener listener = event -> {
            System.out.println("This is a button listener:" + event);
        };
        // 形式3
        BinaryOperator add = (x, y) -> x + y;
        // 形式4
        BinaryOperator lognAdd = (Long x, Long y) -> x + y;

上面几种形式都是Lambda表达式

形式1:Lambda表达式的主体不仅可以是一个表达式,也可以是一段代码块,用{}表明表达式何处开始,何处结束

形式2:Lambda表达式有一个参数event,且只有一个参数,可以省略参数的括号

形式3:有2个x,y,并且都是Long型的,返回x+y这个函数;注意并不是返回x+y的值,那么编译器怎么知道参数的类型呢,等下讲

形式4:也有2个参数x,y,但是声明了是Long型的,并返回x+y的函数代码

那么形式3与形式4有什么区别呢?没有区别!对于3这种来说,编译器会自动推断参数类型,也可以像类型4那样明确告知编译器

这就是java的类型推断

如果用过jdk1.7以上的话,多半知道<>

// 类型推断
        List oldList = new ArrayList();

        List strList = new ArrayList<>();

声明变量时,可以省略类型,jvm会自动推导类型,Lambda则更进一步,把参数的也省略了,一切交给虚拟机吧!

那如果Lambda没有声明类型呢

如上,我们的idea会提示,不能转为Object,因为代码毕竟需要一个地方来指明它的类型,否则它也懵B的

如何传递值

看一个例子

// 引用值
        String name = "test";
        Runnable runnable3 = new Runnable() {
            @Override
            public void run() {
                System.out.println(name);
            }
        };

在线程里面引用了name变量,现在尝试修改name的值,也就是赋给另外的值,如下所示

JAVA8-lambda表达式1:什么是lambda表达式_第2张图片

发现了吗,编译器提示无法通过,且提示我们,变量是final的,不能修改,这就引出了一个定义

Lambda表达式引用的是即成事实的final变量,即意思着不能修改它!在Java8以前,这种变量是必须声明为final的,Java8放松了限制,但是它是既成事实的final变量,不能修改,用不用final声明,取结于编程的习惯;比如下面的代码可以编译通过

// 引用值
        String name = "test";
        // final声明
        final String name2 = "test";
        Runnable runnable3 = new Runnable() {
            @Override
            public void run() {
                // 修改变量name的值
                System.out.println(name + "," + name2);
            }
        };

你可能感兴趣的:(#,lambda,java,开发语言)