详解Java函数式编程和lambda表达式

为什么要使用函数式编程

函数式编程更多时候是一种编程的思维方式,是种方法论。函数式与命令式编程的区别主要在于:函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做。说白了,函数式编程是基于某种语法或调用API去进行编程。例如,我们现在需要从一组数字中,找出最小的那个数字,若使用用命令式编程实现这个需求的话,那么所编写的代码如下:

public static void main(String[] args) {
    int[] nums = new int[]{1, 2, 3, 4, 5, 6, 7, 8};

    int min = Integer.MAX_VALUE;
    for (int num : nums) {
        if (num < min) {
            min = num;
        }
    }
    System.out.println(min);
}

而使用函数式编程进行实现的话,所编写的代码如下:

public static void main(String[] args) {
    int[] nums = new int[]{1, 2, 3, 4, 5, 6, 7, 8};

    int min = IntStream.of(nums).min().getAsInt();
    System.out.println(min);
}

从以上的两个例子中,可以看出,命令式编程需要自己去实现具体的逻辑细节。而函数式编程则是调用API完成需求的实现,将原本命令式的代码写成一系列嵌套的函数调用,在函数式编程下显得代码更简洁、易懂,这就是为什么要使用函数式编程的原因之一。所以才说函数式编程是告诉代码你要做什么,而命令式编程则是告诉代码要怎么做,是一种思维的转变。

说到函数式编程就不得不提一下lambda表达式,它是函数式编程的基础。在Java还不支持lambda表达式时,我们需要创建一个线程的话,需要编写如下代码:

public static void main(String[] args) {
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("running");
        }
    }).start();
}

而使用lambda表达式一句代码就能完成线程的创建,lambda强调了函数的输入输出,隐藏了过程的细节,并且可以接受函数当作输入(参数)和输出(返回值):

public static void main(String[] args) {
    new Thread(() -> System.out.println("running")).start();
}

注:箭头的左边是输入,右边则是输出。

该lambda表达式的作用其实就是返回了Runnable接口的实现对象,这与我们调用某个方法获取实例对象类似,只不过是将实现代码直接写在了lambda表达式里。我们可以做个简单的对比:

public static void main(String[] args) {
    Runnable runnable1 = () -> System.out.println("running");
    Runnable runnable2 = RunnableFactory.getInstance();
}

JDK8接口新特性

1.函数接口,接口只能有一个需要实现的方法,可以使用@FunctionalInterface 注解进行声明。如下:

@FunctionalInterface
interface Interface1 {
    int doubleNum(int i);
}

使用lambda表达式获取该接口的实现实例的几种写法:

public static void main(String[] args) {
    // 最常见的写法
    Interface1 i1 = (i) -> i * 2;
    Interface1 i2 = i -> i * 2;

    // 可以指定参数类型
    Interface1 i3 = (int i) -> i * 2;

    // 若有多行代码可以这么写
    Interface1 i4 = (int i) -> {
        System.out.println(i);
        return i * 2;
    };
}

2.比较重要的一个接口特性是接口的默认方法,用于提供默认实现。默认方法和普通实现类的方法一样,可以使用this等关键字:

@FunctionalInterface
interface Interface1 {
    int doubleNum(int i);

    default int add(int x, int y) {
        return x + y;
    }
}

之所以说默认方法这个特性比较重要,是因为我们借助这个特性可以在以前所编写的一些接口上提供默认实现,并且不会影响任何的实现类以及既有的代码。例如我们最熟悉的List接口,在JDK1.2以来List接口就没有改动过任何代码,到了1.8之后才使用这个新特性增加了一些默认实现。这是因为如果没有默认方法的特性的话,修改接口代码带来的影响是巨大的,而有了默认方法后,增加默认实现可以不影响任何的代码。

3.当接口多重继承时,可能会发生默认方法覆盖的问题,这时可以去指定使用哪一个接口的默认方法实现,如下示例:

@FunctionalInterface
interface Interface1 {
    int doubleNum(int i);

    default int add(int x, int y) {
        return x + y;
    }
}

@FunctionalInterface
interface Interface2 {
    int doubleNum(int i);

    default int add(int x, int y) {
        return x + y;
    }
}

@FunctionalInterface
interface Interface3 extends Interface1, Interface2 {

