Java:函数式编程

1. 函数式编程思想

函数式编程体现的是一种编程思想,是面向数学的抽象,通过表达式将原数据映射为新的数据。

2. 为什么使用函数式编程

一个例子告诉你为什么使用函数式编程:将一个数组中的每个元素求平方,这段代码应该怎么写?

  • 实现方案1

  public static void squareTest1(){

        List<Integer> list = Arrays.asList(1,2,3,4,5);
        //创建一个新集合
        List<Integer> retList = new ArrayList<>();
        //遍历旧集合
        for(Integer element : list){
           //将元素计算后添加到新集合中
           retList.add(element * element);
        }
        //循环输出
        for(Integer element : retList){

            System.out.println(element);
        }
    }
  • 实现方案2

 public static void squareTest2(){

        List<Integer> list = Arrays.asList(1,2,3,4,5);

        //把集合中的元素映射到新的集合中
        List<Integer> retList = list.stream().map((e)->e*e).collect(Collectors.toList());
        
        //对每一个元素执行输出操作
        retList.stream().forEach((e)->System.out.println(e));
    }

总结:方案将待求解的问题转换为一个个命令,然后依次执行命令,最终得到结果,这是一种典型的命令式编程方式。面向对象的编程方式是命令式编程的一种。方案2,通过一个表达式,将原集合元素映射到新的集合,简单明了,这种编程方式就是函数式编程。

3. 函数式编程了解哪些

3.1 lambda表达式

3.1.1 什么是lambda表达式

什么是lambda表达式?形如:(参数1,参数2…)->{//代码块}的一段代码。

3.1.2 如何写lambda表达式

如定义一个函数,这个函数接收一个整型数据和一个计算接口为入参,根据计算接口计算最终结果,代码如下:

     /**
     * 计算接口
     */
    interface Calculate{

       Integer calc(Integer a);

    }

    private static Integer calc(Integer a,Calculate calculate){

        return calculate.calc(a);
    }
    
    public static void interfaceTest(){

        Integer ret = calc(10, new Calculate() {

            @Override
            public Integer calc(Integer a) {

                return a*a;
            }
        });

        System.out.println(ret);
    }

    public static void lambdaTest(){

        //lambda表达式
        Integer ret = calc(10, (e)->e*e);

        System.out.println(ret);
    }

3.1.3 lambda表达式注意事项

使用lambda表达式后代码非常简洁,可以让我们更聚焦于业务逻辑的编写。那么,lambda表达式怎么知道我的接口类型为Calculate的?答案是:编译器的类型推导,编译器会将lambda表达式转换为正确的类型。再看上面的例子,如果Calculate接口有不止一个方法会怎么样?

   /**
     * 计算接口
     */
    interface Calculate{

       Integer calc(Integer a);

       //添加一个接口
       Integer test(Integer a);

    }

此时再用lambda表达式,会收到编译器的报错,说明什么?lambda表达式可替换的接口只能有一个方法,没错,这种接口就是函数式接口。

3.2 函数式接口

3.2.1 什么是函数式接口

函数式接口就是只有一个抽象方法的接口,Java中如何约束一个接口是函数式接口?使用注解:@FunctionalInterface,示例如下:


@FunctionalInterface
interface Calculate{

   Integer calc(Integer a);

}

3.2.2 供lambda表达式使用的函数式接口

3.2.2.1 Predicate接口

Predicate 接口只有一个参数,返回boolean类型。形如:该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)。示例代码:


Predicate<Integer> predicate = (e)->e>10;

predicate.and((e) -> e > 20).test(15);//false

predicate.or((e) -> e > 20).test(15);//true
3.2.2.2 Function 接口

Function 接口有一个参数并且返回一个结果,并附带了一些可以和其他函数组合的默认方法(compose, andThen)。示例代码:

Function<String,Integer> function = (T)->Integer.parseInt(T);
        
function.apply("123");//123
function.andThen((T)->T+100).apply("123");//223
3.2.2.3 Supplier 接口

Supplier 接口返回一个任意泛型的值,和Function接口不同的是该接口没有任何参数。示例代码:

 Supplier<String> supplier = ()->"123";

 supplier.get(); //"123"
3.2.2.4 Consumer 接口

Consumer 接口表示执行在单个参数上的操作。示例代码:

Consumer<String> consumer = (e)->System.out.println(e);

 consumer.accept("123");//打印"123"

3.3 Stream

3.3.1 Java中的流

Java流使程序员得以站在更高的抽象层次上对集合进行操作。

我们先看一个例子,一个集合中有10个整型元素,我们要从中过滤掉偶数元素,只保留奇数元素,代码怎么写?


public static void filterTest(){

    List<Integer> list = Arrays.asList(1,3,5,8,10,13,7,39,28,53);
    
    //一行代码搞定
    List<Integer> newList = list.stream().filter((e)->e%2==1).collect(Collectors.toList());

    newList.forEach((e)->System.out.println(e));
}

3.3.2 Stream操作方法

Stream中提供了很多操作,基本上可以分为两类:中间操作和终止操作。中间操作的返回结果是一个流,可以继续执行链式操作;终止操作意味着流被终止了,不能再继续操作流了。流的中间操作有:filter,map,flatMap等,终止操作有:forEach,reduce,collect等。

3.3.2.1 filter

filter:过滤流中的元素,将符合条件的元素挑出来。

3.3.2.2 map

map:该操作用于将流中的每个元素按照一定的规则映射为一个新的元素。

3.3.2.3 flatMap

flatMap:该操作和map类似,区别是把流中的一个元素映射为多个元素。

3.3.2.4 reduce

reduce:该操作可以实现从一组值中生成一个值,min,max,count等操作都可以看做是reduce操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值