java8-lamdba

news/2024/11/23 23:37:42/

文章目录

    • 目标
    • 基础概念
    • lamdba 表达式
      • 双冒号 :: 关键字
      • Lambda的范围
    • 一些函数式接口的简单介绍
      • Predicate
      • Function
      • Supplier
      • Consumer
      • ToIntFunction

目标

  • 了解lamdba 表达式

    参考 java 简明教程文档

    深入理解Java双冒号(::)运算符的使用

    Java8新特性2:方法引用–深入理解双冒号::的使用

基础概念

引入两个概念: 函数式接口,接口中的默认方法

  • 函数式接口:如果一个接口中,只包含一个抽象方法,就可以认为是一个函数式接口。其中可以使用注解

    @FunctionalInterface 标识这个接口是一个函数式接口,当然不使用这个注解标识也是可以的。

    /*** 函数式接口,只包含一个抽象方法*/
    @FunctionalInterface
    public interface MyPrint<T> {String output(T str);
    }
    
  • 默认方法

    默认方法用于扩展接口中的方法,jdk8 之后,为了在接口中引入其他的功能,需要在接口中提供额外的方法,不能直接在原来的接口中,添加方法,这样会导致实现该接口的类,都要做修改,所以就引入了默认方法,使用 default 标识。默认方法是一个非抽象的方法,实现该接口的类,也都继承默认方法。也可以在接口中添加静态方法,用来扩展接口的功能。

    // List 接口中的 sort 就是一个默认方法
    @SuppressWarnings({"unchecked", "rawtypes"})default void  sort(Comparator<? super E> c) {Object[] a = this.toArray();Arrays.sort(a, (Comparator) c);ListIterator<E> i = this.listIterator();for (Object e : a) {i.next();i.set((E) e);}}// Comparator 接口的中的 静态方法public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {return Collections.reverseOrder();}
    

lamdba 表达式

语法:(param1,param2) -> { return xxx }

首先,函数式接口,才可以用lamdba 表达式,来表示。函数式接口中的默认方法或者静态方法用来扩展,其他的功能。

示例:

函数式接口:

/**
* 函数式接口,只包含一个抽象方法
*/
@FunctionalInterface
public interface MyPrint<T> {String output(T str);default void outputinfo(){System.out.println("info");}
}

lamdba 表达式演示:

@Testpublic void fun2() {String strw = "aaa";// 使用匿名内部类System.out.println(new MyPrint<String>() {@Overridepublic String output(String str) {return str+"1";}}.output(strw));// 使用lamdba 表达式MyPrint<String> myPrint = (str) -> str+"2";System.out.println(myPrint.output(strw));}

从上面演示效果,lamdba 表达式,相当于把匿名内部类中需要实现的方法实现了。那如果接口中,有两个需要被实现的方法,就不能使用lamdba 表达式,因为lamdba表达式不知道你要实现那个方法,所以只能是 函数式接口,才能用lamdba 表达式表示。

再演示一些其他例子:

排序:

对于lamdba 表达式,参数类型,return,或者花括号,在有时,都可以省略,看如下代码:

List<String> strs = Arrays.asList("c", "a", "d");
// 之前的实现方式
Collections.sort(strs, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}
});// lamdba 实现,将匿名内部类代码改为 lamdba 表达式
Collections.sort(strs, (String o1, String o2) -> {return o2.compareTo(o1);
});
// 只有一句,省略 return  和 花括号
Collections.sort(strs, (String o1, String o2) -> o2.compareTo(o1));
// 可以省略参数类型,会自动判断
Collections.sort(strs, (o1, o2) -> o2.compareTo(o1));// ---- 上面的lamdba 表达式,idea 会提示 黄色标识,因为还可以更加简单// 自然顺序的比较
Collections.sort(strs, Comparator.naturalOrder());
// 自然顺序相反的比较
Collections.sort(strs, Comparator.reverseOrder());

线程创建

// 将原来  new Runnable 的代码,变成了 lamdba 表达式  
@Testpublic void fun6() {new Thread(() -> System.out.println(Thread.currentThread().getName()),"thread100").start();}

双冒号 :: 关键字

双冒号:: 关键字,用于引用方法和构造函数

方法引用是与lambda表达式相关的一个重要特性。它提供了一种不执行方法的方法。为此,方法引用需要由兼容的函数接口组成的目标类型上下文。

oracle官方介绍:

Method References
You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it’s often clearer to refer to the existing method by name. Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.

方法引用

使用lambda表达式创建匿名方法。但是,有时lambda表达式只调用现有方法。在这些情况下,按名称引用现有方法通常更清楚。方法引用使您能够做到这一点;对于已经有名称的方法,它们是紧凑、易于读取的lambda表达式。

