从2014年java8发布到现在已经有几个年头了,现在java11都发布了。公司最近把服务器环境重新搭建了一遍,jdk版本也从7换成了8,终于可以在代码里面写Lambda表达式了。作为一名java开发人员,java8的一些新东西也是必须要掌握的,今天就说说这Lambda表达式的使用。

一、Lambda表达式简介

(1)定义
Lambda是一个匿名函数,我们可以把Lambda表达式理解为一段可以传递的代码。
优点:可以写出更简洁、更灵活的代码;同时它还是一种更紧凑的代码风格,使java的语言表达能力得到了提升
(2)看看代码
我们通过对比new一个Runnable的案例来对比使用Lambda表达式和不使用Lambda表达式的区别,代码如下:
	@Test
public void test01() {
// java7 new一个Runnable 匿名内部类
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("runnable java7");
}
}; // java8 new一个Runnable 使用了Lambda表达式,代码更紧凑了
Runnable r2 = () -> System.out.println("runnable java8"); // 开启线程
new Thread(r1).start();
new Thread(r2).start();
} @Test
public void test02() {
// java7 匿名内部类方式 新开一条线程
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("runnable java7 thread");
}
}).start(); // java8 使用了Lambda表达式 替代了匿名内部类,代码更简洁。
// 从这也能体现出Lambda表达式是一段可传递的代码(因为Lambda表达式等价于一个匿名内部类对象,所以可以当参数传递)
new Thread(() -> System.out.println("runnable java8 thread")).start();
}
32
32
 
1
    @Test
2
    public void test01() {
3
        // java7 new一个Runnable 匿名内部类
4
        Runnable r1 = new Runnable() {
5
            @Override
6
            public void run() {
7
                System.out.println("runnable java7");
8
            }
9
        };
10
        
11
        // java8 new一个Runnable  使用了Lambda表达式,代码更紧凑了
12
        Runnable r2 = () -> System.out.println("runnable java8");
13
        
14
        // 开启线程
15
        new Thread(r1).start();
16
        new Thread(r2).start();
17
    }
18
    
19
    @Test
20
    public void test02() {
21
        // java7 匿名内部类方式 新开一条线程
22
        new Thread(new Runnable() {
23
            @Override
24
            public void run() {
25
                System.out.println("runnable java7 thread");
26
            }
27
        }).start();
28
        
29
        // java8   使用了Lambda表达式 替代了匿名内部类,代码更简洁。
30
        // 从这也能体现出Lambda表达式是一段可传递的代码(因为Lambda表达式等价于一个匿名内部类对象,所以可以当参数传递)
31
        new Thread(() -> System.out.println("runnable java8 thread")).start();
32
    }
代码中new一个Runnable可以通过匿名内部类的方式,也可以采用Lambda的方式。但采用Labmbda方式的代码更简洁,可以让代码更紧凑。同时,匿名内部类对象是可以当成参数来直接传递的,Lambda表达式也可以用来当参数传。这就很好的解释了我们上面对Lambda的定义,即:【1】一个匿名函数,【2】一段可以传递的代码。

二、Lambda表达式的语法格式

        说语法格式之前,先来看张图吧。
    
    这图的左边是采用匿名内部类形式new的一个Runnable对象,右边是采用Lambda形式new的Runnable对象。对比一下就能领悟到Lambda表达式的语法格式啦。
(1)Lambda表达式标准格式
Lambda表达式个标准形式如下图:
Lambda表达式标准格式:左侧 -> 右侧
    左侧:指定了Lambda 表达式所需要的所有参数,即:形参列表。
    右侧:指定了Lambda 体,即:Lambda表达式要执行的功能。
(2)Lambda表达式语法格式一
左侧形参列表可以不需要参数的数据类型,java8后会根据上下文自动进行类型推断。
也就是说我们在Lambda的形参列表里面写的参数是可以不写数据类型的。具体案例见下图:
(3)Lambda表达式语法格式二
左侧形参列表只有一个参数时,小括号可以省略不写。不过一般建议还是写一下。
具体的案例见下图
(4)Lambda表达式语法格式三
左侧形参列表没有参数时,小括号必须保留
具体参考下面案例
这也是为什么在(3)中建议一个参数时也把小括号写上,写法统一一下。
(5)Lambda表达式语法格式四
右侧方法体中代码有多行时,需要用大括号包起来
具体看下图:
(6)Lambda表达式语法格式五
当右侧方法体中代码只有一行时,大括号可省略,同时return关键字也可以省略。
具体参考下图:

三、Lambda表达式vs匿名内部类

        看完这么多例子,感觉能用匿名内部类的地方就能用Lambda表达式。其实是不行的,不是所有能用匿名内部类的地方都可以用Lambda表达式来替代的。
下面我们来看个案例
(1)首先随便定义一接口
public interface TestFun {
// 这接口里面有2个抽象方法
void sayHello();
void end();
}
6
6
 
1
public interface TestFun {
2
    // 这接口里面有2个抽象方法
3
    void sayHello();
4
    void end();
5
}
6

(2)使用匿名内部类和Lambda表达式来创建这个接口的实例
	public static void main(String[] args) {
// 匿名内部类 == Lambda表达式 ? no .. // 匿名内部类
TestFun t1 = new TestFun() {
@Override
public void sayHello() {
System.out.println("hello");
}
@Override
public void end() {
System.out.println("end");
}
};
t1.sayHello();
t1.end(); // lambda 创建不了TestFun的实例对象,
// TestFun t2 = () -> {}
// 提示The target type of this expression must be a functional interface
// 因为 lambda表达式需要函数式接口
// 那什么是函数式接口, 我们可以去看看几个函数式接口Comparator、Runnable
// 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。 }
25
25
 
1
    public static void main(String[] args) {
2
        // 匿名内部类 == Lambda表达式 ?   no .. 
3
        
4
        // 匿名内部类
5
        TestFun t1 = new TestFun() {
6
            @Override
7
            public void sayHello() {
8
                System.out.println("hello");
9
            }
10
            @Override
11
            public void end() {
12
                System.out.println("end");
13
            }
14
        };
15
        t1.sayHello();
16
        t1.end();
17
        
18
        // lambda 创建不了TestFun的实例对象,
19
        // TestFun t2 = () -> {}
20
        // 提示The target type of this expression must be a functional interface
21
        // 因为 lambda表达式需要函数式接口
22
        // 那什么是函数式接口,  我们可以去看看几个函数式接口Comparator、Runnable
23
        // 函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
24
        
25
    }
在写代码过程中发现Lambda表达式创建不了这种接口里面有多个抽象方法的对象,而匿名内部类可以。
在使用Lambda表达式时eclipse直接提示了一个错误,错误消息见下图:
这个弹窗的提示说目标类型必须是函数式接口。
(3)小结
    通过上面这个案例,我们发现并不是所有能用匿名内部类的地方都可以用Lambda表达式来替代。
Lambda表达式只能用来替代那些函数式接口的匿名内部类。那什么是函数式接口呢?继续往下看吧

四、函数式接口

(1)定义
从java8实战这书中读到了函数式接口的定义如下:
一言以蔽之,函数式接口就是只定义一个抽象方法的接口
1
1
 
1
一言以蔽之,函数式接口就是只定义一个抽象方法的接口
上面这个定义已经很言简意赅了,函数式接口就是只有一个抽象方法的接口

(2)说说常用的函数式接口
直接可以去看jdk的java.util.function包下面看,都是函数式接口。常用的函数式接口如下:
  • 消费型接口Consumer
        它有一个抽象方法,形参列表为一个参数,没有返回值。具体的参考下面代码的案例
    /**
* 消费型接口Consumer
*/
@Test
public void test01() {
/*
* Consumer是一个消费型接口
* (1)该接口的抽象方法为void accept(T t);
* (2)这个抽象方法形参列表有一个参数,没有返回值;
* (3)这个方法就是一个有数据进去,没数据返回的接口; 所以就叫它消费型接口
*/
Consumer<String> c = (x) -> {
System.out.println(x);
System.out.println("length is:" + x.length());
};
c.accept("hello"); // 我们传一个hello给它,将会在控制台中打印出hello及它的长度
}
17
17
 
1
    /**
2
     * 消费型接口Consumer
3
     */
4
    @Test
5
    public void test01() {
6
        /*
7
         *  Consumer是一个消费型接口
8
         *  (1)该接口的抽象方法为void accept(T t);
9
         *  (2)这个抽象方法形参列表有一个参数,没有返回值;
10
         *  (3)这个方法就是一个有数据进去,没数据返回的接口; 所以就叫它消费型接口
11
         */
12
        Consumer<String> c = (x) -> {
13
            System.out.println(x);
14
            System.out.println("length is:" + x.length());
15
        };
16
        c.accept("hello");  // 我们传一个hello给它,将会在控制台中打印出hello及它的长度
17
    }
  • 断言型接口Predicate
        它有一个抽象方法,形参列表为一个参数,返回值为boolean类型。特别适合条件判断的场景,具体的参考下面代码的案例
    /**
* 断言型接口Predicate
*/
@Test
public void test02() {
/*
* Predicate是一个断言型接口
* (1)该接口的抽象方法为boolean test(T t);
* (2)这个抽象方法形参列表有一个参数,返回值为boolen;
* (3)这个方法就是一个有数据进去,返回true或者false; 特别适合用来做条件判断的场景
*/
// 下面演示一个过滤集合里面元素的案例,过滤掉集合里面小于5的元素
List<Integer> list = listFilter(Arrays.asList(new Integer[]{12, 2, 3, 10, 25}), x -> x >= 5);
System.out.println(list); // 输出 [12, 10, 25]
} /**
* 定义的一个集合过滤方法
* @param list 集合
* @param predicate 断言型接口,用来里面包含了过滤的条件
* @return
*/
private <T> List<T> listFilter(List<T> list, Predicate<T> predicate) {
List<T> result = new ArrayList<T>();
for (T t : list) {
if (predicate.test(t)) {
result.add(t);
}
}
return result;
}
32
32
 
1
    /**
2
     * 断言型接口Predicate
3
     */
4
    @Test
5
    public void test02() {
6
        /*
7
         *  Predicate是一个断言型接口
8
         *  (1)该接口的抽象方法为boolean test(T t);
9
         *  (2)这个抽象方法形参列表有一个参数,返回值为boolen;
10
         *  (3)这个方法就是一个有数据进去,返回true或者false; 特别适合用来做条件判断的场景
11
         */
12
        // 下面演示一个过滤集合里面元素的案例,过滤掉集合里面小于5的元素
13
        List<Integer> list = listFilter(Arrays.asList(new Integer[]{12, 2, 3, 10, 25}), x -> x >= 5);
14
        System.out.println(list);   // 输出 [12, 10, 25]
15
    }
16

17
    /**
18
     * 定义的一个集合过滤方法
19
     * @param list      集合
20
     * @param predicate 断言型接口,用来里面包含了过滤的条件
21
     * @return
22
     */
23
    private <T> List<T> listFilter(List<T> list, Predicate<T> predicate) {
24
        List<T> result = new ArrayList<T>();
25
        for (T t : list) {
26
            if (predicate.test(t)) {
27
                result.add(t);
28
            }
29
        }
30
        return result;
31
    }
32

更多函数式接口,可以直接看java.util.function包里面的内容。


Java8_Lambda表达式的更多相关文章

  1. 【.net 深呼吸】细说CodeDom(2):表达式、语句

    在上一篇文章中,老周厚着脸皮给大伙介绍了代码文档的基本结构,以及一些代码对象与CodeDom类型的对应关系. 在评论中老周看到有朋友提到了 Emit,那老周就顺便提一下.严格上说,Emit并不是针对代 ...

  2. 你知道C#中的Lambda表达式的演化过程吗?

    那得从很久很久以前说起了,记得那个时候... 懵懂的记得从前有个叫委托的东西是那么的高深难懂. 委托的使用 例一: 什么是委托? 个人理解:用来传递方法的类型.(用来传递数字的类型有int.float ...

  3. 再讲IQueryable<T>,揭开表达式树的神秘面纱

    接上篇<先说IEnumerable,我们每天用的foreach你真的懂它吗?> 最近园子里定制自己的orm那是一个风生水起,感觉不整个自己的orm都不好意思继续混博客园了(开个玩笑).那么 ...

  4. Linq表达式、Lambda表达式你更喜欢哪个?

    什么是Linq表达式?什么是Lambda表达式? 如图: 由此可见Linq表达式和Lambda表达式并没有什么可比性. 那与Lambda表达式相关的整条语句称作什么呢?在微软并没有给出官方的命名,在& ...

  5. 背后的故事之 - 快乐的Lambda表达式(一)

    快乐的Lambda表达式(二) 自从Lambda随.NET Framework3.5出现在.NET开发者眼前以来,它已经给我们带来了太多的欣喜.它优雅,对开发者更友好,能提高开发效率,天啊!它还有可能 ...

  6. Kotlin的Lambda表达式以及它们怎样简化Android开发(KAD 07)

    作者:Antonio Leiva 时间:Jan 5, 2017 原文链接:https://antonioleiva.com/lambdas-kotlin/ 由于Lambda表达式允许更简单的方式建模式 ...

  7. SQL Server-表表达式基础回顾(二十四)

    前言 从这一节开始我们开始进入表表达式章节的学习,Microsoft SQL Server支持4种类型的表表达式:派生表.公用表表达式(CTE).视图.内嵌表值函数(TVF).简短的内容,深入的理解, ...

  8. 立即执行函数表达式(IIFE)

    原文地址:benalman.com/news/2010/11/immediately-invoked-function-expression/ 译者:nzbin 也许你还没有注意到,我是一个对术语比较 ...

  9. javascript:逆波兰式表示法计算表达式结果

    逆波兰式表示法,是由栈做基础的表达式,举个例子: 5 1 2 + 4 * + 3 -  等价于   5 + ((1 + 2) * 4) - 3 原理:依次将5 1 2 压入栈中, 这时遇到了运算符 + ...

随机推荐

  1. Web框架的应用

    从今天开始,我们将要学习有关Web框架的一些内容,在学习之前先来学习一下http协议,即基于http是如何通信的. http 概要:http是基于tcp/ip通信协议来传输数据的. 优点: 1.简单快 ...

  2. Git 推送和删除标签

    事实上Git 的推送和删除远程标签命令是相同的,删除操作实际上就是推送空的源标签refs:git push origin 标签名相当于git push origin refs/tags/源标签名:re ...

  3. LeetCode Remove Duplicates from Sorted Array II 删除整型数组中的重复元素并返回剩下元素个数2

    class Solution { public: int removeDuplicates(int A[], int n) { ],*e=&A[]; //s指向“连续数字”的第一个,e往后遍历 ...

  4. 利用photoshop制作gif图片

    首先准备你需要的几张素材图片 1.将素材图片根据发生的顺序放置在不同的图层 2.打开窗口下的时间轴 选择帧动画 3.创建第一张帧动画 选项卡右边这个按钮,点击这个选择新建帧 第一张图片显示其他的隐藏 ...

  5. idea搭建ssm

    第一步:打开intellij idea,创建maven项目 参考:http://blog.csdn.net/w8897282/article/details/71173211  1.创建一个maven ...

  6. js中(break,continue,return)的区别

    break 一般用于跳出整个循环(for,while) continue  跳出本次循环,进入下一次循环 return 只能出现在函数体内,一旦执行return,后面的代码将不会执行,经常用retur ...

  7. System.FormatException: GUID 应包含带 4 个短划线的 32 位数(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)。解决办法

    查一下数据库的UID数据是否格式正确,如: 错误格式1: {E056BB36-D824-4106-A9C3-D8D8B9ADC1C 错误格式2: E056BB36-D824-4106-A9C3-D8D ...

  8. LA 2038 Strategic game(最小点覆盖,树形dp,二分匹配)

    题意即求一个最小顶点覆盖. 对于没有孤立点的图G=(V,E),最大独立集+最小顶点覆盖= V.(往最大独立集加点) 问题可以变成求树上的最大独立集合. 每个结点的选择和其父节点选不选有关, dp(u, ...

  9. 前端知识体系之CSS及其预处理器SASS/LESS

    如果你是个前端设计师,很多时候我们都在写CSS,CSS是定义页面样式的脚本,并不是一种编程语言,只是一行行单纯的描述页面元素的样子,如果对英语熟练的话,它像说话一样简单,这里举个简单的例子: body ...

  10. 关于mongodb的日志

    mongodb的日志与profile相似,在启动mongod时 可以用verbose这个参数配置他的日志详细程度,分为一个v到5个v,其中v越多,详细度越高   mogod.conf port = d ...