    @Override
    default int add(int x, int y) {
        // 指定使用哪一个接口的默认方法实现
        return Interface1.super.add(x, y);
    }
}

函数接口

我们本小节来看看JDK8里自带了哪些重要的函数接口:

可以看到上表中有好几个接口,而其中最常用的是Function接口,它能为我们省去定义一些不必要的函数接口,减少接口的数量。我们使用一个简单的例子演示一下 Function 接口的使用:

import java.text.DecimalFormat;
import java.util.function.Function;

class MyMoney {
    private final int money;

    public MyMoney(int money) {
        this.money = money;
    }

    public void printMoney(Function<Integer, String> moneyFormat) {
        System.out.println("我的存款: " + moneyFormat.apply(this.money));
    }
}

public class MoneyDemo {
    public static void main(String[] args) {
        MyMoney me = new MyMoney(99999999);

        Function<Integer, String> moneyFormat = i -> new DecimalFormat("#,###").format(i);
        // 函数接口支持链式操作,例如增加一个字符串
        me.printMoney(moneyFormat.andThen(s -> "人民币 " + s));
    }
}

运行以上例子,控制台输出如下:

我的存款: 人民币 99,999,999

若在这个例子中不使用Function接口的话,则需要自行定义一个函数接口,并且不支持链式操作,如下示例:

import java.text.DecimalFormat;

// 自定义一个函数接口
@FunctionalInterface
interface IMoneyFormat {
    String format(int i);
}

class MyMoney {
    private final int money;

    public MyMoney(int money) {
        this.money = money;
    }

    public void printMoney(IMoneyFormat moneyFormat) {
        System.out.println("我的存款: " + moneyFormat.format(this.money));
    }
}

public class MoneyDemo {
    public static void main(String[] args) {
        MyMoney me = new MyMoney(99999999);

        IMoneyFormat moneyFormat = i -> new DecimalFormat("#,###").format(i);
        me.printMoney(moneyFormat);
    }
}

然后我们再来看看Predicate接口和Consumer接口的使用,如下示例:

public static void main(String[] args) {
    // 断言函数接口
    Predicate<Integer> predicate = i -> i > 0;
    System.out.println(predicate.test(-9));

    // 消费函数接口
    Consumer<String> consumer = System.out::println;
    consumer.accept("这是输入的数据");
}

运行以上例子,控制台输出如下:

false

这是输入的数据

这些接口一般有对基本类型的封装,使用特定类型的接口就不需要去指定泛型了,如下示例:

public static void main(String[] args) {
    // 断言函数接口
    IntPredicate intPredicate = i -> i > 0;
    System.out.println(intPredicate.test(-9));

    // 消费函数接口
    IntConsumer intConsumer = (value) -> System.out.println("输入的数据是:" + value);
    intConsumer.accept(123);
}

运行以上代码,控制台输出如下:

false

输入的数据是:123

有了以上接口示例的铺垫,我们应该对函数接口的使用有了一个初步的了解,接下来我们演示剩下的函数接口使用方式:

public static void main(String[] args) {
    // 提供数据接口
    Supplier<Integer> supplier = () -> 10 + 1;
    System.out.println("提供的数据是:" + supplier.get());

    // 一元函数接口
    UnaryOperator<Integer> unaryOperator = i -> i * 2;
    System.out.println("计算结果为:" + unaryOperator.apply(10));

    // 二元函数接口
    BinaryOperator<Integer> binaryOperator = (a, b) -> a * b;
    System.out.println("计算结果为:" + binaryOperator.apply(10, 10));
}

运行以上代码,控制台输出如下:

提供的数据是:11

计算结果为:20

计算结果为:100

而BiFunction接口就是比Function接口多了一个输入而已,如下示例:

class MyMoney {
    private final int money;
    private final String name;

    public MyMoney(int money, String name) {
        this.money = money;
        this.name = name;
    }

    public void printMoney(BiFunction<Integer, String, String> moneyFormat) {
        System.out.println(moneyFormat.apply(this.money, this.name));
    }
}

public class MoneyDemo {
    public static void main(String[] args) {
        MyMoney me = new MyMoney(99999999, "小明");

        BiFunction<Integer, String, String> moneyFormat = (i, name) -> name + "的存款: " + new DecimalFormat("#,###").format(i);
        me.printMoney(moneyFormat);
    }
}

