跟上java8–了解lambda

星朝      2022-04-10     337

关键词:

从java8出现以来lambda是最重要的特性之一,它可以让我们用简洁流畅的代码完成一个功能。 很长一段时间java被吐槽是冗余和缺乏函数式编程能力的语言,随着函数式编程的流行java8种也引入了 这种编程风格。在此之前我们都在写匿名内部类干这些事,但有时候这不是好的做法,本文中将介绍和使用lambda, 带你体验函数式编程的魔力。

技术分享图片

什么是lambda?

lambda表达式是一段可以传递的代码,它的核心思想是将面向对象中的传递数据变成传递行为。 我们回顾一下在使用java8之前要做的事,之前我们编写一个线程时是这样的:

1
2
3
4
5
6
Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println("do something.");     
    }
}

也有人会写一个类去实现Runnable接口,这样做没有问题,我们注意这个接口中只有一个run方法, 当把Runnable对象给Thread对象作为构造参数时创建一个线程,运行后将输出do something.。 我们使用匿名内部类的方式实现了该方法。

这实际上是一个代码即数据的例子,在run方法中是线程要执行的一个任务,但上面的代码中任务内容已经被规定死了。 当我们有多个不同的任务时,需要重复编写如上代码。

设计匿名内部类的目的,就是为了方便 Java 程序员将代码作为数据传递。不过,匿名内部 类还是不够简便。 为了执行一个简单的任务逻辑,不得不加上 6 行冗繁的样板代码。那如果是lambda该怎么做?

1
Runnable r = () -> System.out.println("do something.");

嗯,这代码看起来很酷,你可以看到我们用()和->的方式完成了这件事,这是一个没有名字的函数,也没有人和参数,再简单不过了。 使用->将参数和实现逻辑分离,当运行这个线程的时候执行的是->之后的代码片段,且编译器帮助我们做了类型推导; 这个代码片段可以是用{}包含的一段逻辑。下面一起来学习一下lambda的语法。

基础语法

在lambda中我们遵循如下的表达式来编写:

1
expression = (variable) -> action
  • variable: 这是一个变量,一个占位符。像x,y,z,可以是多个变量;
  • action: 这里我称它为action, 这是我们实现的代码逻辑部分,它可以是一行代码也可以是一个代码片段。

可以看到Java中lambda表达式的格式:参数、箭头、以及动作实现,当一个动作实现无法用一行代码完成,可以编写 一段代码用{}包裹起来。

lambda表达式可以包含多个参数,例如:

1
int sum = (x, y) -> x + y;

这时候我们应该思考这段代码不是之前的x和y数字相加,而是创建了一个函数,用来计算两个操作数的和。 后面用int类型进行接收,在lambda中为我们省略去了return。

函数式接口

函数式接口是只有一个方法的接口,用作lambda表达式的类型。前面写的例子就是一个函数式接口,来看看jdk中的Runnable源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object‘s
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

这里只有一个抽象方法run,实际上你不写public abstract也是可以的,在接口中定义的方法都是public abstract的。 同时也使用注解@FunctionalInterface告诉编译器这是一个函数式接口,当然你不这么写也可以,标识后明确了这个函数中 只有一个抽象方法,当你尝试在接口中编写多个方法的时候编译器将不允许这么干。

尝试函数式接口

我们来编写一个函数式接口,输入一个年龄,判断这个人是否是成人。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class FunctionInterfaceDemo {
    @FunctionalInterface
    interface Predicate<T> {
        boolean test(T t);
    }
    /**
     * 执行Predicate判断
     *
     * @param age       年龄
     * @param predicate Predicate函数式接口
     * @return          返回布尔类型结果
     */
    public static boolean doPredicate(int age, Predicate<Integer> predicate) {
        return predicate.test(age);
    }
     
    public static void main(String[] args) {
        boolean isAdult = doPredicate(20, x -> x >= 18);
        System.out.println(isAdult);
    }
}

从这个例子我们很轻松的完成 是否是成人 的动作,其次判断是否是成人,在此之前我们的做法一般是编写一个 判断是否是成人的方法,是无法将 判断 共用的。而在本例只,你要做的是将 行为 (判断是否是成人,或者是判断是否大于30岁) 传递进去,函数式接口告诉你结果是什么。

实际上诸如上述例子中的接口,伟大的jdk设计者为我们准备了java.util.function包

技术分享图片

我们前面写的Predicate函数式接口也是JDK种的一个实现,他们大致分为以下几类:

技术分享图片

消费型接口示例

