Java基础深化和提高 ---- 函数式编程 Lambda

简介: Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内 部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作 中,可以极大地优化代码结构。

Lambda表达式介绍

Lambda简介

2345_image_file_copy_1.jpg

Lambda 表达式是 JDK8 的一个新特性,可以取代大部分的匿名内 部类,写出更优雅的 Java 代码,尤其在集合的遍历和其他集合操作 中,可以极大地优化代码结构。

在Java语言中,可以为变量赋予一个值:

2345_image_file_copy_2.jpg

能否把一个代码块赋给一变量吗?

2345_image_file_copy_3.jpg

在Java 8之前,这个是做不到的。但是Java 8问世之后,利用 Lambda特性,就可以做到了。

甚至我们可以让语法变得更简洁

在Java 8里面,所有的Lambda的类型都是一个接口,而Lambda表 达式本身,也就是”那段代码“,需要是这个接口的实现。这是我认 为理解Lambda的一个关键所在,简而言之就是,Lambda表达式本 身就是一个接口的实现。直接这样说可能还是有点让人困扰,我们 继续看看例子。我们给上面的aBlockOfCode加上一个类型:

 

这种只有一个接口函数需要被实现的接口类型,我们叫它”函数式接 口“。为了避免后来的人在这个接口中增加接口函数导致其有多个接 口函数需要被实现,变成"非函数接口”,我们可以在这个上面加上 一个声明@FunctionalInterface, 这样别人就无法在里面添加新的接 口函数了。

Lambda作用

最直观的作用就是使得代码变得异常简洁。

接口要求

虽然使用 Lambda 表达式可以对某些接口进行简单的实现,但并不 是所有的接口都可以使用 Lambda 表达式来实现。Lambda 规定接 口中只能有一个需要被实现的方法,不是规定接口中只能有一个方 法。 jdk 8 中有另一个新特性:default, 被 default 修饰的方法会有默 认实现,不是必须被实现的方法,所以不影响 Lambda 表达式的使 用。

@FunctionalInterface注解作用

@FunctionalInterface标记在接口上,“函数式接口”是指仅仅只包含 一个抽象方法的接口。

Lambda表达式语法

语法结构

(parameters) -> expression
(parameters) ->{ statements;}

语法形式为 () -> {}: () 用来描述参数列表,如果有多个参数,参数之间用逗号隔开,如 果没有参数,留空即可; -> 读作(goes to),为 lambda运算符 ,固定写法,代表指向动作; {} 代码块,具体要做的事情,也就是方法体内容;

Lambda表达式的重要特征

可选类型声明:不需要声明参数类型,编译器可以统一识别参数 值。 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定 义圆括号。 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自 动返回值,大括号需要指定明表达式返回了一个数值。

Lambda案例

// 1. 不需要参数,返回值为 5  
() -> 5  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何
值(看起来像是返回void)  
(String s) -> System.out.print(s)

Lambda表达式入门案例

定义函数接口

/**
* 无返回值,无参数
*/
@FunctionalInterface
interface NoReturnNoParam{
    void method();
}
/**
* 无返回值,有一个参数
*/
@FunctionalInterface
interface NoReturnOneParam{
    void method(int a);
}
/**
* 无返回值,有多个参数
*/
@FunctionalInterface
interface NoReturnMultiParam{
    void method(int a,int b);
}
/**
* 有返回值,无参数
*/
@FunctionalInterface
interface ReturnNoParam{
    int method();
}
/**
* 有返回值,有一个参数
*/
@FunctionalInterface
interface ReturnOneParam{
    int method(int a);
}
/**
* 有返回值,有多个参数
*/
@FunctionalInterface
interface ReturnMultiParam{
    int method(int a,int b);
}

实现函数接口

public static void main(String[] args) {
    /**
     * 无返回值,无参数
     */
    NoReturnNoParam noReturnNoParam = ()->{
        System.out.println("NoReturnNoParam");
       };
        noReturnNoParam.method();
    /**
     * 无返回值,有一个参数
     */
    NoReturnOneParam noReturnOneParam = (int a)->{
        System.out.println("NoReturnOneParam"+a);
   };
     noReturnOneParam.method(10);
    /**
     * 无返回值,有多个参数
     */
    NoReturnMultiParam noReturnMultiParam = (int a, int b)->{
        System.out.println("NoReturnMultiParam "+a+"\t"+b);
   };
    noReturnMultiParam.method(10,20);
    /**
     * 有返回值,无参数
     */
    ReturnNoParam returnNoParam = ()->{
        System.out.print("ReturnNoParam ");
        return 10;
   };
    System.out.println(returnNoParam.method());
   /**
     * 有返回值,有一个参数
     */
    ReturnOneParam returnOneParam = (int a)->{
        System.out.print("ReturnOneParam ");
        return a;
   };
System.out.println(returnOneParam.method(10));
    /**
     * 有返回值,有多个参数
     */
    ReturnMultiParam returnMultiParam = (int a ,int b)->{
        System.out.print("ReturnMultiParam ");
        return a+b;
   };
System.out.println(returnMultiParam.method(10, 20));
}