运行以上代码,控制台输出如下:

小明的存款: 99,999,999

方法引用

在学习了lambda表达式之后,我们通常会使用lambda表达式来创建匿名方法。但有的时候我们仅仅是需要调用一个已存在的方法。如下示例:

Arrays.sort(stringsArray, (s1, s2) -> s1.compareToIgnoreCase(s2));

在jdk8中,我们可以通过一个新特性来简写这段lambda表达式。如下示例:

Arrays.sort(stringsArray, String::compareToIgnoreCase);

这种特性就叫做方法引用(Method Reference)。方法引用的标准形式是:类名::方法名。(注意:只需要写方法名,不需要写括号)。

目前方法引用共有以下四种形式:

类型 示例 代码示例 对应的Lambda表达式
引用静态方法 ContainingClass::staticMethodName String::valueOf (s) -> String.valueOf(s)
引用某个对象的实例方法 containingObject::instanceMethodName x::toString() () -> this.toString()
引用某个类型的任意对象的实例方法 ContainingType::methodName String::toString (s) -> s.toString
引用构造方法 ClassName::new String::new () -> new String()

下面我们用一个简单的例子来演示一下方法引用的几种写法。首先定义一个实体类:

public class Dog {
    private String name = "二哈";
    private int food = 10;

    public Dog() {
    }

    public Dog(String name) {
        this.name = name;
    }

    public static void bark(Dog dog) {
        System.out.println(dog + "叫了");
    }

    public int eat(int num) {
        System.out.println("吃了" + num + "斤");
        this.food -= num;
        return this.food;
    }

    @Override
    public String toString() {
        return this.name;
    }
}

通过方法引用来调用该实体类中的方法,代码如下:

package org.zero01.example.demo;

import java.util.function.*;

/**
 * @ProjectName demo
 * @Author: zeroJun
 * @Date: 2018/9/21 13:09
 * @Description: 方法引用demo
 */
public class MethodRefrenceDemo {

    public static void main(String[] args) {
        // 方法引用,调用打印方法
        Consumer<String> consumer = System.out::println;
        consumer.accept("接收的数据");

        // 静态方法引用,通过类名即可调用
        Consumer<Dog> consumer2 = Dog::bark;
        consumer2.accept(new Dog());

        // 实例方法引用,通过对象实例进行引用
        Dog dog = new Dog();
        IntUnaryOperator function = dog::eat;
        System.out.println("还剩下" + function.applyAsInt(2) + "斤");

        // 另一种通过实例方法引用的方式,之所以可以这么干是因为JDK默认会把当前实例传入到非静态方法,参数名为this,参数位置为第一个,所以我们在非静态方法中才能访问this,那么就可以通过BiFunction传入实例对象进行实例方法的引用
        Dog dog2 = new Dog();
        BiFunction<Dog, Integer, Integer> biFunction = Dog::eat;
        System.out.println("还剩下" + biFunction.apply(dog2, 2) + "斤");

        // 无参构造函数的方法引用,类似于静态方法引用,只需要分析好输入输出即可
        Supplier<Dog> supplier = Dog::new;
        System.out.println("创建了新对象:" + supplier.get());

        // 有参构造函数的方法引用
        Function<String, Dog> function2 = Dog::new;
        System.out.println("创建了新对象:" + function2.apply("旺财"));
    }
}

最后需要说一句的就是能够使用方法引用的地方就尽量不要使用lambda表达式,这样就不会多生成一个类似 lambda$0这样的函数,能够减少一些资源的开销。

类型推断

通过以上的例子,我们知道之所以能够使用Lambda表达式的依据是必须有相应的函数接口。这一点跟Java是强类型语言吻合,也就是说你并不能在代码的任何地方任性的写Lambda表达式。实际上Lambda的类型就是对应函数接口的类型。Lambda表达式另一个依据是类型推断机制,在上下文信息足够的情况下,编译器可以推断出参数表的类型,而不需要显式指名。
所以说 Lambda 表达式的类型是从 Lambda 的上下文推断出来的,上下文中 Lambda 表达式需要的类型称为目标类型,如下图所示:

接下来我们使用一个简单的例子,演示一下 Lambda 表达式的几种类型推断,首先定义一个简单的函数接口:

