首页 技术 正文
技术 2022年11月18日
0 收藏 689 点赞 4,604 浏览 5574 个字

函数式接口详细定义

函数式接口只有一个抽象方法

由于default方法有一个实现,所以他们不是抽象的.如果一个接口定义了一个抽象方法,而他恰好覆盖了Object的public方法,仍旧不算做接口的抽象方法, 因为它终将会在某处得到一个实现.(如果不是public的那么计数) 也即是只有一个抽象方法默认不算,Object的public也不算 

函数式接口的实例可以通过 lambda表达式  方法引用 或者构造方法引用进行表示
类型必须是接口,而不能是其他的比如class 而且需要符合函数式接口的定义要求 否则使用注解时编译器报错
不管他们是否有使用注解FunctionalInterface 进行注解, 编译器将会把任何满足函数式接口定义的接口当做一个函数式接口 也就是说不加也行,但是显然不加的话,就没有限制约束,后续可能增加了其他方法导致出错

常用函数式接口

四大基础接口   java.util.function 包         接口                           抽象方法

  • Predicate<T>           boolean test(T t);
  • Consumer<T>          void accept(T t);
  • Function<T, R>        R apply(T t);
  • Supplier<T>             T get();

 java.util.function.Predicate<T>断言 也就是条件测试器 接收条件,进行测试接口定义了一个名叫test的抽象方法,它接受泛型T对象,并返回一个boolean。test (条件测试) , and-or- negate(与或非) 方法java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

java.util.function.Consumer<T>

消费者 消费数据 接收参数,返回void  数据被消费了定义了一个名叫accept的抽象方法,它接受泛型T的对象,没有返回(void)你如果需要访问类型T的对象,并对其执行某些操作,就可以使用这个接口java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

java.util.function.Function<T, R>函数 有输入有输出 数据转换功能接口定义了一个叫作apply的方法,它接受一个泛型T的对象,并返回一个泛型R的对象。java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

java.util.function.Supplier<T>
提供者 不需要输入,产出T 提供数据
无参构造方法 提供T类型对象

java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

为什么要有基本类型扩展

只有对象类型才能作为泛型参数,对于基本类型就涉及到装箱拆箱的操作,虽然是自动的但是这不可避免给内存带来了额外的开销,装箱和拆箱都会带来开销所以为了减小这些性能开销   对基本类型进行类型扩展Stream 类的某些方法对基本类型和装箱类型做了区分Java 8中,仅对 整型长整型双浮点型做了特殊处理  因为它们在数值计算中用得最多 对基本类型做特殊处理的方法在命名上有明确的规范

  • 如果参数是基本类型,则不加前缀只需类型名即可
  • 如果方法返回类型为基本类型,则在基本类型前再加上一个 To

总结一句话:

加了类型前缀[Int|Double|Long] 表示参数是基本类型, 如果在此基础上又加上了To  表示返回类型是基本类型 

如有可能,应尽可能多地使用对基本类型做过特殊处理的方法,进而改善性能 

函数式接口的实例

函数式接口的实例可以通过 lambda表达式  方法引用 或者构造方法引用进行表示

Lambda表达式

可以把Lambda表达式理解为简洁地表示可传递的匿名函数的一种方式,也就是用来表示匿名函数它没有名称,但它有参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。特点

  • 匿名——我们说匿名,是因为它不像普通的方法那样有一个明确的名称:写得少而想得多!
  • 函数——我们说它是函数,是因为Lambda函数不像方法那样属于某个特定的类。但和方法一样,Lambda有参数列表、函数主体、返回类型,还可能有可以抛出的异常列表。
  • 传递——Lambda表达式可以作为参数传递给方法或存储在变量中。
  • 简洁——无需像匿名类那样写很多模板代码。

基本语法 Lambda的基本语法是

(parameters) -> expression

或(请注意语句的花括号)

