Java函数式编程和Lambda表达式

简介: Java函数式编程和Lambda表达式

文章目录



什么是函数式编程


相信大家都使用过面向对象的编程语言,面向对象编程是对数据进行抽象,而函数式编程是对行为进行抽象。函数式编程让程序员能够写出更加容易阅读的代码。


那什么时候函数式编程呢?


函数式编程是一种编程的方法论,主要是将行为编写成一个个的函数。


什么是函数?


函数就是对输入的值进行处理,返回另外的值。


Lambda表达式


在Java 8 中引入的Labmda表达式是函数式编程的一种实现。


什么是Lambda表达式呢?我们举个例子


下面的代码如果使用Java 7 的话应该这样写:


//sort using java 7
   private void sortUsingJava7(List<String> names){   
      Collections.sort(names, new Comparator<String>() {
         @Override
         public int compare(String s1, String s2) {
            return s1.compareTo(s2);
         }
      });
   }


代码里面需要实现一个匿名类,看起来是不是很复杂? 下面我们用java 8 的lambda表达式将其改写:


//sort using java 8
   private void sortUsingJava8(List<String> names){
      Collections.sort(names, (s1, s2) -> s1.compareTo(s2));
   }
}


其中(s1, s2) -> s1.compareTo(s2) 是Comparator的compare方法的实现。


这里我们使用了Lambda表达式替换了Comparator的匿名类。为什么可以这样做?什么样的匿名类才能被Lambda表达式替换呢? 这里我们引入一个概念,叫做函数式接口。

Lambda表达式需要一个函数式接口作为其对应类型,而它的方法体就是函数接口的实现。每一个该接口类型的Lambda表达式都会被匹配到该接口的抽象方法。


@FunctionalInterface函数式接口


所谓函数是接口是指包括如下特征的接口:


  • 接口有且仅有一个抽象方法
  • 接口允许定义静态方法
  • 接口允许定义默认方法
  • 接口允许java.lang.Object中的public方法


我们看一下上面的Comparator的实现:


@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj);
    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }
    default Comparator<T> thenComparing(Comparator<? super T> other) {
        Objects.requireNonNull(other);
        return (Comparator<T> & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return (res != 0) ? res : other.compare(c1, c2);
        };
    }
    default <U> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        return thenComparing(comparing(keyExtractor, keyComparator));
    }
    default <U extends Comparable<? super U>> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        return thenComparing(comparing(keyExtractor));
    }
    default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
        return thenComparing(comparingInt(keyExtractor));
    }
    default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
        return thenComparing(comparingLong(keyExtractor));
    }
    default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
        return thenComparing(comparingDouble(keyExtractor));
    }
    public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
        return Collections.reverseOrder();
    }
    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
        return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
    }
    public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(true, comparator);
    }
    public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
...
    }
    public static <T, U> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
...
    }
    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
...
    }
    public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
...
    }
    public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
...
    }
    public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
...
    }
}


我们可以看到Comparator接口里面有static方法,有default方法,有一个来自Object的boolean equals(Object obj);有一个需要实现的抽象方法int compare(T o1, T o2)

default方法是java 8添加的最新的关键词,表示实现这个接口的类如果不自己实现这个方法,那么就用接口自己的吧,其作用主要是向下兼容。


JDK自带了一些有用的函数式接口:


  • java.lang.Runnable,
  • java.awt.event.ActionListener,
  • java.util.Comparator,
  • java.util.concurrent.Callable
  • java.util.function包下的接口,如Consumer、Predicate、Supplier等


Lambda表达式的格式


一般来说Lambda的表达式是这样的格式:


parameter -> expression body


查看下面的代码:


public static void main(String[] args) {
        Runnable noArguments = () -> System.out.println("Hello World");
        ActionListener oneArgument = event -> System.out.println("button clicked");
        Runnable multiStatement = () -> {
            System.out.print("Hello");
            System.out.println(" World");
        };
        BinaryOperator<Long> add = (x, y) -> x + y;
        BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;
    }


上面是我们经常在Lambda中使用的几种格式。


  • 不包含参数的格式


