Java的Lamdba语法和函数式编程理解

2025-12-12 0 566
一:背景

代码中看到了Lambda表达式和Cousume结合使用,针对这个在代码中的运行顺序有点看不懂执行顺序,因此了解下Lambda表达式在代码中的使用场景做一个简单研究。

二:使用场景

Lambda表达式是java8中引入新特性,其标准形式为:() ->{};

变体形式包括:

(x,y)->{return x +y;} //省略参数类型

(x,y) -> x +y //省略函数体的括号和 return

x -> x*x //省略参数括号和函数体的大括号和 return

()中是参数,{}中是运行表达式。示例如下

Thread thread1 = new Thread(
        () ->{System.out.println(Thread.currentThread().getId() +\"11111\");}
);
thread1.start();
场景1:替代匿名内部类
//采用匿名内部类实现线程中方法运行
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getId() + \"    11111\");
    }
});
thread.start();
​
//使用lambda替缓匿名内部类
Thread thread1 = new Thread(
        () ->{System.out.println(Thread.currentThread().getId() +\"    11111\");}
);
thread1.start();
使用场景2:结合stream api进行集合元素处理
//forEach 循环读取list每一项
List list1 = Arrays.asList(\"aaa\",\"bbb\");
//循环读取每一项并打印,采用标准for循环或者增强for都行 
for (int i = 0;i<list1.size();i++){
    System.out.println(list1.get(i));
}

//foreach要是换成匿名内部类的实现方式如下,和上面标准for循环一样效果,可进一步将匿名内部类改造成Lambda方式
list1.forEach(new Consumer() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});

//采用forEach方式,同样实现循环读取打印每一个,和上面一样效果,采用lambda效果
list1.forEach((s)->{System.out.println(s);});
引申场景1:

forEach函数接受一个Cousume对象,Counsumer类定义中有一个accept函数,因此其实foreach函数接受的就是一个抽象接口对象。

default void forEach(Consumer action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}
​
public interface Consumer<T> {
    void accept(T t);
}

以上场景其实就是典型的接口中传入一个匿名对象,然后该函数调用匿名函数的方法,所以从写法上等价于

List<String> list1 = Arrays.asList(\"aaa\",\"bbb\");
list1.forEach((s)->{System.out.println(s);});
​
//和上面的lambda表达式写法一样,上面就是匿名内部类的简化写法
list1.forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});

所以Consumer就是提供了空接口的类,如果要使用lamba表达式来实现一些逻辑时就需要有一个类似的接口类,供用户来直接使用,因此java 提供了Consumer这个接口类,在实际使用过程中可以Consumer作为参数放在接口中,这样就能直接在调用处直接将返回方法传递到函数中,就像传递了一个匿名内部类一样。

引申场景2:

在看到Consumer对象时,进一步可引申出java函数式编程,java函数式编程的主要几个实现接口类为:

Function,Consumer,Supplier,Predicate。这4个类各自有各自的作用,此处如何使用不详细展开,此4个类就是java中函数式编程的支持API。

在函数式编程中还引入了另外一个Optional类,该类的主要几个使用方法是

//判断值是否为空,不为空值则返回执行一个动作,为空则不执行
public void ifPresent(Consumer<? super T> action) {
    if (value != null) {
        action.accept(value);
    }
}
//获取到Optional内包含的那个对象的值,如果为空则返回orElse中的另外值
public T orElse(T other) {
    return value != null ? value : other;
}
//将Optional中的那个值进行map映射,映射规则就是map中传入的函数 可能出现返回Optional<Optional>
public  Optional map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent()) {
        return empty();
    } else {
        return Optional.ofNullable(mapper.apply(value));
    }
}
//将Optional中的那个值进行map映射,映射规则就是map中传入的函数  但是返回的是一个没有嵌套的Option 对象
public  Optional flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent()) {
        return empty();
    } else {
        @SuppressWarnings(\"unchecked\")
        Optional r = (Optional) mapper.apply(value);
        return Objects.requireNonNull(r);
    }
}

Optional的简单引用实例处理:

public static void testLambda4(){
    //通过ofNullable产生一个Optional对象
    Optional<String> op = Optional.ofNullable(getName());
    //通过ifPresent判断 如果op包含的对象不为空时,则执行这个函数对象
    op.ifPresent((s) ->{System.out.println(s);});
    //使用map函数将Optional中包的对象执行一次toUpperCase操作,
    //且执行完之后如果返回的Optional不为空的话则执行 函数对象 
    op.map(String::toUpperCase).ifPresent((s)->{System.out.println(\"装换完成的\"+s);});
    //map函数的另外一种写法,即使用标准lambda表达式作为参数传入给到map函数,和上一行的函数等效
    //map函数中的入参是一个函数式接口Function,此处应该传入的lambda表达式应该包含一个返回值,
    //为什么是一个返回值的函数不是一个返回为void的函数,是根据map函数的定义的Function中的泛型接口确定的
    op.map(  (s) ->{
        return s.toUpperCase();
    }
    ).ifPresent((s)->{System.out.println(\"装换完成的\"+s);} );
    
    
    //map函数和flatmap函数的区别,返回值是否会嵌套返回Optional对象
    Optional<Optional<String>> s2 = op.map((s) -> {
            return Optional.ofNullable(s.toUpperCase());
        });
    
    Optional<String> s1 = op.flatMap(s -> {
    return Optional.ofNullable(s.toUpperCase());});
    
    
    
}
​
public static String getName(){
    return \"aaa\";
}

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

申明:本文由第三方发布,内容仅代表作者观点,与本网站无关。对本文以及其中全部或者部分内容的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。本网发布或转载文章出于传递更多信息之目的,并不意味着赞同其观点或证实其描述,也不代表本网对其真实性负责。

左子网 编程相关 Java的Lamdba语法和函数式编程理解 https://www.zuozi.net/35930.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、描述:源码描述(含标题)与实际源码不一致的(例:货不对板); 2、演示:有演示站时,与实际源码小于95%一致的(但描述中有”不保证完全一样、有变化的可能性”类似显著声明的除外); 3、发货:不发货可无理由退款; 4、安装:免费提供安装服务的源码但卖家不履行的; 5、收费:价格虚标,额外收取其他费用的(但描述中有显著声明或双方交易前有商定的除外); 6、其他:如质量方面的硬性常规问题BUG等。 注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。
查看详情
  • 1、左子会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、左子无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在左子上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于左子介入快速处理。
查看详情

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务