如何使用lambda表达式提升开发效率

简介: 如何使用lambda表达式提升开发效率

再也无需前思后想,一切岂非已然过往。——《且听风吟》

高手问答第 305 期 —— 如何使用 lambda 表达式提升开发效率?

Java8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。

Lambda表达式

https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

简单来说:就是把我们的函数(方法)作为参数传递、调用等

例子:自定义函数式接口(用jdk自带的函数式接口也可以)

import java.io.Serializable;
/**
 * 可序列化的Functional
 *
 * @author VampireAchao
 */
@FunctionalInterface
public interface Func<T, R> extends Serializable {
    /**
     * 调用
     *
     * @param t 参数
     * @return 返回值
     */
    R apply(T t);
}

我们定义一个类可以去实现该接口

/**
 * 可序列化的函数式接口实现类
 *
 * @author VampireAchao
 */
public class FuncImpl implements Func<Object, String> {
    /**
     * 调用
     *
     * @param o 参数
     * @return 返回值
     */
    @Override
    public String apply(Object o) {
        return o.toString();
    }
}

到此为止,都非常的简单

这里就有个问题:假设我有很多的地方需要不同的类去实现Func,我就得每次都去写这么一个类,然后实现该接口并重写方法

这样很麻烦!因此我们使用匿名内部类

Func<String, Integer> func = new Func<String, Integer>() {
    /**
     * 调用
     *
     * @param s 参数
     * @return 返回值
     */
    @Override
    public Integer apply(String s) {
        return s.hashCode();
    }
};

我们可以看到,使用了匿名内部类后不用每次去新建这个类了,只需要在调用的地方,new一下接口,创建一个匿名内部类即可

但这样还有个问题,我们每次都要写这么一大几行代码,特别麻烦

由此而生,我们有了lambda这种简写的形式

https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html#syntax

Func<String, String> func1 = (String s) -> {
    return s.toUpperCase();
};

如果只有一行,我们可以省略掉中括号以及return

Func<String, String> func2 = (String s) -> s.toUpperCase();

我们可以省略掉后边的参数类型

Func<String, String> func3 = s -> s.toUpperCase();

如果我们满足特定的形式,我们还可以使用方法引用(双冒号)的形式缩写

Func<String, String> func4 = String::toUpperCase;

这里除了我们的参数->返回值写法:s->s.toUpperCase(),还有很多种

例如无参数带返回值写法()->"yes"、无参无返回值写法()->{}等等

而方法引用这种写法有如下几种:

https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

package org.dromara.streamquery;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
/**
 * 语法糖——方法引用
 *
 * @author VampireAchao
 */
public class MethodReferences {
    public static Object staticSupplier() {
        return "whatever";
    }
    public Object instanceSupplier() {
        return "whatever";
    }
    public Object anonymousInstanceFunction() {
        return "whatever";
    }
    public static void main(String[] args) {
        // 引用构造函数
        Supplier<MethodReferences> conSup = () -> new MethodReferences();
        conSup = MethodReferences::new;
        // 数组构造函数引用
        IntFunction<int[]> intFunction = value -> new int[value];
        // intFunc == new int[20];
        int[] intFuncResult = intFunction.apply(20);
        // 引用静态方法
        Supplier<Object> statSup = () -> staticSupplier();
        statSup = MethodReferences::staticSupplier;
        Object statSupResult = statSup.get();
        // 引用特定对象的实例方法
        Supplier<Object> instSup = new MethodReferences()::instanceSupplier;
        instSup = new MethodReferences()::instanceSupplier;
        Object instSupResult = instSup.get();
        // 引用特定类型的任意对象的实例方法
        Function<MethodReferences, Object> anonInstFunc = streamDemo -> streamDemo.anonymousInstanceFunction();
        anonInstFunc = MethodReferences::anonymousInstanceFunction;
    }
}

顺便放几个常用的,jdk自带的函数式接口写法

package org.dromara.streamquery;
import java.math.BigDecimal;
import java.util.function.*;
/**
 * 常用的几个函数式接口写法
 *
 * @author VampireAchao
 */