Lambda语法简化

/**
     * 无返回值,无参数
     */
   /* NoReturnNoParam noReturnNoParam = ()->{ System.out.println("NoReturnNoParam");
    };*/
    /**
     * 简化版
     */
    NoReturnNoParam noReturnNoParam = ()-> System.out.println("NoReturnNoParam");
    noReturnNoParam.method();
    /**
     * 无返回值,有一个参数
     */
   /* NoReturnOneParam noReturnOneParam = (int a)->{
        System.out.println("NoReturnOneParam "+a);
    };*/
    /**
     * 简化版
     */
    NoReturnOneParam noReturnOneParam = a -> System.out.println("NoReturnOneParam "+a);
     noReturnOneParam.method(10);
    /**
     * 无返回值,有多个参数
     */
   /* NoReturnMultiParam noReturnMultiParam = (int a, int b)->{
        System.out.println("NoReturnMultiParam "+a+"\t"+b);
    };*/
    NoReturnMultiParam noReturnMultiParam = (a,b)-> System.out.println("NoReturnMultiParam "+a+"\t"+b);
    noReturnMultiParam.method(10,20);
    /**
     * 有返回值,无参数
     */
     /* ReturnNoParam returnNoParam = ()->{
        System.out.print("ReturnNoParam ");
        return 10;
    };*/
    /**
     * 简化版
     */
    ReturnNoParam returnNoParam = ()->10+20;
    System.out.println(returnNoParam.method());
    /**
     * 有返回值,有一个参数
     */
  /* ReturnOneParam returnOneParam = (int a)->
      {
        System.out.print("ReturnOneParam ");
        return a;
    };*/
    /***
     * 简化版
     */
    ReturnOneParam returnOneParam = a->a;
  System.out.println(returnOneParam.method(10));
  /**
     * 有返回值,有多个参数
     */
    /*ReturnMultiParam returnMultiParam = (int a ,int b)->{
        System.out.print("ReturnMultiParam ");
        return a+b;
    };*/
    /**
     * 简化版
     */
    ReturnMultiParam returnMultiParam = (a ,b)- >a+b;
    System.out.println(returnMultiParam.method(10, 20));
}

Lambda表达式的使用

Lambda表达式引用方法

有时候我们不是必须使用Lambda的函数体定义实现,我们可以利 用 lambda表达式指向一个已经存在的方法作为抽象方法的实现。

要求

  1、参数的个数以及类型需要与函数接口中的抽象方法一致。

  2、返回值类型要与函数接口中的抽象方法的返回值类型一致。

语法

     方法归属者::方法名 静态方法的归属者为类名,非静态方法归属者 为该对象的引用。

案例