(parameters) -> { statements; } 

 Lambda表达式三个部分

  1. 参数列表
  2. 箭头   ( -> 把参数列表与Lambda主体分隔开)
  3. Lambda主体 (表达式或者语句)

1.  表达式不包含参数,使用空括号 () 表示没有参数         () -> System.out.println(“Hello World”);      2.  包含且只包含一个参数,可省略参数的括号                s  -> System.out.println(“Hello World”); 3.  Lambda 表达式的主体不仅可以是一个表达式,而且也可以是一段代码块,使用大括号({})将代码块括起来 该代码块和普通方法遵循的规则别无二致,可以用返回或抛出异常来退出。 只有一行代码的 Lambda表达式也可使用大括号,用以明确 Lambda表达式从何处开始、到哪里结束。

() -> {

    System.out.print(“Hello”);

    System.out.println(” World”);

};

4. Lambda 表达式也可以表示包含多个参数的方法   (Long x, Long y) -> x + y; 5.可以把  4  中的表达式进行简化,(x, y) -> x + y;    这借助于类型推断 下面会说到   Lambda只能引用值,而不是变量(要求事实上的final)匿名内部类,需要引用它所在方法里的变量时,需要将变量声明为 final Lambda表达式不要求必须是final 变量  但是,该变量在既成事实上必须是final 事实上的 final 是指只能给该变量赋值一次。换句话说,Lambda 表达式引用的是值,而不是变量 跟匿名内部类类似,使用的是变量值的拷贝 所以需要是不改变的如果你试图给该变量多次赋值,然后在 Lambda 表达式中引用它,编译器就会报错比如:java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口无需设置final 一切运行正常java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口一旦给hello变量重新赋值 ,编译器将会报错java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口   

方法引用

方法引用让你可以重复使用现有的方法定义  并像Lambda一样传递它们方法引用使用  :: 来表示方法引用主要有三类(1) 指向静态方法的方法引用(例如Integer的parseInt方法, 写作Integer::parseInt)       也就是静态方法作用于对象上 java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口示例:字符串转换为数值java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口   (2)指向 任意类型实例方法 的方法引用(例如 String 的 length 方法,写作String::length)  你在引用一个对象的方法,而这个对象本身是Lambda的一个参数。例如,Lambda表达式(String s) -> s.toUppeCase()   可以写作String::toUpperCase   java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口 示例:打印字符串的长度 1个 3个  2个   (没有空格和换行所以挤在一起了)java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口  (3) 指向现有对象的实例方法的方法引用比如lambda表达式中调用字符串helloString的charAt()方法  helloString就是一个现有对象java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口示例:获取字符串位于给定序列的charAt值java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口 

构造函数引用

对于一个现有构造函数,你可以利用它的名称和关键字new来创建它的一个引用:ClassName::new它的功能与指向静态方法的引用类似 定义Class A   三个属性 设置了默认值 以观察构造方法的调用情况java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口

class A {
private String s1="a";
private String s2="b";
private String s3="c";
A(){
}
A(String s1){
this.s1=s1;
}A(String s1,String s2){
this.s1=s1;
this.s2=s2;
}
A(String s1,String s2,String s3){
this.s1=s1;
this.s2=s2;
this.s3=s3;
}@Override
public String toString() {
final StringBuilder sb = new StringBuilder("A{");
sb.append("s1='").append(s1).append('\'');
sb.append(", s2='").append(s2).append('\'');
sb.append(", s3='").append(s3).append('\'');
sb.append('}');
return sb.toString();
}
}

java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口可以看到分别调用了,无参构造方法 一个参数构造方法以及两个参数构造方法 如果三个构造方法如何设置呢?我们只需要定义函数接口即可java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口 java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口再次运行java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口   

类型检查与类型推断

 

类型检查

我们知道当我们操作赋值运算时会有类型检查比如:java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口那么对于函数式接口与函数值呢 