// TODO 对于方法引用,还不是很理解,但是在语义上,其实能看懂做了什么事情,有了新理解,再补充

具体示例:参考 Java8新特性2:方法引用–深入理解双冒号::的使用

在代码中的体现,更突显在java8 stream 中的应用

实现一个小例子:根据身份证号码,将性别自动设置到对象的性别字段中

通用的身份证号码设置性别方法

// 两个参数一个是 idcard ,一个是   Consumer  接口
// 简单介绍一下 Consumer 是一个函数式接口,接受一个参数,但是不返回结果。 执行的方法 accept
private void setSexInfo(String idcard, Consumer<String> user) {int genderByIdCard = IdcardUtil.getGenderByIdCard(idcard); // 根据身份证,获取性别(参见 hutool 这个类库)if (genderByIdCard == 1) {  // 男user.accept("M");}user.accept("F");  // 女}

用户对象:

public class Person{String sex;public String getSex() {return sex;}public void setSex(String sex) {this.sex = sex;}
}

测试:

    @Testpublic void fun09(){Person person = new Person();// 使用匿名函数setSexInfo("410327188510154456", new Consumer<String>() {@Overridepublic void accept(String s) {person.setSex(s);}});// 使用 lamdba 表达式setSexInfo("410327188510154456", s -> myComparator.setSex(s));// 使用 :: 双冒号setSexInfo("410327188510154456", person::setSex);}

对于 Consumer 接口中执行的流程,可以看做是,当 user.accept(“M”); 执行时,M 会作为参数,调用对接口的实现,就是 person.setSex(s); 的逻辑

在idea 中,会给出对应的优化建议,点代码左边提示的 黄色选项 。上述代码,就可以从匿名函数到lamdba表达式到双冒号的形式的优化

tada3F.png

Lambda的范围

参见: java8简明教程文档

对于lambdab表达式外部的变量,其访问权限的粒度与匿名对象的方式非常类似。 你能够访问局部对应的外部区域的局部final变量,以及成员变量和静态变量。

一些函数式接口的简单介绍

具体代码示例:参考 java8 实战 3.4.1 使用函数接口 这一章 或者 java8 简明教程中的介绍

Predicate

接受一个输入参数,返回一个boolean 的结果。在操作stream中,filter方法中接受的参数就是 Predicate 接口

    boolean test(T t);

示例:

/*** Predicate 断言,一个布尔类型的函数* 可以用于 集合类,filter 的过滤等等*/@Testpublic void fun() {// Predicate是一个布尔类型的函数Predicate<String> predicate = (s) -> s.length() > 0;boolean str1 = predicate.test("hello world");boolean str2 = predicate.test("");System.out.println(str1);System.out.println(str2);// 短路与 &&boolean test = predicate.and((s) -> s.equals("hello")).test("aaa");System.out.println(test);// 逻辑非boolean hello_world = predicate.negate().test("hello world");System.out.println(hello_world);// 逻辑或boolean aaa = predicate.or(predicate).test("aaa");System.out.println(aaa);// 判断两个对象是否相等boolean test2 = Predicate.isEqual("a2").test("a3");System.out.println(test2);boolean test3 = Predicate.isEqual("a3").test("a3");System.out.println(test3);boolean test4 = Predicate.isEqual(null).test("a3");System.out.println(test4);Predicate<String> ceshi1 = String::isEmpty;boolean test1 = ceshi1.test("");System.out.println(test1);}

Function

接收一个参数,返回一个结果。可以理解为数学公式 y = f(x),传入参数x,得到结果y. 在集合stream中,map方法接收的参数就是 Function

    R apply(T t);

示例:

/*** 表示接受一个参数,并返回一个结果* 可以理解为  y = f(x)* 接受x 参数,输出y,那么 f(x) 这个函数,我们自己定义就可以了*/@Testpublic void fun02() {// 定义 f(x) 函数Function<Integer, Integer> function = (x) -> x + 1;// 获取结果Integer result = function.apply(5);System.out.println(result);// 定义 f(x) 函数Function<Integer, Integer> function1 = (x) -> x * 5;// compose 代表先执行 compose 传入的逻辑,再执行apply 的逻辑// 6Integer apply = function.compose(function1).apply(1);System.out.println(apply);// andThen 代表先执行当前的逻辑,再执行,andthen 传入的逻辑Integer apply1 = function.andThen(function1).apply(1);System.out.println(apply1);// ((1+1)+1)*5*5  建造者模式Integer apply2 = function.andThen(function1).andThen(function1).compose(function).apply(1);System.out.println(apply2);Function<String, Integer> toInteger = Integer::valueOf;Function<String, String> backToString = toInteger.andThen(String::valueOf);backToString.apply("123"); // "123"}

Supplier

不接收参数,返回一个结果。可以理解为 实体字段的get 方法

    T get();

示例:

    /*** 接口产生一个给定类型的结果*/@Testpublic void fun03() {Supplier<String> str = String::new;String s = str.get();Supplier<Person> str1 = Person::new;// 在执行get 方法时,才会拿到person 对象 ,spring beanfactory  在执行 getbean 的时候,才会创建该对象// 延迟加载的功能Person person = str1.get();}

Consumer

接收一个参数,但是不返回结果。可以理解为 实体字段的set 方法。在集合forEach 时,传入的参数就是 Consumer 接口

void accept(T t);

示例:

    /*** 接受一个参数输入且没有任何返回值的操作* 在 集合的 foreach 中 就需要填这个接口*/@Testpublic void fun04() {Consumer<Person> personConsumer = (t) -> System.out.println("第一打印" + t.toString());Consumer<Person> personConsumer2 = (t) -> System.out.println("第二打印" + t.toString());// 执行personConsumer.accept(new Person());// 现在执行 accpect ,再执行 addthen 添加的personConsumer.andThen(personConsumer2).accept(new Person());// foreach 代码中,就调用改的 action.accept(t);Arrays.asList("1", "2").forEach((x) -> {System.out.println(x);});}

ToIntFunction

接收一个参数,返回一个int 类型的结果,跟Function 类似,这里限定了返回的结果类型是 int

    int applyAsInt(T var1);

在这里插入图片描述


http://www.ppmy.cn/news/696710.html

相关文章

Masa Blazor in Blazor Day

2022年第一场Blazor中文社区的开发者分享活动&#xff0c;我们的团队也全程参与其中&#xff0c;在议程中&#xff0c;也分享了我们团队的Blazor 管理后台模板&#xff0c;针对于Blazor&#xff0c;先科普一波&#xff0c;避免有些朋友不了解&#xff0c;Blazor是微软推出的基于…

lambda入门

什么是Lambda表达式&#xff1f; 在java的学习过程中&#xff0c;你是否见过如下图这样的代码&#xff1a; 初看时你可能不求甚解&#xff0c;但如果你有一定的java基础&#xff0c;你应该可以看出这段代码做了什么。首先&#xff0c;这段代码声明了一个接口对象&#xff0c;然…

MariaDB 版本

MariaDB 数据库管理系统是 MySQL 的一个分支&#xff0c;主要由开源社区在维护&#xff0c;采用GPL授权许可。 GitHub 产生 在Oracle控制下的MySQL开发&#xff0c;有两个主要问题&#xff1a;1. MySQL核心开发团队是封闭的&#xff0c;完全没有Oracle之外的成员参加。很多高…

BALM: Bundle Adjustment for Lidar Mapping

文章目录 代价函数&#xff0c;雅可比矩阵和海森矩阵自适应栅格化基于BA优化的LOAM 根据点在直线或平面上的约束&#xff0c;构建扫面间的特征匹配&#xff0c;基于此使用BA算法来进一步优化LOAM等视觉里程计得到的位姿。采用了非常巧妙的方式计算直线法向量相较于位姿变化的导…

DAMA-DMBOK 数据治理功能框架

1、DAMA知识领域车轮图 2、DAMA-DMBOK 功能框架标识出了11 个主要的数据管理知识领域 数据治理&#xff08;Data Governance&#xff09;通过建立一个能够满足企业数据需求的决策体系&#xff0c;为数据管理提供指导和监督数据架构&#xff08;Data Architecture&#xff09;定…

Mariadb数据库

Mariadb基础 关系模型&#xff1a; 二维关系&#xff1a;表 行&#xff1a;row, entry 列&#xff1a;column, attribution 索引&#xff1a;数据结构&#xff0c;辅助完成数据查找的&#xff1b; SQL代码&#xff1a; 存储过程 存储函数 触发器 事件调度器 事务(Transac…

AWS Lambda的简介与使用

Lambda的简介 AWS Lambda 是一项计算服务&#xff0c;可使您无需预配置或管理服务器即可运行代码。AWS Lambda 只在需要时执行您的代码并自动缩放&#xff0c;从每天几个请求到每秒数千个请求。您只需按消耗的计算时间付费 – 代码未运行时不产生费用。借助 AWS Lambda&#x…

HTML转EXE工具(HTML App Build)永久免费版

HTML转EXE工具&#xff08;HTM2EXE&#xff09;在CSDN上发布时间轴&#xff1a; 序号时间链接12022-08-17HTML转EXE工具&#xff08;HTML App Build&#xff09;初始版22023-02-18HTML转EXE工具&#xff08;HTML App Build&#xff09;最新版32023-06-23&#xff08;实际未发布…