JAVA基础深化提高(九) | 函数式编程

一、Lambda表达式介绍

1.1 Lambda简介

Lambda表达式是Java 8引入的一种新特性,用于简化代码编写和提高代码可读性。它允许我们以更简洁的方式定义和传递匿名函数。

Lambda表达式由箭头"->"分隔为两部分:左侧为参数列表,右侧为表达式主体。它通常用于替代需实现函数式接口的匿名内部类。

Lambda表达式具有以下特点:

  1. 简洁性:Lambda表达式可以极大地减少冗余的代码,使得程序更加精简和易读。
  2. 函数式编程:Lambda表达式鼓励使用函数式编程思想,通过将函数视为第一等公民来处理数据和逻辑。
  3. 延迟执行:Lambda表达式允许延迟执行代码,比如在需要的时候才进行计算或处理。

Lambda表达式的应用场景包括但不限于:

  1. 集合操作:可以通过Lambda表达式对集合进行遍历、过滤和转换等操作。
  2. 多线程编程:可以将Lambda表达式作为线程任务,简化多线程编程的代码量。
  3. 排序和比较:可以通过Lambda表达式定义自定义的排序规则和比较器。

Lambda表达式的语法形式可以灵活运用,适应不同的需求和场景。它是现代Java编程中的重要工具,使代码更加简洁、灵活和易于维护。

1.2 接口要求

虽然使用 Lambda 表达式可以对某些接口进行简单的实现,但并不是所有的接口都可以使用 Lambda 表达式来实现。Lambda 规定接口中只能有一个需要被实现的方法,不是规定接口中只能有一个方法。

jdk 8 中有另一个新特性:default, 被 default 修饰的方法会有默认实现,不是必须被实现的方法,所以不影响 Lambda 表达式的使用。

@FunctionalInterface注解作用

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

二、Lambda表达式语法

2.1 语法结构

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

语法形式为 () -> {}:

() 用来描述参数列表,如果有多个参数,参数之间用逗号隔开,如果没有参数,留空即可;

-> 读作(goes to),为 lambda运算符 ,固定写法,代表指向动作;

{} 代码块,具体要做的事情,也就是方法体内容;

2.2 Lambda表达式的重要特征

可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。

可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。

可选的大括号:如果主体包含了一个语句,就不需要使用大括号。

可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

2.3 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表达式入门案例

3.1 定义函数接口

/**
 * 无返回值,无参数
 */
@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);
}

3.2 实现函数接口

 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;
        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表达式的使用

4.1 Lambda表达式的引用方法

4.1.1 要求

  • 参数的个数以及类型需要与函数接口中的抽象方法一致。
  • 返回值类型要与函数接口中的抽象方法的返回值类型一致。

4.1.2 语法

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

4.1.3 案例

 	/**
     * 要求:
     * 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 value1 = returnOneParam1.method(10);
        System.out.println(value1);
    }
}

4.2 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 (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+" "+i);
            }
        },"Lambda Thread").start();

        System.out.println(Thread.currentThread().getName()+" 结束");
    }
}

4.3 Lambda 表达式中的闭包问题

4.3.1 什么是闭包

闭包的本质就是代码片断。所以闭包可以理解成一个代码片断的引用。在Java中匿名内部类也是闭包的一种实现方式。

在闭包中访问外部的变量时,外部变量必须是final类型,虚拟机会帮我们加上 final 修饰关键字。

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

五、常用的函数接口

5.1 Consumer接口的使用

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

5.1.1 遍历集合

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

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.forEach(System.out::println);
    }

    //格式化数字的函数式方法
    public void f1(Consumer<Double> c, Double money) {
        c.accept(money);
    }

    @Test
    public void f1Test() {
        f1(c -> {
            DecimalFormat df = new DecimalFormat("#,###.###");//格式化数字,不保留0
            System.out.println(df.format(c));
        }, 123459687978.78966);
        System.out.println("-----------------------------------------------");
        f1(c -> {
            DecimalFormat df = new DecimalFormat("0,000.000");//格式化数字,可以保留0
            System.out.println(df.format(c));
        }, 123459687978.78966);
    }
}

在这里插入图片描述

5.2 Predicate接口的使用

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

5.2.1 删除集合中的元素

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

class PredicateImpl implements Predicate{

    @Override
    public boolean test(Object o) {
        return (o.equals("b"));
    }
}
public class Test6 {
    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("a"));
        list.forEach(System.out::println);
    }
    /**
     * 根据指定规则过滤集合中的的信息然后返回一个过滤后的集合
     */
    @Test
    public void filterListTest(){
        List<String> list = new ArrayList<>();
        list.add("hello abc");
        list.add("welcome abc");
        list.add("hello world");
        list.add("你好 abc");
        list.add("大家好 abc");
        list.add("hello mickey");
        list.stream().filter(s -> s.contains("hello")).collect(Collectors.toList()).forEach(System.out::println);
    }
}