函数式接口 变量名 = Lambda-匿名函数/方法引用/构造方法引用;

 那么函数作为值是如何进行类型检查的? Lambda的类型是从使用Lambda的上下文推断出来的上下文中Lambda表达式需要的类型称为目标类型上下文是比如接受它传递的方法的形式参数,或接受它的值的局部变量形式参数或者局部变量都会有类型的定义与声明 比如筛选 1~9之中小于5的数值

List<Integer> listNum = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

List filteredNum = listNum.stream().filter(i -> i.compareTo(5) <0).collect(Collectors.toList());

System.out.println(filteredNum);

java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口这个示例中接收  Lambda表达式  作为参数的形式参数为  Predicate<? super T> predicate也就是目标类型    函数接口为Predicate<T> 找到了目标类型 我们的T为Integer也就是Predicate<Integer> 他的抽象方法为 boolean test(T t);   也就是  boolean test(Integer t);  接收一个Integer返回一个boolean我们的Lambda匿名函数 i -> i.compareTo(5) < 0 就是接收一个Integer  返回一个boolean 所以类型检查通过简单说就是:

1. 通过形参类型或者变量类型 找到函数接口进而找到抽象方法的声明2. 然后在与参数值进行比对查看是否匹配

 可以看得出来,Lambda表达式最终匹配的是 函数接口中的抽象方法的方法签名

如果不同的函数接口,具有相互兼容的抽象方法签名  那么一个Lambda表达式显然可以匹配多个函数接口

 

特殊的void兼容规则如果一个Lambda的主体是一个语句表达式, 它就和一个返回void的函数描述符兼容(当然需要参数列表也兼容)。就是说 如果主体是一个语句,不管做什么或者调用方法返回其他的类型,他都可以兼容void

 例如List的add方法   boolean add(E e);

List<String> list= new ArrayList<>();

// Predicate返回了一个boolean

Predicate<String> p = s -> list.add(s);

// Consumer返回了一个void

Consumer<String> b = s -> list.add(s);

上面的代码都可以通过编译,并且运行 

类型推断

 类型推断的概念,在Java中不是第一次出现Java SE 7之前,声明泛型对象的代码如下

List<String> list = new ArrayList<String>();

Java 7中,可以使用如下代码:

List<String> list = new ArrayList<>();

这就是类型推断  ,一个最直接直观的好处就是可以简化代码的书写,这不就是语法糖么 针对 Lambda表达式也有类型推断Java编译器可以根据  上下文(目标类型)推断出用什么函数式接口来配合Lambda表达式然后就可以获取到函数接口对应的函数描述符也就是那个抽象方法的方法签名编译器可以了解Lambda表达式的参数类型,这样就可以在Lambda语法中省去标注参数类型  比如刚才的筛选 1~9之中小于5的数值的例子中,就可以有如下几种写法

.filter((Integer i) -> { return i.compareTo(5) < 0;}).collect(Collectors.toList());

.filter((Integer i) ->i.compareTo(5) < 0).collect(Collectors.toList());

.filter(i ->i.compareTo(5) < 0).collect(Collectors.toList());

  

如何使用函数式接口

 函数式接口定义了函数的类型   有了类型就如同其他类型 比如 int 一样  你可以定义变量你可以传递参数你可以返回 一个函数方法有方法签名和方法体两部分内容组成函数接口只是有了方法签名方法体由函数式接口的实例传递(也就是Lambda表达式-匿名函数   方法引用 构造方法引用 )具体的调用则是调用抽象方法  抽象方法的方法体就是函数式接口的实例比如:定义一个函数式接口,也可以使用预置的 比如 Predicate等java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口 然后就是定义变量 使用Lambda实例化再接着就是方法调用java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口java8函数式接口详解、函数接口详解、lambda表达式匿名函数、方法引用使用含义、函数式接口实例、如何定义函数式接口  

转自:https://www.cnblogs.com/noteless/p/9501253.html

Java 8 函数式接口 : Supplier、Function、Consumer、Predicate

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,075
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,551
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,399
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,176
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,811
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,893