class Usual {
    public static Consumer<Object> consumer() {
        // 有参数无返回值
        return o -> {
        };
    }
    public static Function<Integer, Object> function() {
        // 有参数有返回值
        return o -> o;
    }
    public static Predicate<Object> predicate() {
        // 有参数,返回值为boolean
        return o -> true;
    }
    public static Supplier<Object> supplier() {
        // 无参数有返回值
        return Object::new;
    }
    public static BiConsumer<String, Integer> biConsumer() {
        // 俩参数无返回值
        return (q, o) -> {
        };
    }
    public static BiFunction<Integer, Long, BigDecimal> biFunction() {
        // 俩参数,有返回值
        return (q, o) -> new BigDecimal(q).add(BigDecimal.valueOf(o));
    }
    public static UnaryOperator<Object> unaryOperator() {
        // 一个参数,返回值类型和参数一样
        return q -> q;
    }
    public static BinaryOperator<Object> binaryOperator() {
        // 俩参数和返回值类型保持一致
        return (a, o) -> a;
    }
}

Stream

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。方法全是传入函数作为参数,来达到我们的目的。

java.util.stream (Java Platform SE 8 )

// 声明式编程是告诉计算机需要计算“什么”而不是“如何”去计算
// 现在,我想要一个List,包含3个数字6
List<Integer> sixSixSix =
        // 我想要:
        Stream
                // 数字6
                .generate(() -> 6)
                // 3个
                .limit(3)
                // 最后收集起来转为List
                .collect(Collectors.toList());
sixSixSix.forEach(System.out::print);

Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。

// 就像sql里的排序、截取
// 我要把传入的list逆序,然后从第五个(元素下标为4)开始取值,取4条
abc = abc.stream()
        // 排序(按照自然顺序的逆序)
        .sorted(Comparator.reverseOrder())
        // 从下标为4开始取值
        .skip(4)
        // 取4条
        .limit(4)
        // 最后收集起来转为List
        .collect(Collectors.toList());
System.out.println("我要把传入的list逆序,然后从第五个(元素下标为4)开始取值,取4条");
abc.forEach(System.out::print);
System.out.println();

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

/**
 * 老办法实现一个list,存储3个6
 *
 * @return [6, 6, 6]
 */
private static List<Integer> oldSix() {
    // 老办法
    List<Integer> sixSixSix = new ArrayList<>(3);
    sixSixSix.add(6);
    sixSixSix.add(6);
    sixSixSix.add(6);
    System.out.println("老办法实现一个list,存储3个6");
    for (Integer integer : sixSixSix) {
        System.out.print(integer);
    }
    System.out.println();
    return sixSixSix;
}
/**
 * 新方法实现一个list,存储3个6
 *
 * @return [6, 6, 6]
 */
private static List<Integer> newSix() {
    List<Integer> sixSixSix = Stream.generate(() -> 6).limit(3).collect(Collectors.toList());
    System.out.println("新方法实现一个list,存储3个6");
    sixSixSix.forEach(System.out::print);
    System.out.println();
    return sixSixSix;
}

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。

// 管道中传输,节点中处理
int pipe = abc.stream()
        // 筛选
        .filter(i -> i > 'G')
        // 排序
        .sorted(Comparator.reverseOrder())
        .mapToInt(Object::hashCode)
        // 聚合
        .sum();
System.out.println("将26个字母组成的集合过滤出大于'G'的,逆序,再获取hashCode值,进行求和");
System.out.println(pipe);

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

// 将26个大写字母Character集合转换为String然后转换为小写字符
List<String> terminalOperation = abc.stream()
        // 中间操作(intermediate operation)
        .map(String::valueOf).map(String::toLowerCase)
        // 最终操作(terminal operation)
        .collect(Collectors.toList());
System.out.println("26个大写字母Character集合,转换成String然后转换为小写字符,收集起来");
terminalOperation.forEach(System.out::print);
System.out.println();