/**
* 无返回值,无参数
*/
@FunctionalInterface
interface NoReturnNoParam{
    void method();
}
/**
* 无返回值,有一个参数
*/
@FunctionalInterface
interface NoReturnOneParam{
    void method(int a);
}
/**
* 无返回值,有多个参数
*/
@FunctionalInterface
interface NoReturnMultiParam{
    void method(int a,int b);
}
/**
* 有返回值,无参数
*/
@FunctionalInterface
interface ReturnNoParam{
    int method();
}
/**
* 有返回值,有一个参数
*/
@FunctionalInterface
interface ReturnOneParam{
    int method(int a);
}
/**
* 有返回值,有多个参数
*/
@FunctionalInterface
interface ReturnMultiParam{
    int method(int a,int b);
}
public class Test {
    public static void main(String[] args) {
        /**
         * 无返回值,无参数
         */
       /* NoReturnNoParam noReturnNoParam = ()->{
          System.out.println("NoReturnNoParam");};*/
        /**
         * 简化版
         */
        NoReturnNoParam noReturnNoParam = ()-> System.out.println("NoReturnNoParam");
        noReturnNoParam.method();
        /**
         * 无返回值,有一个参数
         */
       /* NoReturnOneParam noReturnOneParam =(int a)->{
          System.out.println("NoReturnOneParam "+a);
        };*/
        /**
         * 简化版
         */
        NoReturnOneParam noReturnOneParam = a -> System.out.println("NoReturnOneParam"+a);
         noReturnOneParam.method(10);
        /**
         * 无返回值,有多个参数
         */
       /* NoReturnMultiParam noReturnMultiParam = (int a, int b)->{
          System.out.println("NoReturnMultiParam"+a+"\t"+b);
        };*/
          NoReturnMultiParam noReturnMultiParam = (a,b)-> System.out.println("NoReturnMultiParam"+a+"\t"+b);
        noReturnMultiParam.method(10,20);
        /**
         * 有返回值,无参数
         */
       /* ReturnNoParam returnNoParam = ()->{
            System.out.print("ReturnNoParam ");
            return 10;
        };*/
        /**
         * 简化版
         */
        ReturnNoParam returnNoParam = ()->10+20;
      System.out.println(returnNoParam.method());
        /**
         * 有返回值,有一个参数
         */
      /* ReturnOneParam returnOneParam = (inta)->{
            System.out.print("ReturnOneParam");
            return a;
        };*/
        /***
         * 简化版
         */
         ReturnOneParam returnOneParam = a->a;
         System.out.println(returnOneParam.method(10));
        /**
         * 有返回值,有多个参数
         */
        /*ReturnMultiParam returnMultiParam = (int a ,int b)->{
            System.out.print("ReturnMultiParam");
            return a+b;
        };*/
        /**
         * 简化版
         */
        ReturnMultiParam returnMultiParam = (a,b)->a+b;
      System.out.println(returnMultiParam.method(10,20));
   }
    /**
     * 要求:
     * 1,参数的个数以及类型需要与函数接口中的抽象方法一致。
     * 2,返回值类型要与函数接口中的抽象方法的返回值类型一致。
     * @param a
     * @return
     */
public static int doubleNum(int a){
        return 2*a;
   }
    public int addTwo(int a){
        return a+2;
   }
}
public class Test2 {
    public static void main(String[] args) {
        ReturnOneParam returnOneParam =Test::doubleNum;
        int value = returnOneParam.method(10);
        System.out.println(value);
        Test test = new Test();
        ReturnOneParam returnOneParam1 = test::addTwo;
        int value2 = returnOneParam1.method(10);
        System.out.println(value2);
   }
}

Lambda表达式创建线程

public class Test3 {
    public static void main(String[] args) {
        System.out.println(Thread.currentThread().getName()+" 开始");
        new Thread(()->{
            for(int i=0;i<20;i++){
                try {
                    Thread.sleep(500);
               } catch (InterruptedExceptione) {
                    e.printStackTrace();
               }
              System.out.println(Thread.currentThread().getName()+" "+i);
           }
       },"Lambda Thread ").start();
      System.out.println(Thread.currentThread().getName()+" 结束");
   }
}

Lambda 表达式中的闭包问题

什么是闭包

闭包的本质就是代码片断。所以闭包可以理解成一个代码片断的引 用。在Java中匿名内部类也是闭包的一种实现方式。 在闭包中访问外部的变量时,外部变量必须是final类型,虚拟机会 帮我们加上 final 修饰关键字。

public class Test4 {
    public static void main(String[] args) {
        final int num  =10;
        NoReturnNoParam noReturnNoParam = ()- >System.out.println(num);
        noReturnNoParam.method();
   }
}

常用的函数接口

Consumer接口的使用

Consumer 接口是JDK为我们提供的一个函数式接口,该接口也被 称为消费型接口。

遍历集合

我们可以调用集合的 public void forEach(Consumer action) 方法,通过 lambda 表达式的方式遍历集合中的元素。以下 是 Consumer 接口的方法以及遍历集合的操作。

public class Test4 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.forEach(System.out::println);
   }
}

Predicate接口的使用

Predicate 是 JDK 为我们提供的一个函数式接口,可以简化程序的编写。

删除集合中的元素

我们通过public boolean removeIf(Predicate filter)方 法来删除集合中的某个元素,

public class Test5 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("d");
        list.removeIf(ele->ele.equals("b"));
        list.forEach(System.out::println);
   }
}

Comparator接口的使用

Comparator是 JDK 为我们提供的一个函数式接口,该接口为比较 器接口。

元素排序

之前我们若要为集合内的元素排序,就必须调用 sort 方法,传入比 较器重写 compare 方法的比较器对象,现在我们还可以使用 lambda 表达式来简化代码。

public class Test7 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("d");
        list.add("b");
        list.add("c");
        list.sort((o1,o2)->o1.compareTo(o2));
        list.forEach(System.out::println);
   }
}

Stream流介绍

Stream流简介