Runnable noArguments = () -> System.out.println(“Hello World”);


  • 只包含一个参数,并可以省略括号


ActionListener oneArgument = event -> System.out.println(“button clicked”);


  • Lambda的主体是一段代码块


Runnable multiStatement = () -> {
System.out.print(“Hello”);
System.out.println(" World");
};


  • 多个参数


BinaryOperator add = (x, y) -> x + y;


  • 显式指定参数的类型


BinaryOperator addExplicit = (Long x, Long y) -> x + y;


所有Lambda 表达式中的参数类型都是由编译器推断得出的。如果编译器无法推断你的参数类型,则需要手动指定。


方法引用


在第一个例子中我们讲到了如下的Lambda表达式:


Collections.sort(names, (s1, s2) -> s1.compareTo(s2));


其中(s1, s2) -> s1.compareTo(s2) 表示的是两个字符串的比较,调用了String类的compareTo方法。为了更简洁的表示业务逻辑,可以是用方法引用来替换Lambda表达式。


Collections.sort(names, String::compareTo);


这样比原来的代码更短,而且更加简洁。

有三种方法可以被引用:


  • 静态方法
  • 实例方法
  • 使用new的构造函数方法如:(TreeSet::new)
相关文章
|
20天前
|
安全 Java API
Java中的Lambda表达式:简洁与功能的结合
Java中的Lambda表达式:简洁与功能的结合
170 91
|
20天前
|
安全 Java
Java中的Switch表达式:更简洁的多路分支
Java中的Switch表达式:更简洁的多路分支
189 91
|
2月前
|
自然语言处理 Java Apache
在Java中将String字符串转换为算术表达式并计算
具体的实现逻辑需要填写在 `Tokenizer`和 `ExpressionParser`类中,这里只提供了大概的框架。在实际实现时 `Tokenizer`应该提供分词逻辑,把输入的字符串转换成Token序列。而 `ExpressionParser`应当通过递归下降的方式依次解析
181 14
|
1月前
|
Java 编译器
Java 17 Switch表达式:更简洁、更强大的流程控制
Java 17 Switch表达式:更简洁、更强大的流程控制
|
2月前
|
设计模式 数据采集 Java
Java正则表达式的基础知识,进阶至熟练掌握。
通过大量的练习来熟悉它们的识别模式、如何设计模式来解决实际问题,才能够逐步达到熟练掌握。更多的是通过实践、编写代码和解决真实问题来完善技能。在这方面,没有快速的捷径,唯有刻意练习和长时间的代码实践。
57 0
|
3月前
|
SQL JSON 安全
Java 8 + 中 Lambda 表达式与 Stream API 的应用解析
摘要:本文介绍了Java 8+核心新特性,包括Lambda表达式与Stream API的集合操作(如过滤统计)、函数式接口的自定义实现、Optional类的空值安全处理、接口默认方法与静态方法的扩展能力,以及Java 9模块化系统的组件管理。每个特性均配有典型应用场景和代码示例,如使用Stream统计字符串长度、Optional处理Map取值、模块化项目的依赖声明等,帮助开发者掌握现代Java的高效编程范式。(150字)
61 1
|
5月前
|
Java 编译器 API
Java Lambda 表达式:以 Foo 接口为例深入解析
本文深入解析了 Java 8 中 Lambda 表达式的用法及其背后的函数式接口原理,以 `Foo` 接口为例,展示了如何通过简洁的 Lambda 表达式替代传统匿名类实现。文章从 Lambda 基本语法、函数式接口定义到实际应用层层递进,并探讨默认方法与静态方法的扩展性,最后总结常见误区与关键点,助你高效优化代码!
113 0
|
9月前
|
Java API 开发者
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。
|
10月前
|
Java API 数据处理
探索Java中的Lambda表达式与Stream API
【10月更文挑战第22天】 在Java编程中,Lambda表达式和Stream API是两个强大的功能,它们极大地简化了代码的编写和提高了开发效率。本文将深入探讨这两个概念的基本用法、优势以及在实际项目中的应用案例,帮助读者更好地理解和运用这些现代Java特性。

热门文章

最新文章