相关文章
|
6月前
|
开发框架 .NET 编译器
C# 10.0中Lambda表达式的改进:更简洁、更灵活的代码编写体验
【1月更文挑战第21天】随着C#语言的不断发展,Lambda表达式作为一种简洁、高效的函数式编程工具,在C# 10.0中迎来了重要的改进。本文将详细探讨C# 10.0中Lambda表达式的新特性,包括参数类型的推断增强、自然类型的Lambda参数以及Lambda表达式的属性改进等。这些改进不仅简化了Lambda表达式的编写过程,还提升了代码的可读性和灵活性,为开发者带来了更优质的编程体验。
|
6月前
|
存储 C++
【C++】可变参数模板使用总结(简洁易懂,详细,含代码演示)
【C++】可变参数模板使用总结(简洁易懂,详细,含代码演示)
|
5月前
|
Serverless 开发者 Python
Python函数式编程:让你的代码更简洁、更高效!
【6月更文挑战第12天】Python函数式编程引入了数学函数概念,强调无副作用和不可变数据。特点包括高阶函数、Lambda表达式、map、filter和reduce。示例展示了如何使用map进行平方运算,filter筛选条件元素,reduce计算元素总和,体现其简洁高效。虽然不适用于所有情况,但函数式编程能提升代码可读性和可维护性。
32 3
|
6月前
|
缓存 Python
Python 中的装饰器:提升代码可读性和灵活性的利器
装饰器是 Python 中一种强大的工具,它能够在不修改原有代码的情况下,增加新的功能和行为。本文将深入探讨装饰器的原理、用法以及在实际开发中的应用场景,帮助读者更好地理解并运用装饰器来提升代码的可读性和灵活性。
|
6月前
|
缓存 开发者 Python
深入探讨Python中的装饰器:提升代码可读性与灵活性
在Python编程中,装饰器是一种强大的工具,可以在不修改原始函数代码的情况下,对其行为进行扩展或修改。本文将深入探讨装饰器的原理和用法,以及如何利用装饰器提升代码的可读性和灵活性,为Python开发者提供更加优雅和高效的编程方式。
|
6月前
|
Java 开发者
Java中的Lambda表达式:简洁、高效的编程利器
Java语言的发展历程中,Lambda表达式作为一种函数式编程的利器,为开发者带来了更加简洁高效的编程方式。本文将介绍Lambda表达式的基本语法、特性及其在Java编程中的应用,以及如何充分利用Lambda表达式提升代码的可读性和性能。
53 1
|
6月前
|
存储 并行计算 算法
Lambda表达式与函数式工具
【5月更文挑战第10天】探索Python的函数式编程:Lambda表达式用于快速定义匿名函数,如求平方;函数式工具如`map()`、`filter()`、`reduce()`简化代码。通过实例展示在数据处理、并行计算中的应用,如匿名函数与`map()`结合实现列表元素运算,`filter()`筛选条件,`reduce()`做累积计算。不可变性和纯函数提升代码可靠性,结合面向对象编程实现代码复用。利用`functools`、`itertools`等模块及第三方库如`toolz`增强函数式编程能力。函数式编程适用于数据处理、并行计算,优点在于清晰、高效和易于维护。
37 0
|
6月前
|
编译器 程序员 C++
C++从入门到精通:3.1模板编程——提高代码的复用性和灵活性
C++从入门到精通:3.1模板编程——提高代码的复用性和灵活性
|
6月前
|
Java 程序员 C#
Lambda表达式:简洁而强大的函数式编程利器
【4月更文挑战第3天】本文探讨了Lambda表达式的基础和在编程中的应用,包括简化代码和提高可读性。Lambda表达式是匿名函数,用于简单的功能,如示例中的平方运算和列表筛选。通过`map`、`filter`等函数,Lambda表达式能有效处理列表操作。文中还展示了Lambda表达式的高级用法,如闭包特性、异常处理及与高阶函数的结合。通过实例,读者可以学习如何利用Lambda表达式实现更高效、简洁的编程。
61 0
|
6月前
|
Java 开发者
Java中的Lambda表达式:简洁、灵活的编程利器
在现代软件开发中,编写简洁、高效的代码是至关重要的。Java中的Lambda表达式为开发者提供了一种简洁、灵活的编程方式,使得代码更具可读性和可维护性。本文将探讨Lambda表达式的基本概念、语法结构以及在实际项目中的应用,以帮助读者更好地理解和运用这一强大的编程工具。
24 0