Stream是数据渠道,用于操作数据源所生成的元素序列,它可以实 现对集合的复杂操作,例如过滤、排序和映射等。Stream不会改变 源对象,而是返回一个新的结果集。

Stream流的生成方式

生成流:通过数据源(集合、数组等)创建一个流。

中间操作:一个流后面可以跟随零个或者多个中间操作,其目的主要是打开流,做出某种程度的数 据过滤/映射,然后返回一个新的流,交给下一个操作使用。

终结操作:一旦执行终止操作,就执行中间的链式操作,并产生结果。

Stream流的常见方法

数据过滤

public class Test8 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("oldlu");
        list.add("oldlin");
        list.add("kevin");
        list.add("peter");
        //多条件and关系
        list.stream().filter(ele -> ele.startsWith("o")).filter(ele-
>ele.endsWith("n")).collect(Collectors.toList()).forEach(System.out::println);
        System.out.println("------------------------");
        //多条件or关系
        Predicate<String> predicate1 = ele ->ele.startsWith("o");
        Predicate<String> predicate2 = ele->ele.endsWith("n");
        list.stream().filter(predicate1.or(predicate2)
).collect(Collectors.toList()).forEach(System.out::println);
   }
}

数量限制

public class Test9 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("oldlu");
        list.add("oldlin");
        list.add("kevin");
        list.add("peter");
        //limit
      list.stream().limit(2).forEach(System.out::println);
   }
}

元素排序

public class Test10 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("b");
        list.add("c");
        list.add("a");
        list.add("d");
        //升序排序
      list.stream().sorted(Comparator.naturalOrder()).forEach(System.out::println);
        System.out.println("---------------");
        //降序排序
      list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
   }
}


目录
相关文章
|
1月前
|
存储 Java 数据挖掘
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
84 6
|
1月前
|
Java API 开发者
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。
|
2月前
|
Java API 开发者
Java中的Lambda表达式:简洁代码的利器####
本文探讨了Java中Lambda表达式的概念、用途及其在简化代码和提高开发效率方面的显著作用。通过具体实例,展示了Lambda表达式如何在Java 8及更高版本中替代传统的匿名内部类,使代码更加简洁易读。文章还简要介绍了Lambda表达式的语法和常见用法,帮助开发者更好地理解和应用这一强大的工具。 ####
|
2月前
|
并行计算 Java 编译器
深入理解Java中的Lambda表达式
在Java 8中引入的Lambda表达式,不仅简化了代码编写,还提升了代码可读性。本文将带你探索Lambda表达式背后的逻辑与原理,通过实例展示如何高效利用这一特性优化你的程序。
|
2月前
|
搜索推荐 Java API
探索Java中的Lambda表达式
本文将深入探讨Java 8引入的Lambda表达式,这一特性极大地简化了代码编写,提高了程序的可读性。通过实例分析,我们将了解Lambda表达式的基本概念、使用场景以及如何优雅地重构传统代码。文章不仅适合初学者,也能帮助有经验的开发者加深对Lambda表达式的理解。
|
2月前
|
Java
探索Java中的Lambda表达式
【10月更文挑战第37天】本文将带你深入理解Java的Lambda表达式,从基础语法到高级特性,通过实例讲解其在函数式编程中的应用。我们还将探讨Lambda表达式如何简化代码、提高开发效率,并讨论其在实际项目中的应用。
|
2月前
|
Java API
Java中的Lambda表达式与函数式编程####
【10月更文挑战第29天】 本文将深入探讨Java中Lambda表达式的实现及其在函数式编程中的应用。通过对比传统方法,我们将揭示Lambda如何简化代码、提高可读性和维护性。文章还将展示一些实际案例,帮助读者更好地理解和应用Lambda表达式。 ####
|
1月前
|
安全 Java API
Java中的Lambda表达式:简化代码的现代魔法
在Java 8的发布中,Lambda表达式的引入无疑是一场编程范式的革命。它不仅让代码变得更加简洁,还使得函数式编程在Java中成为可能。本文将深入探讨Lambda表达式如何改变我们编写和维护Java代码的方式,以及它是如何提升我们编码效率的。
|
2月前
|
安全 Java API
Java中的Lambda表达式与Stream API的高效结合####
探索Java编程中Lambda表达式与Stream API如何携手并进,提升数据处理效率,实现代码简洁性与功能性的双重飞跃。 ####
36 0
|
2月前
|
Java 开发者
探索Java中的Lambda表达式
【10月更文挑战第43天】本文将深入浅出地介绍Java中的Lambda表达式,通过实际代码示例,带领读者理解其背后的原理及应用场景。Lambda表达式不仅简化了代码,还提高了开发效率,是Java开发者必备的技能之一。