5.3 Comparator接口的使用

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

5.3.1 元素排序

class ComparatorImpl implements Comparator<String>{
    @Override
    public int compare(String o1, String o2) {
        return o1.compareTo(o2);
    }
}

public class Test7 {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("b");
        list.add("c");
        list.add("d");
        list.add("a");

        list.sort((o1,o2)->o1.compareTo(o2));
        list.forEach(System.out::println);
        System.out.println("-----------------");

        //引用类方法
        list.sort(String::compareTo);
        list.forEach(System.out::println);
        System.out.println("-----------------");

        //使用Comparator接口中的naturalOrder方法做升序排序。
        list.sort(Comparator.naturalOrder());
        list.forEach(System.out::println);
        System.out.println("-----------------");

        //使用Comparator接口中的naturalOrder方法做升序排序。
        list.sort(Comparator.reverseOrder());
        list.forEach(System.out::println);
        System.out.println("-----------------");
    }
}

六、Stream流介绍

6.1 Stream流简介

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

6.2 Stream流的生成方式

  • 生成流:通过数据源(集合、数组等)创建一个流。
  • 中间操作:一个流后面可以跟随零个或者多个中间操作,其目的主要是打开流,做出某种程度的数据过滤/映射,然后返回一个新的流,交给下一个操作使用。
  • 终结操作:一旦执行终止操作,就执行中间的链式操作,并产生结果。

6.3 Stream流的常见方法

6.3.1 数据过滤

public class Test8 {
    public static void main(String[] args) {
        /**
         * 1.创建Stream对象
         * 2.操作Stream对象
         * 3.结束Stream对象
         */

        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);
    }

	//函数式接口过滤求和
    @Test
    public void f1(){
        List<User> list = new ArrayList<>();
        list.add(new User(1, "mickey", 18));
        list.add(new User(2, "john", 18));
        list.add(new User(3, "doc", 18));
        list.add(new User(4, "cat", 18));
        list.add(new User(5, "tom", 18));
        list.add(new User(6, "tomcat", 18));
        list.add(new User(7, "mysql", 18));
        list.add(new User(8, "java", 18));
        System.out.println(list.stream().map(user -> user.getAge()).reduce((d1, d2) -> d1 + d2).get());
    }

    @Test
    public void f2(){
        List<User> list = new ArrayList<>();
        list.add(new User(1, "amickey", 22));
        list.add(new User(2, "johna", 33));
        list.add(new User(3, "doca", 19));
        list.add(new User(4, "cat", 20));
        list.add(new User(5, "toma", 20));
        list.add(new User(6, "tomcat", 70));
        list.add(new User(7, "mysqla", 73));
        list.add(new User(8, "java", 84));
        //查看user集合中的名字中是否都包含 a  包含返回true 反之false 
        System.out.println(list.stream().allMatch(user -> user.getMickey().contains("a")));
    }

    @Test
    public void test3() {
        //以()代表流,[]为数组,""为字符串
        List<String> list = Arrays.asList("a-b-c", "d-e-f");

        //map中的第一个t是"a-b-c",返回的是[a,b,c]一个数组
        //map以后流中的元素为([a,b,c],[e,d,f])两个元素,每个元素是数组
        //map: ("a-b-c", "d-e-f")---->([a,b,c],[e,d,f]) ,size=2
        list.stream().map(t -> t.split("-")).forEach(e -> System.out.println(Arrays.toString(e)));

        System.out.println("-----------");

        //flatMap第一个t是"a-b-c",返回的是(a,b,c)的一个子流,最后聚合所有子流合并为一个流
        //flatMap: ("a-b-c", "d-e-f")---->((a,b,c),(d,e,f))-->(a,b,c,d,e,f) ,size=6
        list.stream().flatMap(t -> Stream.of(t.split("-"))).forEach(System.out::println);
    }
}

6.3.2 数量限制

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");
        list.stream().limit(2).collect(Collectors.toList()).forEach(System.out::println);
    }
}

6.3.3 元素排序

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().forEach(System.out::println);
        System.out.println("----------------------");
        list.stream().sorted(Comparator.naturalOrder()).forEach(System.out::println);

        System.out.println("----------------------");
        //降序排序
        list.stream().sorted(Comparator.reverseOrder()).forEach(System.out::println);
    }

 	@Test
    public void f1(){
        List<User> list = new ArrayList<>();
        list.add(new User(1, "mickey", 22));
        list.add(new User(2, "john", 33));
        list.add(new User(3, "doc", 19));
        list.add(new User(4, "cat", 20));
        list.add(new User(5, "tom", 20));
        list.add(new User(6, "tomcat", 70));
        list.add(new User(7, "mysql", 73));
        list.add(new User(8, "java", 84));
        list.stream().sorted((o1,o2)->Integer.compare(o1.getAge(),o2.getAge())).collect(Collectors.toList()).forEach(System.out::println);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值