1
2
3
4
5
6
public static void donation(Integer money, Consumer<Integer> consumer){
    consumer.accept(money); 
}
public static void main(String[] args) {
    donation(1000, money -> System.out.println("好心的麦乐迪为Blade捐赠了"+money+"元")) ;
}

供给型接口示例

1
2
3
4
5
6
7
8
9
10
public static List<Integer> supply(Integer num, Supplier<Integer> supplier){
       List<Integer> resultList = new ArrayList<Integer>()   ;
       for(int x=0;x<num;x++) 
           resultList.add(supplier.get());
       return resultList ;
}
public static void main(String[] args) {
    List<Integer> list = supply(10,() -> (int)(Math.random()*100));
    list.forEach(System.out::println);
}

函数型接口示例

转换字符串为Integer

1
2
3
4
5
6
public static Integer convert(String str, Function<String, Integer> function) {
    return function.apply(str);
}
public static void main(String[] args) {
    Integer value = convert("28", x -> Integer.parseInt(x));
}

断言型接口示例

筛选出只有2个字的水果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static List<String> filter(List<String> fruit, Predicate<String> predicate){
    List<String> f = new ArrayList<>();
    for (String s : fruit) {
        if(predicate.test(s)){
            f.add(s);
        }
    }
    return f;
}
public static void main(String[] args) {
    List<String> fruit = Arrays.asList("香蕉", "哈密瓜", "榴莲", "火龙果", "水蜜桃");
    List<String> newFruit = filter(fruit, (f) -> f.length() == 2);
    System.out.println(newFruit);
}

默认方法

在Java语言中,一个接口中定义的方法必须由实现类提供实现。但是当接口中加入新的API时, 实现类按照约定也要修改实现,而Java8的API对现有接口也添加了很多方法,比如List接口中添加了sort方法。 如果按照之前的做法,那么所有的实现类都要实现sort方法,JDK的编写者们一定非常抓狂。

幸运的是我们使用了Java8,这一问题将得到很好的解决,在Java8种引入新的机制,支持在接口中声明方法同时提供实现。 这令人激动不已,你有两种方式完成 1.在接口内声明静态方法 2.指定一个默认方法。

我们来看看在JDK8中上述List接口添加方法的问题是如何解决的

1
2
3
4
5
6
7
8
9
default void sort(Comparator<? super E> c) {
    Object[] a = this.toArray();
    Arrays.sort(a, (Comparator) c);
    ListIterator<E> i = this.listIterator();
    for (Object e : a) {
        i.next();
        i.set((E) e);
    }
}

翻阅List接口的源码,其中加入一个默认方法default void sort(Comparator<? super E> c)。 在返回值之前加入default关键字,有了这个方法我们可以直接调用sort方法进行排序。

1
2
3
List<Integer> list = Arrays.asList(2, 7, 3, 1, 8, 6, 4);
list.sort(Comparator.naturalOrder());
System.out.println(list);

Comparator.naturalOrder()是一个自然排序的实现,这里可以自定义排序方案。你经常看到使用Java8操作集合的时候可以直接foreach的原因也是在Iterable接口中也新增了一个默认方法:forEach,该方法功能和 for 循环类似,但是允许 用户使用一个Lambda表达式作为循环体。

原文地址:http://biezhi.me/2017/07/17/keep-up-with-java8-lambda.html

java8——lambda表达式

...不介绍Lambda的前世今生,这里只对Lambda表达的应用做详细了解。以及与内部类的差异点。Lambda表达式Lambda表达式是JavaSE8版本中引入的新的语法糖。将功能看做方法参数,将代码看做数据。Lambda表达式语法:LambdaParameters->LambdaBo... 查看详情

java8中lambda表达式默认方法的模板方法模式,你够了解么?

为了以更简单的术语描述模板方法,考虑这个场景:假设在一个工作流系统中,为了完成任务,有4个任务必须以给定的执行顺序执行。在这4个任务中,不同工作流系统的实现可以根据自身情况自定义任务的执行内容。模板方法... 查看详情

java8中的lambda表达式

...OP(面向对象编程)的功能来加以讨论。在本文中,我们将了解到lambda表达式具体是什么东西,还有就是它们是如何将自己融入整个Java生态系统的。我们也会对没有使用lambda表达 查看详情

java8函数式编程数据流和lambda表达式

...本文将通过简单的实例令读者对函数式编程有一个大体的了解。我们知道OOP是以类为基础的,程序中必须首先抽象和定义class。那么FP创建的基础是什么?或者说在Java8中,至少需要了解什么知识点才能实现基本的函数式编程呢?... 查看详情

