>什么是Lambda表达式
简短的说,Lambda表达式是一种用于取代匿名类,把函数行为表述为函数式编程风格的一种匿名函数。
匿名类大家自然熟悉,上面那句话提到了“函数行为”,那么什么是函数行为?
假设有这样一个应用场景:计算机要通过给定的某工人的薪水计算出该工人要交纳多少税。我们有以下代码:
@FunctionalInterface
interface TaxFunction{
double tax(double salary);
class Computer{
public double taxing(double salary,TaxFunction func){
return func.tax(salary);
计算机计算税收,应当有一个计算方式,这个计算方式就是TaxFunction接口类中给出的抽象方法tax。之所以要设计成抽象的方法,因为针对不同的收入阶层或是企业类型,可能会有不同的税收方法。假设对于工人A,税收为其总收入salary的10%:
Computer computer = new Computer();
double hisTax = computer.taxing(251, new TaxFunction() {
@Override
public double tax(double salary) {
return salary*0.1;
这其中我们使用了一个匿名类TaxFunction并直接重写了tax方法。这个tax方法就是一种函数行为,其描述了这样一种行为:x->f(x)=x*0.1,也就是传入一个状态值x,返回经过函数f映射后的值0.1*x。
这是一种函数式编程的思想。关于函数式编程,还可以查看>这篇文章<中第一个例子辅助理解。
>短小精悍的Lambda表达式
在上面那个例子中,很容易注意到我们只为了完成 x->f(x)=x*0.1 的映射,就要new 一个匿名类 TaxFunction写上足足至少四行代码来完成这个函数行为。Java本来就以冗余被人所诟病,这样的写法虽然看上去没什么问题,但是也暴露了Java代码“又臭又长”的缺点。
而Java中的Lambda表达式就是JDK8中为了避免这种冗余而出现的一种新特性。借由Lambda表达式,上面那段代码要怎么写呢?
Computer computer = new Computer();
hisTax = computer.taxing(251, x -> x*0.1);
一行就搞定了。要想知道Lambda表达式究竟是怎么完成这一个操作的,我们需要先了解两个东西:
Lambda表达式的写法和
函数式接口@FunctionalInterface。
>函数式接口@FunctionalInterface
在JDK8中提供了一个新包java.util.function,在这个包里给出了很多常用的函数式接口。我们这里以public interface Function<T, R>作讲解:
@FunctionalInterface//1.函数接口注解
public interface Function<T, R> {
//2.唯一的一个抽象方法
R apply(T t);
//下面这些方法不用管
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
static <T> Function<T, T> identity() {
return t -> t;
注意到,一个函数式接口有两个要素:
- 唯一的一个public抽象方法。(注意:除了这个唯一的抽象方法还允许存在从Object继承下来的抽象方法,如toString()、equalTo())
- @FunctionalInterface注解,这个注解可以显著增加代码的可读性,同时,当编程者不小心在该函数式接口中定义了多于一个的抽象方法时,IDE将会给出错误信息,杜绝一些低级编程错误。如下所示:
我们先来想想一个函数需要哪些必须内容呢?
也就是 x - >f(x) 的一个映射,只需要有传入的参数(也称为状态)x和返回值(也称为映射值)f(x)。至于这个函数叫什么、返回值类型是什么,都不重要。一个匿名函数只需要以上两个必须要素。
结合上面提到的函数接口@FunctionalInterface,之所以要求必须是【唯一】的一个抽象方法,就是为了方便在用Lambda表达式替代匿名类中的函数式时能够方便地找到要替换的匿名函数。
那么Lambda表达式应该怎么书写呢?
在Lambda表达式中,有两种类型的短句:表达式(expression)和语句(statement)。表达式总是有返回值的,如3+2和3>2,一个返回int一个返回布尔值;语句总是没有返回值的,如System.out.println("身披白袍's博客")。表达式和语句可以被一对花括号 { } 裹住,被称作一个语句块,语句块可以类比于一般函数中public void func(int x){ $内容 } 中的{ $内容 }。
一个Lambda表达式总是以以下的形式出现:
* 当且仅当$短句只有一句时,可以省略花括号 { };若此时唯一的短句为一个表达式,可以省略return关键词。当左侧参数只有一个时,可以省略一对圆括号();
* 左侧就是刚刚提到的两个函数要素中的“传入的参数”,-> 右侧的内容就是“返回的值”(包括void)。
我们来举个例子,若在上文的收税模型中,我们要先打印这个工人的工资再求税收,需要这么写:
hisTax = computer.taxing(251, x -> { // 语句块,用花括号括起来
System.out.println("salary = " + x); // 打印工人的工资
return x * 0.1; // 此时这里多了一个return,因为已经不是唯一的表达式了
看完这些内容,再回到我们上面计算税收的例子:
//没用Lambda表达式前
double hisTax = computer.taxing(251, new TaxFunction() {
@Override
//唯一的抽象函数,可被视为一个匿名函数
public double tax(double salary) {
return salary*0.1;
//用Lambda表达式替代了接口中唯一的抽象函数tax()
hisTax = computer.taxing(251, x -> x*0.1);
是不是就能明白Lambda表达式x -> x*0.1是怎么完成匿名函数tax的功能了呢?
如果还没有体会到Lambda表达式的魔力,我们再举个例子:
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 4);
LinkedList<Integer> list = nums.stream().
filter(x -> x>1).
map(n -> n+1 ).
collect(Collectors.toCollection(LinkedList::new));
这段代码的功能是,
过滤出大于1的数字,然后把这些大于1的数字加一,再包装成一个LinkedList。
我们一行一行来看:
LinkedList<Integer> list = nums.stream().
第一行,把一个List<Interger>转化为数据流。关于stream流,这里有一篇非常棒的入门文章:
https://www.ibm.......mapi/。可以暂时不看,你只需要知道它的功能是把nums里的数据挨个排队然后送往下一个函数filter():
filter(x -> x>1).
第二行,这是一个Lambda表达式,直接给出了函数行为:输入一个x状态,然后判断这个状态是否大于一;如果大于1,送往下一个函数map:
map(n -> n+1 ).
第三行,这是一个映射函数。在steam中很重要的概念就是映射/折叠(map/reduce或fold)。它的功能可以理解成把数据流中的每一个状态x进行一个映射操作,比如这里就是把每个状态加一后送往下一个函数collect:
collect(Collectors.toCollection(LinkedList::new));
第四行,这是一个收集函数,是stream中的Terminal操作(终点操作)。所有数据被送到这里后会被收集,并不再往下流动。Collectors.toCollection(LinkedList::new)是一个方法引用,目的是进一步简写Lambda函数,可以到这里查看相关的内容:
http://blog.csdn.net/Shenpibaipao/article/details/78614280。此处只需要知道它把所有经过过滤、加一后的状态收集起来并封装成一个LinkedList就行了。
如果我们不用Lambda表达式来书写这段代码,会是怎么样的呢:
LinkedList<Integer> list2 = nums.stream().
filter(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
if(integer>1)return true;
return false;
map(new Function<Integer, Integer>() {
@Override
public Integer apply(Integer integer) {
return integer+1;
collect(Collectors.toCollection(LinkedList::new));
是不是非常非常长且非常不直观?可以说,用了Lambda表达式来书写函数行为,生产效率和代码美观度将会得到极大的提高。
看到这里基本上对Lambda表达式有了基础的了解。当然了解还是不够的,多看一些实战用例可以更好地理解Lambda表达式:http://www.importnew.com/16436.html
Lambda表达式背景基础语法函数式接口Lambda表达式的基本使用变量的捕获匿名类中的变量捕获Lambda中的变量捕获Lambda在集合当中的使用Lambda的优点和缺点
Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式可以看作是一个匿名函数。
基本语法: (parameters)
1.无法使用continue,break等 用于一般foreach循环的;可用return 此处用法与continue等同;
2.无法在编译期,去改变循环外的对象的引用,或者是基本类型的值;
Integer[] a = new Integer[]{1,2,3,4,5};
Lambda表达式
Lambda表达式是一个
匿名函数,我们可以把
lambda表达式理解为一段可以传递的代码(将代码段像数据一样传递)。使用它可以写出更简洁,更灵活的代码。作为一种更紧凑的代码风格,是
Java语言的表达式能力得到的提升。
Lambda表达式的本质只是一个“
语法糖”,由编译器推断并帮你转换为包装为常规的代码,因此你可以使用更少的代码来实现同样的功能。
Java中的
Lambda表达式通常使用(argument)->{body}语法书写,例如:
左侧:
lambda 表达式的参数列表
JDK在不断升级过程中,要致力解决的问题之一就是让程序代码变得更加简洁。JDK8引入的Lambda表达式在简化程序代码方面大显身手,它用简明扼要的语法来表达某种功能包含的操作。在程序遍历访问集合中元素的场合,运用Lambda表达式可以大大简化操纵集合的程序代码。
Lambda表达式的基本用法
我们先看一个程序示例
public class SimpleTest {
public static void main(String[] args) {
String [] data={"To
目录前言一丶Lambda表达式存在意义1.问题提出2.方式一:策略模式3.方式二:使用内部类4.方式三:Lambda表达式二丶什么是Lambda表达式1.Lambda语法2.函数式接口3.Lambda表达式的示例<1>无参数无返回值<2>有一个参数,且只有一条语句<3>有返回值,且只有一条语句<4>两个以上参数,有返回值,有多条语句<5>. lambda表达式参数列表的类型可以省略不写
哈哈哈,SE部分的最后一篇博客啦,补上SE阶段的博客完整