Java8学习记录(一)——Lambda表达式

2023-11-09

这两天看了《Java8实战》,做一下记录。

目录

一、行为参数化:

1.什么是行为参数化:

二、函数式接口:

1.概念:

三、Lambda表达式:

四、方法引用(注意点):

1.静态方法引用:

2.实例方法引用(重点来了):

①任意类型的实例方法引用: 

②现有对象的实例方法引用:

3.构造方法引用:


一、行为参数化:

1.什么是行为参数化:

1. 你说:我要所有重量为 50g 的苹果。管理员调用 findByWeight(int weight) 拿给你。

2. 你又说你要红色的所有苹果,管理员调用 findByColor(String color) 帮你找到。

3. 这时你又要重量为 50g 并且为红色的所有苹果,管理员:???。

4.现在只好请来程序员带哥,修改程序加上一个 findByWeightAndColor(int weight, String color)。

   有了 findByWeightAndColor 还要 findByWeight 和 findByColor,这就打破了Don't Repeat Yourself(不要重复你自己)的软件工程原则。于是考虑将这两个需求结合成一个方法。用两个 boolean 参来控制筛选条件,具体逻辑就不写了。

findByWeightAndColor(int weight, boolean useWeight, String color, boolean useColor
);

   这样写不但臃肿,而且如果需要刷选大于50克的苹果,那还得重新写一个方法。这是不能接收的。

以上例子是把值作为参数进行查找,对于不同需求需要写不同的方法,每种查找方式都需要写一个方法,这显然是不合理的。这时程序员带哥就想到,为什么不能只写一个方法,把需求也就是行为当做参数进行传递呢?

 

①此时,只需要写一个过滤器接口,里面写一个抽象过滤方法,而过滤条件自己定义就好了。

public interface AppleFilter {
   boolean filter(Apple apple);
}

②把自己写好的过滤条件 appleFilter 当做参数传进去。

pubic List<Apple> getApple(List<Apple> list, AppleFilter appleFilter){
    if (appleFilter.filter(apple)){
        ......
    }
    .....
}

③自定义过滤重量 >50 克且颜色为 red 过滤器。这不就是熟悉的匿名内部类吗(匿名内部类需要注意这几点)。

List<Apple> list1 = obj.getApple(list, new AppleFilter() {
    @Override
    public boolean filter(Apple apple) {
        if ("red".equals(apple.getColor) && apple.getWeight()>50){
            return true;
        }
        return false;
    }
});

以上就是行为参数化。

 

二、函数式接口:

1.概念:

① 如果一个接口只有一个抽象方法,那它就是函数式接口。(注意是抽象方法)

② 加了@FunctionalInterface 注解的接口就是函数式接口,但得符合条件①才行。

这样看来,上面定义的过滤器接口就是一个函数式接口

public interface AppleFilter {
   boolean filter(Apple apple);
}

Java库中也有定义好的函数式接口:

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);
}
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}
@FunctionalInterface
public interface Predicate<T> {
    boolean test(T t);
}

 

三、Lambda表达式:

现在就要引出 Lambda表达式了:

1.Lambda 必须依附在函数式接口上。

2.Lambda 实际上是一种语法糖。

List<Apple> list1 = obj.getApple(list, new AppleFilter() {
    @Override
    public boolean filter(Apple apple) {
        .......
    }
});

对于上文的代码,可以用 Lambda 表达式来写。

List<Apple> list1 = c.getApple(list,
    (Apple apple) -> apple.getWeight()>50 && "red".equals(apple.getColor()));

也可以这样写:

AppleFilter appleFilter = apple -> "red".equals(apple.getColor()) && apple.getWeight()>50;
List<Apple> list1 = obj.getApple(list, appleFilter);

再如,新建一个线程执行打印:

new Thread(()-> sout("hello world")).start();

Lambda表达式必须通过上下文进行推断,推断过程:

 

四、方法引用(注意点):

1.静态方法引用:

Function<String, Integer> function = s -> Integer.parseInt(s);
                         ↓
Function<String, Integer> function = Integer::parseInt;
int num = function.apply("123");

2.实例方法引用(重点来了):

①指向任意类型的实例方法引用:

Function<String, Integer> function = s -> s.length();
//可以这样写
Function<String, Integer> function = String::length;
//参数写进去
function.apply("qwe");

②指向现有对象的实例方法引用

public int getValue(int num) {
    return this.hashCode() - num;
}

Apple apple = new Apple();
Function<Integer, Integer> function = num -> apple.getValue(num);
//可以写成这样
Function<Integer, Integer> function1 = apple1::getValue;