@FunctionalInterface
interface IMath {
    int add(int x, int y);
}

示例代码如下:

public class TypeDemo {

    public static void main(String[] args) {
        // 1.通过变量类型定义
        IMath iMath = (x, y) -> x + y;

        // 2.数组构建的方式
        IMath[] iMaths = {(x, y) -> x + y};

        // 3.强转类型的方式
        Object object = (IMath) (x, y) -> x + y;

        // 4.通过方法返回值确定类型
        IMath result = createIMathObj();

        // 5.通过方法参数确定类型
        test((x, y) -> x + y);

    }

    public static IMath createIMathObj() {
        return (x, y) -> x + y;
    }

    public static void test(IMath iMath){
        return;
    }
}

变量引用

Lambda表达式类似于实现了指定接口的内部类或者说匿名类,所以在Lambda表达式中引用变量和我们在匿名类中引用变量的规则是一样的。如下示例:

public static void main(String[] args) {
    String str = "当前的系统时间戳是: ";
    Consumer<Long> consumer = s -> System.out.println(str + s);
    consumer.accept(System.currentTimeMillis());
}

值得一提的是,在JDK1.8之前我们一般会将匿名类里访问的外部变量设置为final,而在JDK1.8里默认会将这个匿名类里访问的外部变量给设置为final。例如我现在改变str变量的值,ide就会提示错误:

至于为什么要将变量设置final,这是因为在Java里没有引用传递,变量都是值传递的。不将变量设置为final的话,如果外部变量的引用被改变了,那么最终得出来的结果就会是错误的。

下面用一组图片简单演示一下值传递与引用传递的区别。以列表为例,当只是值传递时,匿名类里对外部变量的引用是一个值对象:

若此时list变量指向了另一个对象,那么匿名类里引用的还是之前那个值对象,所以我们才需要将其设置为final防止外部变量引用改变:

而如果是引用传递的话,匿名类里对外部变量的引用就不是值对象了,而是指针指向这个外部变量:

所以就算list变量指向了另一个对象,匿名类里的引用也会随着外部变量的引用改变而改变:

级联表达式和柯里化

在函数式编程中,函数既可以接收也可以返回其他函数。函数不再像传统的面向对象编程中一样,只是一个对象的工厂或生成器,它也能够创建和返回另一个函数。返回函数的函数可以变成级联 lambda 表达式,特别值得注意的是代码非常简短。尽管此语法初看起来可能非常陌生,但它有自己的用途。

级联表达式就是多个lambda表达式的组合,这里涉及到一个高阶函数的概念,所谓高阶函数就是一个可以返回函数的函数,如下示例:

// 实现了 x + y 的级联表达式
Function<Integer, Function<Integer, Integer>> function1 = x -> y -> x + y;
System.out.println("计算结果为: " + function1.apply(2).apply(3));  // 计算结果为: 5

这里的 y -> x + y 是作为一个函数返回给上一级表达式,所以第一级表达式的输出是 y -> x + y这个函数,如果使用括号括起来可能会好理解一些:

x -> (y -> x + y)

级联表达式可以实现函数柯里化,简单来说柯里化就是把本来多个参数的函数转换为只有一个参数的函数,如下示例:

Function<Integer, Function<Integer, Function<Integer, Integer>>> function2 = x -> y -> z -> x + y + z;
System.out.println("计算结果为: " + function2.apply(1).apply(2).apply(3));  // 计算结果为: 6

如果大家想学习以上路线内容,在此我向大家推荐一个架构学习交流群。交流学习群号874811168 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

函数柯里化的目的是将函数标准化,函数可灵活组合,方便统一处理等,例如我可以在循环里只需要调用同一个方法,而不需要调用另外的方法就能实现一个数组内元素的求和计算,代码如下:

public static void main(String[] args) {
    Function<Integer, Function<Integer, Function<Integer, Integer>>> f3 = x -> y -> z -> x + y + z;
    int[] nums = {1, 2, 3};
    for (int num : nums) {
        if (f3 instanceof Function) {
            Object obj = f3.apply(num);
            if (obj instanceof Function) {
                f3 = (Function) obj;
            } else {
                System.out.println("调用结束, 结果为: " + obj);  // 调用结束, 结果为: 6
            }
        }
    }
}

级联表达式和柯里化一般在实际开发中并不是很常见,所以对其概念稍有理解即可,这里只是简单带过。