知识精解java8中的lambda表达式

...,不会覆盖相关技术的全部内容,适合想要快速了解相关技术核心内容的人群阅读。本文为《Java8函数式编程》(Java8Lambdas:FunctionalProgrammingfortheMasses)第二章内容的精解,若对相关知识感兴趣,想要全面的学习... 查看详情

java8:lambda表达式增强版comparator和排序

1、概述在这篇教程里,我们将要去了解下即将到来的JDK8(译注,现在JDK8已经发布了)中的Lambda表达式——特别是怎样使用它来编写Comparator和对集合(Collection)进行排序。这篇文章是Baeldung上的“Java——回归基础”(“Java–Bac... 查看详情

都java19了,还不了解java8?一文带你深入了解java8新特性

...赞收藏)新特性以下是Java8新增的部分特性,更多新特性了解请详细参考:​​WhatsNewinJDK8​​•Lambda表达式•方法引用•函数式接口•默认方法•Strea 查看详情

java8_stream_了解

了解StreamJava8中有两大最为重要的改变。第一个是Lambda表达式;另外一个则是StreamAPI(java.util.stream.*)。Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操... 查看详情

java8lambda的使用

与python不一样,pythonlambda是定义匿名函数,而在java8中lambda是匿名内部类例1、用lambda表达式实现Runnable我开始使用Java8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例。看一下Java8之前的runnabl... 查看详情

Java8 Lambda 与匿名类

】Java8Lambda与匿名类【英文标题】:Java8LambdasvsAnonymousclasses【发布时间】:2014-05-0311:48:18【问题描述】:由于最近发布了Java8,而且它全新的lambda表达式看起来非常酷,我想知道这是否意味着我们习惯的Anonymous类的消亡。我对此... 查看详情

java8-04-笔记

Java8-04-笔记强大的StreamAPI1、了解Stream流2、什么是Stream3、Stream操作的三个步骤3.1创建Stream3.2Stream中间操作3.3Stream终止操作(终端操作)3.4StreamAPI练习3.5并行流与顺序流强大的StreamAPI1、了解Stream流Java8中有两个最为重要的改变:*... 查看详情

JAVA8 可选和 Lambda

】JAVA8可选和Lambda【英文标题】:JAVA8OptionalandLambdas【发布时间】:2021-08-1314:42:37【问题描述】:假设我有这个class模型层次结构:publicclassAprivateIntegerid;privateList<B>b;还有:publicclassBprivateIntegerid;privateList<C>c;最后:publiccla... 查看详情

java8新特性03lambda表达式

一.Lambda表达式概述Lambda表达式是Java8中最大的变化。它允许我们将一个函数当作方法的参数,或者说把一段代码当作数据使用。很多基于JVM平台的语言一开始就支持Lambda表达式,比如Scala,但是Java语言一直只能使用匿名内部类来... 查看详情

java8中的lambda表达式

Lambda是什么Lambda表达式,也可称为闭包,是java8的新特性,作用是取代大部分内部类,优化java代码结构,让代码变得更加简洁紧凑。Lambda的基本语法 (expression)->expression或(expression)->{statements;} Lambda最重要特点用()->{}... 查看详情

java8都有哪些新特性

...类的流式访问,可以基于此使用map和reduce并行计算。java了解可以多看看视频,你会了解更多,推荐b站高淇老师讲的java还不错。 参考技术D随着编程语言生态系统的气候不断变化以及技术的革新,经历20余年的发展,Java 查看详情

java8新特性lambda表达式

一、Lambda表达式是什么?Lambda读音:拉姆达。Lambda是一个匿名函数,匿名函数就是一个没有名字的函数。Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)。Lambda表达式可以使代码变的更加简洁紧凑。语法lambda... 查看详情

java8:lambda表达式

1、lambda表达式的书写(1)lambda表达式:在java中Lambda表达式是对象,他们必须依赖于一类特别的对象类型函数式接口@FunctionalInterfaceinterfaceMyInterface1{voidmyMethod1();}@FunctionalInterfaceinterfaceMyInterface2{voidmyMethod2();}publicclassTest 查看详情

java8lambda表达式

Java8Lambda表达式语法lambda表达式的语法格式如下:(parameters)->expression或(parameters)->{statements;}Lambda表达式实例publicclassCalculator{interfaceIntegerMath{intoperation(inta,intb);}publicintoperateBinary(inta,in 查看详情