System.out.println((apple.hashCode()-3) == function.apply(3));//true

这究竟是什么意思?我比较浅显推断应该是这样(如果不对请指正):

①任意类型的实例方法引用: 

                           Lambda:( arg0, rest ) -> arg0 .method ( rest )       对应上面代码 s -> s.length();

               方法引用: ClassName :: method            对应上面代码 String::length;

:: 前面的类型和后面的方法名可以用来匹配参数,返回值就是 :: 后面的方法的返回值,通过 :: 前面的类型可以创建一个对象 obj。如上面代码 String::length,通过String可以创建一个String对象,后面的 length() 不需要参数。所以 function.apply("qwe"), "qwe"就是传入的对象;返回值就是由 obj.length() 计算所得。

 

现有对象的实例方法引用:

                          Lambda: (args) -> expr . method(args)       对应上面代码 function = num -> apple.getValue(num);

                          方法引用: expr :: method       对应上面代码  function = apple1 :: getValue;

function.apply(3)。:: 前面已经有具体对象,所以直接 apple1.getValue(3) 获得返回值。

 

再看一个究极例子加深理解(参考文章):

public interface FunctionInterface {
    public int calculate(Bean1 bean1, Bean2 bean2);
}
public class Bean1 {
    public void expect1(Bean1 bean1) {}

    public int expect2(Bean2 bean2){
        return this.hashCode() - bean2.hashCode();
    }

    public void test1(FunctionInterface i) {}
}
public class Bean2 {
    public void expect1(Bean1 bean1) {}

    public int expect2(Bean2 bean2) {}

    public void test1(FunctionInterface i) {}
}

测试代码:

public static void main(String[] args) {
    FunctionInterface interface1 = (Bean1 bean1, Bean2 bean2) -> bean1.hashCode() - bean2.hashCode();
    FunctionInterface interface2 = Bean1::expect2;

    Bean1 bean1 = new Bean1();
    Bean2 bean2 = new Bean2();

    //计算结果是一样的
    System.out.println(bean1.hashCode() - bean2.hashCode());
    System.out.println(interface1.calculate(bean1, bean2));//1.
    System.out.println(interface2.calculate(bean1, bean2));//2.
}

1式:正宗的 Lambda 表达式,不用多说。

2式:这个就有意思了,Bean1 :: expect2。根据上文分析,:: 生成Bean1类型的一个对象,调用 expect2 方法,expect2 方法中有一个 Bean2 类型的参数,要想执行 calculate 方法,那么到目前还缺一个参数。其实并不缺,也就是说省略了Bean1类型的参数bean1,lambda 就可以使用:: 前导的Bean1构建一个对象,作为第一个参数。

 

3.构造方法引用:

Supplier supplier = () -> new Apple();
            ↓
Supplier supplier = Apple::new;

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java8学习记录(一)——Lambda表达式 的相关文章