以上就是详解Java函数式编程和lambda表达式的详细内容,更多关于Java函数式编程和lambda表达式的资料请关注我们其它相关文章!

(0)

相关推荐

  • 详解Java8中的lambda表达式、::符号和Optional类

    Java8中的lambda表达式.::符号和Optional类 0. 函数式编程 函数式编程(Functional Programming)属于编程范式(Programming Paradigm)中的用语,此外还有命令式编程(Imperative Programing)等,有兴趣的同学可以自行了解,我们这里大概解释一下函数式编程,在函数式编程中,输入一旦确定了,输出都确定了,函数调用的结果只依赖于传入的输入变量和内部逻辑,不依赖于外部,这样的写出的函数没有副作用.举个例子: public cla

  • Java lambda list转换map时,把多个参数拼接作为key操作

    我就废话不多说了,大家还是直接看代码吧~ Map<String, Parts> partsMap = synList.stream().collect(Collectors.toMap(k -> k.getOe()+k.getOeId()+k.getPartGroupId()+k.getStdPartId()+k.getBrandCode(), part -> part)); 补充知识:Java8 Collectors.toMap的两个大坑 Collectors.toMap()方法

  • Java8新特性之Lambda表达式的使用

    1. lambda表达式介绍 lambda表达式是Java8提供的新特性之一,也可以称之为闭包:它支持Java能够进行简单的函数式编程,也就是说可以把一个匿名函数作为一个方法的参数进行传递:其格式分为三部分,第一部分为入参列表,第二部由->固定组成,第三部分为方法体: public class LambdaTest { public static void main(String[] args) { // 使用lambda表达式创建线程 Thread thread = new Thread(()

  • java8 多个list对象用lambda求差集操作

    业务场景:调用同步接口获取当前全部有效账户,数据库已存在部分账户信息,因此需要筛选同步接口中已存在本地的帐户. 调用接口获取的数据集合 List<AccountVo> list = response.getData().getItems(); 本地查询出来的账户集合 List<Account> towList = accountRepository.findAll(); 筛选差集代码 List<AccountVo> distinctByUniqueList = list

  • Java8 lambda表达式2种常用方法代码解析

    与python不一样,python lambda是定义匿名函数,而在java8中lambda是匿名内部类 例1.用lambda表达式实现Runnable 我开始使用Java 8时,首先做的就是使用lambda表达式替换匿名类,而实现Runnable接口是匿名类的最好示例.看一下Java 8之前的runnable实现方法,需要4行代码,而使用lambda表达式只需要一行代码.我们在这里做了什么呢?那就是用() -> {}代码块替代了整个匿名类. // Java 8之前: new Thread(ne

  • Java lambda 循环累加求和代码

    java 8 stream 提供了下面几种类型的求和 Stream::mapToInt Stream::mapToDouble Stream::mapToLong public void test() { List<Person> people = new ArrayList<>(); people.add(new Person("zhangsan",20)); people.add(new Person("lisi", 26)); peop

  • 详解Java8中的Lambda表达式

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

  • Java8的Lambda表达式你真的会吗

    理解Lambda Lambda表达式可以是一段可以传递的代码,它的核心思想是将面向对象中的传递数据变成传递行为,也就是行为参数化,将不同的行为作为参数传入方法. 随着函数式编程思想的引进,Lambda表达式让可以用更加简洁流畅的代码来代替之前冗余的Java代码. 口说无凭,直接上个例子吧.在Java8之前,关于线程代码是这样的: class Task implements Runnable{ @Override public void run() { System.out.println("Ja

  • java8 forEach结合Lambda表达式遍历 List操作

    我就废话不多说了,大家还是直接看代码吧~ @Test void testJava8ForeachMap() { Map<String, Integer> items = new HashMap<>(); items.put("A", 10); items.put("B", 20); items.put("C", 30); items.put("D", 40); items.put("E&quo

  • Java8 Lambda表达式模板方法实现解析

    Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容.在这个教程当中,我们将学习Java的注解,如何定制注解,注解的使用以及如何通过反射解析注解. Java1.5引入了注解,当前许多java框架中大量使用注解,如Hibernate.Jersey.Spring.注解作为程序的元数据嵌入到程序当中.注解可以被一些解析工具或者是编译工具进行解析.我们也可以声明注解在编译过程或执行时产生作用. 在使用注解之前,程序源数据只是通过java注释和javadoc,但是注解提供的功能要远远超

  • java lambda循环_使用Java 8 Lambda简化嵌套循环操作

    java lambda循环 对于每个经常需要在Java 8(或更高版本)中使用多维数组的人来说,这只是一个快速技巧. 在这种情况下,您可能经常会以类似于以下代码的结尾: float[][] values = ... for (int i = 0; i < values.length; i++) { for (int k = 0; k < values[i].length; k++) { float value = values[i][k]; // do something with i, k

  • java中lambda表达式的分析与具体用法

    Lamda表达式 λ 希腊字母表中排序第十一位字母,英语名称为Lambda 避免匿名内部类定义过多 其实质属于函数式 编程的概念 (params)->expression[表达式] (params)->statement[语句] (params)->{statements} (a-> System.out.print("i like lambda–>"+a)); new Thread (()->System.out.println("多线程

  • Java8语法糖之Lambda表达式的深入讲解

    一.Lambda表达式简介 Lambda表达式,是Java8的一个新特性,也是Java8中最值得学习的新特性之一.(另一个新特性是流式编程.) Lambda表达式,从本质上讲是一个匿名方法.可以使用这个匿名方法,实现接口中的方法. 功能:通常使用Lambda表达式,是为了简化接口实现的.关于接口实现可以有多种方式实现,例如:①设计接口的实现类.②使用匿名内部类.但是③使用lambda表达式,比这两种方式都简单. 要求:lambda表达式,只能实现函数式接口:即一个接口中,要求实现类必须实现的抽象

  • Java8如何使用Lambda表达式简化代码详解

    系统环境: Java JDK 版本:1.8 参考地址: Java 8 Lambda 表达式 Jdk 8 新特性 04 方法引用与构造器引用 Java 8 新特性:Lambda 表达式之方法引用 一.Lambda 表达式简介 1.什么是 Lambda 表达式 Lambda 表达式是在 JDK 8 中引入的一个新特性,可用于取代大部分的匿名内部类.使用 Lambda 表达式可以完成用少量的代码实现复杂的功能,极大的简化代码代码量和代码结构.同时,JDK 中也增加了大量的内置函数式接口供我们使用,使得

  • Java8新特性:Lambda表达式之方法引用详解

    1.方法引用简述 方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法.方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文.计算时,方法引用会创建函数式接口的一个实例. 当Lambda表达式中只是执行一个方法调用时,不用Lambda表达式,直接通过方法引用的形式可读性更高一些.方法引用是一种更简洁易懂的Lambda表达式. Lambda表达式全文详情地址:http://blog.csdn.net/sun_promise/article/details/

  • java lambda 表达式中的双冒号的用法说明 ::

    双冒号运算就是Java中的[方法引用],[方法引用]的格式是 类名::方法名 注意是方法名哦,后面没有括号"()"哒.为啥不要括号,因为这样的是式子并不代表一定会调用这个方法.这种式子一般是用作Lambda表达式,Lambda有所谓懒加载嘛,不要括号就是说,看情况调用方法. 例如 表达式: person -> person.getAge(); 可以替换成 Person::getAge 表达式 () -> new HashMap<>(); 可以替换成 HashMa

  • java 8 lambda表达式中的异常处理操作

    简介 java 8中引入了lambda表达式,lambda表达式可以让我们的代码更加简介,业务逻辑更加清晰,但是在lambda表达式中使用的Functional Interface并没有很好的处理异常,因为JDK提供的这些Functional Interface通常都是没有抛出异常的,这意味着需要我们自己手动来处理异常. 因为异常分为Unchecked Exception和checked Exception,我们分别来讨论. 处理Unchecked Exception Unchecked exc

  • 使用Java 8 Lambda表达式将实体映射到DTO的操作

    当我们需要将DTO转换为实体(Hibernate实体等)并向后转换时,我们都会面临混乱的开销代码. 在我的示例中,我将用Java 8演示代码如何变得越来越短. 让我们创建目标DTO: public class ActiveUserListDTO { public ActiveUserListDTO() { } public ActiveUserListDTO(UserEntity userEntity) { this.username = userEntity.getUsername(); ..

随机推荐