Lambda深入理解

1.Lambda简介

“Lambda 表达式”(lambdaexpression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名。我们可以把Lambda表达式理解为简洁地可传递的匿名函数的一种方式:它没有名称,但它有参数列表,函数主体,返回类型,可能还有一个可以抛出的异常列表。

  • 匿名——匿名这里的意思是无需写函数名字也就是方法名称。
  • 函数——它也是一个函数,因为Lambda函数不像方法那样属于特定的类。但和方法一样,都会有参数列表,函数主体,返回类型,还可能有可以跑出的异常。
  • 传递——以前java不支持传递方法,现在有了Lambda表达式以后可以把其作为参数传递给方法。
  • 简介——无需像匿名类那样写很多模板代码。

举个例子:

JAVA7:
Comparator<Apple> byWeight = new Comparator<Apple>() {
            public int compare(Apple a1, Apple a2){
                return a1.getWeight().compareTo(a2.getWeight());
            }
        };
JAVA8:
Comparator<Apple> byWeight =(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());

上面描述两个苹果比较重量的例子,这里我们可以看出我们的Lambda表达式的代码更加小并且精巧。

2.Lambda讲解

对于我们第一节中的Lambda表达式有三个部分:

  • 参数列表 (Apple a1, Apple a2)
  • 箭头 -> 用于把参数列表和Lambda分离开
  • Lambda主体 a1.getWeight().compareTo(a2.getWeight())

Java语言设计者选择这样的语法,是因为C#和Scala等语言中的类似功能广受欢迎。 Lambda的基本语法是:

(parameters) -> expression 自带return,后面跟表达式

(parameters) -> { statements; } 不带return 需要手动设置,后面跟语句

2.1哪里使用Lambda表达式?

2.1.1函数式接口

一言以蔽之,函数式接口就是只定义一个抽象方法的接口。举几个例子:

public interface Comparator<T> {
int compare(T o1, T o2);
}
public interface Runnable{
void run();
}
public interface ActionListener extends EventListener{
void actionPerformed(ActionEvent e);
}
public interface Callable<V>{
V call();
}
public interface PrivilegedAction<V>{
V run();
}

上面的都是函数接口,因为他们在自己的接口中只有一个方法。对于函数式接口,Lambda表达式允许我们直接用内联的方式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例。你用匿名内部类也可以完成同样的事情,匿名内部类会有点笨重,代码量会增加。

Runnable r1 = () -> System.out.println("Hello World 1"); //lambda
Runnable r2 = new Runnable(){
public void run(){
System.out.println("Hello World 2");
}
}; //匿名内部类
public static void process(Runnable r){
r.run();
}
process(r1);
process(r2);
process(() -> System.out.println("Hello World 3")); //lambda

在java8中引入了一个注解@FunctionalInterface。这个注解用于表示该接口会设计成一个函数式接口。如果你用@FunctionalInterface定义了一个接口,而它却不是函数式接口的话,编译器将返回一个提示原因的错误。@FunctionalInterface不是必须的但是为了良好的接口设计就像@Override一样,用来表示方法为重写了。

3.函数式接口详解

如上面所说,函数式接口值定义了一个方法。函数式接口的抽象方法的签名称为函数描述符。所以为了应用不同的Lambda表达式,java8也为我们提供了一些常见函数描述符的函数式接口。在我们的java.util.function包中有几个新引入的需要介绍。

3.1Predicate

java.util.function.Predicate<T>接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean。
使用代码如下:

@FunctionalInterface
public interface Predicate<T>{
boolean test(T t);
}
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
List<T> results = new ArrayList<>();
for(T s: list){
if(p.test(s)){
results.add(s);
}
}
return results;
}
Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

在Predicate<T>中有几个default方法用来加强其使用,and,or等等。

3.2Consumer

Consumer顾名思义消费,只消费参数不返回参数。它定义了一个accept方法,接受泛型T的对象,没有返回。你如果需要访问类型T的对象,并对其执行某些操作,就可以使用这个接口。

@FunctionalInterface
public interface Consumer<T>{
    void accept(T t);
}
public static <T> void forEach(List<T> list, Consumer<T> c){
    for(T i: list){
        c.accept(i);
    }
}

    forEach(
    Arrays.asList(1,2,3,4,5),
    (Integer i) -> System.out.println(i)
    );

上面展示了如何打印list中的每个元素,在stream中也会有foreach传递的也是我们的Consumer。

3.3Function

java.util.function.Function<T,R>接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象。如果你需要定义一个Lambda,将输入对象的信息映射到输出,就可以使用这个接口。同样的在stream中有一个map方法参数也是这个,下面我们将模仿map方法。

public static <T,R> List<R> map(List<T> list, Function<T,R> function){
        List<R> result = new ArrayList<R>();
        for(T s : list){
            result.add(function.apply(s));
        }
        return result;
    }
List<String> list = map(Arrays.asList(1,2,3),(Integer i)-> String.valueOf(i));

上面展现了如何把一个Integer类型的字符列表转换成String类型的字符列表。

3.4基本类型的设计

java8为了让我们对基本类型更好的使用,提供了基本类型的函数接口,主要是为了节约我们的内存,如果我们自动装箱拆箱,会占用更多内存。所以提供了一些DoublePredicate、 IntConsumer、 LongBinaryOperator、 IntFunction等的函数式接口让我们使用。

4.lambda综合实战

下面我们会对Apple对象进行排序,我们会按照重量的策略进行排序

4.1最简单的

在java的集合中提供了一个排序的方法,sort方法,方法签名如下:

void sort(Comparator<? super E> c)

第一个方案也是我们最简单的:

public static class AppleComparator implements Comparator<Apple>{

        @Override
        public int compare(Apple o1, Apple o2) {
            return o1.getWeight().compareTo(o2.getWeight());
        }
    }
inventory.sort(new AppleComparator());

4.2匿名内部类

inventory.sort(new Comparator<Apple>() {
    public int compare(Apple a1, Apple a2){
        return a1.getWeight().compareTo(a2.getWeight());
    }
});

4.3使用Lambda表达式

Comparator是函数式接口我们可以使用lambda表达式来改造

inventory.sort((Apple a1, Apple a2)-> a1.getWeight().compareTo(a2.getWeight()));

这里我们可以不用加属性类型,更加简单:

inventory.sort((a1, a2) -> a1.getWeight().compareTo(a2.getWeight()));

当然在我们还能更简单在Comparator中有一个comparing方法的静态辅助方法,它可以接受一个Function。

inventory.sort(Comparator.comparing(a -> a.getWeight()));

4.4方法引用

使用lambda的语法糖可以更加简单

inventory.sort(Comparator.comparing(Apple::getWeight));
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容