随机推荐

  • Unity3D物体上下左右旋转(不受物体自身坐标轴影响【万向锁问题解决】)

    直接将代码挂载到需要旋转的物体上 按上下左右键旋转即可 using UnityEngine using System Collections public class SpinObject MonoBehaviour public Game
  • FineReport.10 一(帆软)(报表基础练习)

    文章目录 一 FineReport 1 报表 2 安装 二 安装目录 2 1 设计器相关目录 2 2 工程相关文件夹 2 3 缓存文件 2 3 1 FineReportEnv xml 三 初始练习 四 遇见的问题记录 1 初始数据库出问题需
  • Python基础入门(五)——关于一个Number类型的小实例

    Number类型数据是我们在python当中经常要用到的数据类型 先上一些小知识点 再上实例 相关知识点 Number类型 Number类型 Number类型的定义和删除 一句话 赋值就是定义 删除要用DEL 定义 var1 1 var2
  • 大语言模型的演进

    大语言模型的演进 借着上次科技树剪枝的话题 大语言模型为人工智能科技树再次剪枝 让我们再来看看大语言模型这个分枝是如何生长的 也是经历6年的Google和OpenAI两家公司几次大战后的结果 第一回合 2017年6月 Google的6500
  • 从代码生成到问题解答,InsCode AI助你成为编程及写作高手

    目录 前言 InsCode AI写作助手 创造更好的写作体验 InsCode AI 创作助手 如何帮助创作者高效创作文章 结论 个人感受 一 你平时会使用这类AI工具吗 你对这类型的工具有什么看法 二 你可以花几分钟体验一下InsCode
  • 新的刷脸支付方式掘起手机支付将会終结

    手机支付将会終结 新的支付方式掘起 新的支付方式对很多人还是很陌生的 这就要很好的推广和布置 现在推出了二代的蜻蜓刷脸设备 向商户销售出了舒缓的二代蜻蜓刷脸支付设备 超市 快餐厅 自动贩卖机都已经实现商业直播 相信很快在每个城市 都会发现这
  • 重载new/delete(C++中的new/delete与operator new/operator delete)

    转 http blog csdn net zhangxiao93 article details 50768025 原文 http www cnblogs com luxiaoxun archive 2012 08 10 2631812 h
  • k8s的dashboard日常操作

    k8s的dashboard日常操作 一 k8s的dashboard介绍 1 dashboard介绍 2 dashboard的功能 集群管理 工作负载 服务发现和负载均衡 存储 配置 日志视图 三 查看集群的所有角色 四 查看集群的命令空间
  • Python数据结构-----递归实现快速排序

    目录 前言 快速排序 1 概念 2 示例 Python代码实现 递归实现快速排序 前言 今天我们就来一起学习快速排序的思想方法 然后通过Python语言来实现快速排序的功能 下面我们就开始今天的学习吧 快速排序 1 概念 快速排序其实是冒泡
  • 使用ggplot2包绘制分组带状图实战

    使用ggplot2包绘制分组带状图实战 在数据可视化中 分组带状图是一种常用的图表类型 可以直观地展示多个组别之间的差异和变化趋势 而R语言中的ggplot2包提供了丰富的绘图函数 其中geom jitter函数可以用来创建分组带状图 下面
  • SpringBoot + Websocket 实现实时聊天

    SpringBoot WebSocket 实现实时聊天 最近有点小时间 上个项目正好用到了websocket实现广播消息来着 现在来整理一下之前的一些代码 分享给大家 WebSocket协议是基于TCP的一种新的网络协议 它实现了浏览器与服
  • ctfshow-web10 with rollup 绕过

    0x00 前言 CTF 加解密合集 CTF Web合集 网络安全知识库 文中工具皆可关注 皓月当空w 公众号 发送关键字 工具 获取 0x01 题目 0x02 Write Up 基本方法 到处点一点 点到取消的时候 突然发现 可以下载一个文
  • C语言中signed和unsigned怎么理解?C语言unsigned long、long long 取值范围???

    C语言中signed和unsigned signed意思为有符号的 也就是第一个位代表正负 剩余的代表大小 例如 signed int 大小区间为 128 127 unsigned意思为无符号的 所有的位都为大小 没有负数 例如 unsig
  • java实现下载excel读取与生成超详细

    背景 没啥背景 就是要做这个功能 创建ExcelUtil工具类 具体导入导出方法如下 excel导入 param inputStream 导入的excel文件 return public static List
  • 酱香咖啡喝了没?用数据分析揭秘瑞幸咖啡的7500万用户增长策略

    瑞幸 X 茅台 这波联名赢麻了 不仅狂卖 542 万杯 甚至带动茅台市值飙升200亿 瑞幸这几年联名搞了不少 又是线条小狗的爱情故事 又是椰树 维密 周大福 足球的 下面老李就从数据分析角度 带大家来看一下近几年 瑞幸咖啡的用户增长策略 是
  • 数据结构笔记之链式栈的基本操作

    include stdio h include stdlib h include io h include math h include time h define OK 1 define ERROR 0 define TRUE 1 def
  • VMWare安装

    1 1 VMWare简介 VMWare是一个虚拟技术的合集 它提供了众多的相关软件 类似于Parallels VMWare是商业应用 而且价格非常的贵 所以 通常我们使用的是网上别人破解的版本 而不是使用官方的正版 VMWare官网 VMw
  • 【UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0xd3 in position 0: invalid continuation byte】

    UnicodeDecodeError utf 8 codec can t decode byte 0xd3 in position 0 invalid continuation byte F jupyter work dir MMLAB m
  • 有一个公网IP,在内网如何架设多台服务器?

    进行内网ip到外网ip的映射 也就是pat 这个工作现在多半由防火墙来完成 不过如果没有防火墙 用路由器也可以完成 只不过会在高峰时加重路由器的负担 思科2600路由可以独立完成各种nat pat但是因为这款产品本身属于低端产品 所以能够担
  • Java8学习记录(一)——Lambda表达式

    这两天看了 Java8实战 做一下记录 目录 一 行为参数化 1 什么是行为参数化 二 函数式接口 1 概念 三 Lambda表达式 四 方法引用 注意点 1 静态方法引用 2 实例方法引用 重点来了 任意类型的实例方法引用 现有对象的实例