四大函数式接口指的是Consumer、Function、Predicate、Supplier,位于java.util.function包下:

函数式编程

lamabda表达式

函数式接口:在java中是指:有且仅有一个抽象方法的接口。也即适用于函数式编程场景的接口。而Java中的函数式编程体现就是Lambda,所以函数式接口就是可以适用于Lambda使用的接口。

lambda表达式表示函数式接口的实例。

lambda表达式的类型是一个函数式接口类型。

备注:“语法糖"是指使用更加方便,但是原理不变的代码语法。例如在遍历集合时使用的for-each语法,其实底层的实现原理仍然是迭代器,这便是“语法糖”。从应用层面来讲,Java中的Lambda可以被当做是匿名内部类的“语法糖”,但是二者在原理上是不同的。

以下是这种函数式接口的示例:

@FunctionalInterface
interface Processor {
int getStringLength(String str);
}

我们可以为其函数式接口实例赋值lambda表达式。

Processor stringProcessor = (String str) -> str.length();

函数式接口格式:接口中只能存在一个抽象方法

修饰符 interface 接口名称{
public abstract 返回值 方法名称(参数列表)
// 其他方式
}
// public abstract 可以不写 编译器自动加上
修饰符 interface 接口名称{
返回值 方法名称(参数列表)
// 其他方式
}

方法前面的public abstract 可以不写,编译器会自动加上

@FunctionalInterface注解

@FunctionalInterface // 标明为函数式接口
public abstract MyFunctionInterface{
void method(); //抽象方法
}

一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法,否则将会报错。需要注意的是,即使不使用该注解,只要满足函数式接口的定义,这仍然是一个函数式接口,使用起来都一样。(该接口是一个标记接口)

Javadoc关于函数式接口的规范

An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface as defined by the Java Language Specification.Conceptually, a functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract. If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface’s abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.
 
Note that instances of functional interfaces can be created with lambda expressions, method references, or constructor references.
 
If a type is annotated with this annotation type, compilers are required to generate an error message unless:
• The type is an interface type and not an annotation type, enum, or class.
• The annotated type satisfies the requirements of a functional interface.
 
However, the compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a Functional Interface annotation is present on the interface declaration.

根据Java语言规范的定义,一个使用了该注释的接口类型声明将被视为一个函数式接口。从概念上讲,一个函数式接口有且只有一个抽象方法。由于默认方法(default)已经有了实现,所以它们不是抽象方法。

如果一个接口中声明的抽象方法是重写了超类Object类中任意一个public方法,那么这些抽象方法并不会算入接口的抽象方法数量中。

因为任何接口的实现都会从其父类Object或其它地方获得这些方法的实现。
        注意:函数式接口的实现可以由Lambda表达式方法引用构造器引用等方式实现。
        如果一个类型使用了该注释@FunctionalInterface,除非这个类型是一个接口类型(而不是一个注释类型、枚举或类),否则编译器将会生成一个错误信息。同时使用该注释的接口满足函数式接口的要求,即一个函数式接口有且只有一个抽象方法。

但是编译器会将所有定义为函数式接口(满足函数式接口要求)的接口视为函数式接口,而不管这个接口声明中是否使用了函数式接口的注释(即@FunctionalInterface)。
 从中我们可以知道:

  • 一个函数式接口有且只有一个抽象方法。
  • 默认方法不是抽象方法,因为它们已经实现了。
  • 重写了超类Object类中任意一个public方法的方法并不算接口中的抽象方法。

比如Comparator接口,这是jdk当中的一个函数式接口:

Comparator的接口方法(含有大量的default方法):

含有两个抽象方法(虽然没有被显示声明为abstract):

compare(T o1,T o2),equals(Object obj)

Java8中的函数式接口定义是只有一个抽象方法的接口,但是这个Comparator中,好像是有多个抽象方法,为什么它也叫函数式接口呢?。

但是实际上只有一个:int compare(T o1,T o2)

defualt方法  默认方法有点类似静态方法。

equals方法是Object的方法。所以虽然Comparator接口中有两个抽象方法compare和equals,但equals并不算入接口中的抽象方法,所以Comparator接口还是满足函数式接口的要求,Comparator接口是一个函数式接口。

使用Lambda进行传参

假设有一个 方法使用该函数式接口作为参数,那么就可以使用Lambda进行传参.如线程中的Runable接口

public class Test_Functional {
// 定义一个含有函数式接口的方法
public static void doSomthing(MyFunctionalInterface functionalInterface) {
functionalInterface.method();//调用自定义函数式接口的方法
}
public static void main(String[] args) {
//调用函数式接口的方法
doSomthing(()->System.out.println("excuter lambda!"));
}
} @FunctionalInterface // 标明为函数式接口
public abstract MyFunctionInterface{
void method(); //抽象方法
}

使用Lambda作为返回值

如果一个方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式

public class lambda_Comparator {
//下面给出 lambda 以及实际替代的内部类写法
private static Comparator<String> newComparator(){
return (a,b)->b.length()-a.length();
}
private static Comparator<String> newComparator1(){
return new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.length()-a.length();
}
};
}
public static void main(String[] args) {
String[] array={"abc","ab","abcd"};
System.out.println(Arrays.toString(array));
Arrays.sort(array, newComparator1()); // 方式一
Arrays.sort(array,(a,b)->b.length()-a.length());//更简单的方式
System.out.println(Arrays.toString(array));
}
}

Arrays.sort(...)其中的一种参数形式如下:

sort(T[] a, Comparator<? super T> c)//根据指定的比较器引发的顺序对指定的对象数组进行排序。 

常用函数式接口

在上面简单介绍了一些Lambda表达式得好处与语法,我们知道使用Lambda表达式是需要使用函数式接口的,那么,岂不是在我们开发过程中需要定义许多函数式接口。

其实不然,java8其实已经为我们定义好了4类内置函数式接口,这4类接口其实已经可以解决我们开发过程中绝大部分的问题,只有一小部分比较特殊得情况需要我们自己去定义函数式接口,下面就简单来学习一下java8内置得4大核心函数式接口。

Consumer<T>:消费型接口(void accept(T t))

/**
* 消费型接口Consumer<T>
*/
@Test
public void test1 () {
consumo(500, (x) -> System.out.println(x));
} public void consumo (double money, Consumer<Double> c) {
c.accept(money);
}

以上为消费型接口,有参数,无返回值类型的接口。

Supplier<T>:供给型接口(T get())

  来看一个简单得例子:

/**
* 供给型接口,Supplier<T>
*/
@Test
public void test2 () {
Random ran = new Random();
List<Integer> list = supplier(10, () -> ran.nextInt(10)); for (Integer i : list) {
System.out.println(i);
}
} /**
* 随机产生sum个数量得集合
* @param sum 集合内元素个数
* @param sup
* @return
*/
public List<Integer> supplier(int sum, Supplier<Integer> sup){
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < sum; i++) {
list.add(sup.get());
}
return list;
}

上面就是一个供给类型得接口,只有产出,没人输入,就是只有返回值,没有入参

Function<T, R>:函数型接口(R apply(T t))

  下面看一个简单的例子:

/**
* 函数型接口:Function<R, T>
*/
@Test
public void test3 () {
String s = strOperar(" asdf ", x -> x.substring(0, 2));
System.out.println(s);
String s1 = strOperar(" asdf ", x -> x.trim());
System.out.println(s1);
} /**
* 字符串操作
* @param str 需要处理得字符串
* @param fun Function接口
* @return 处理之后得字符传
*/
public String strOperar(String str, Function<String, String> fun) {
return fun.apply(str);
}

上面就是一个函数型接口,输入一个类型得参数,输出一个类型得参数,当然两种类型可以一致。

Predicate<T>:断言型接口(boolean test(T t))

  下面看一个简单得例子:

/**
* 断言型接口:Predicate<T>
*/
@Test
public void test4 () {
List<Integer> l = new ArrayList<>();
l.add(102);
l.add(172);
l.add(13);
l.add(82);
l.add(109);
List<Integer> list = filterInt(l, x -> (x > 100));
for (Integer integer : list) {
System.out.println(integer);
}
} /**
* 过滤集合
* @param list
* @param pre
* @return
*/
public List<Integer> filterInt(List<Integer> list, Predicate<Integer> pre){
List<Integer> l = new ArrayList<>();
for (Integer integer : list) {
if (pre.test(integer))
l.add(integer);
}
return l;
}

上面就是一个断言型接口,输入一个参数,输出一个boolean类型得返回值。

其他类型的一些函数式接口

除了上述得4种类型得接口外还有其他的一些接口供我们使用:

    1).BiFunction<T, U, R>

      参数类型有2个,为T,U,返回值为R,其中方法为R apply(T t, U u)

    2).UnaryOperator<T>(Function子接口)

      参数为T,对参数为T的对象进行一元操作,并返回T类型结果,其中方法为T apply(T t)

    3).BinaryOperator<T>(BiFunction子接口)

      参数为T,对参数为T得对象进行二元操作,并返回T类型得结果,其中方法为T apply(T t1, T t2)

    4).BiConsumer(T, U)

      参数为T,U无返回值,其中方法为 void accept(T t, U u)

    5).ToIntFunction<T>、ToLongFunction<T>、ToDoubleFunction<T>

      参数类型为T,返回值分别为int,long,double,分别计算int,long,double得函数。

    6).IntFunction<R>、LongFunction<R>、DoubleFunction<R>

      参数分别为int,long,double,返回值为R。

以上就是java8内置得核心函数式接口,其中包括了大部分得方法类型,所以可以在使用得时候根据不同得使用场景去选择不同得接口使用。

Java新特性-四大函数式接口的更多相关文章

  1. 乐字节-Java8新特性之函数式接口

    上一篇小乐带大家学过 Java8新特性-Lambda表达式,那什么时候可以使用Lambda?通常Lambda表达式是用在函数式接口上使用的.从Java8开始引入了函数式接口,其说明比较简单:函数式接口 ...

  2. Java 8新特性-1 函数式接口

    Java 8 引入的一个核心概念是函数式接口(Functional Interfaces). 通过在接口里面添加一个抽象方法,这些方法可以直接从接口中运行. 如果一个接口定义个唯一一个抽象方法,那么这 ...

  3. Java(44)JDK新特性之函数式接口

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201667.html 博客主页:https://www.cnblogs.com/testero ...

  4. Java8新特性之函数式接口

    <Java 8 实战>学习笔记系列 定义 函数式接口只定义一个抽象方法,可以有多个默认方法 函数式接口的接口名上,会被@FunctionalInterface标注 作用 函数式接口的方法可 ...

  5. JDK8新特性:函数式接口@FunctionalInterface的使用说明

    我们常用的一些接口Callable.Runnable.Comparator等在JDK8中都添加了@FunctionalInterface注解. 通过JDK8源码javadoc,可以知道这个注解有以下特 ...

  6. jdk1.8新特性之函数式接口

    函数式接口就是只有一个抽象方法的接口.如果这个接口里没有或者包含了两个以上的抽象方法,对不起,你不叫函数式接口,只能叫你接口.那这个函数式有啥用呢?如果配合Lambda表达式的话,可以大大的简化代码. ...

  7. JDK8新特性:函数式接口

    一,定义 函数式接口,英文为Functional Interface.首先它是一个接口,那么它与其它接口有什么不同呢?不同点就是在这个接口中只允许有一个抽象方法. 这里的只允许一个抽象方法不包括以下几 ...

  8. JDK8新特性之函数式接口

    什么是函数式接口 先来看看传统的创建线程是怎么写的 Thread t1 = new Thread(new Runnable() { @Override public void run() { Syst ...

  9. Java JDK1.8新特性之四大函数式接口

    JDK 1.8的一些新特性 四大核心函数式接口(Consumer.Predicate.Supplier.Function),结合lambda表达式 import java.util.ArrayList ...

  10. 第46天学习打卡(四大函数式接口 Stream流式计算 ForkJoin 异步回调 JMM Volatile)

    小结与扩展 池的最大的大小如何去设置! 了解:IO密集型,CPU密集型:(调优)  //1.CPU密集型 几核就是几个线程 可以保持效率最高 //2.IO密集型判断你的程序中十分耗IO的线程,只要大于 ...

随机推荐

  1. 【转载】How to Use t-SNE Effectively —— (机器学习数据可视化) t-SNE使用指南

    原文地址:https://distill.pub/2016/misread-tsne/ 说明: 原文是比较有名的一个指南性博文,讲的就是t-SNE技术的一些使用注意事项和说明,属于说明性文章,内容很不 ...

  2. js 实现俄罗斯方块(三)

    我又来啦!上一篇有点水,本篇我们来干货! 嘿嘿,首先我们先搭建游戏世界------网格 所有的操作包括左移右移下移旋转都是在这个网格中 既然是使用js来写当然跑不了html啦,实现网格最简单的 方法就 ...

  3. java中的几种锁

    一.公平锁/非公平锁 公平锁是指多个线程按照申请锁的顺序来获取锁. 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁.有可能,会造成优先级反转或者饥饿 ...

  4. 第 111 场双周赛 - 力扣(LeetCode)

    第 111 场双周赛 - 力扣(LeetCode) 2824. 统计和小于目标的下标对数目 - 力扣(LeetCode) 枚举即可 class Solution { public: int count ...

  5. mmdetection使用未定义backbone训练

    首先找到你需要用到的 backbone,一般有名的backbone 都会在github有相应的代码开源和预训练权重提供 本文以mobilenetv3 + fastercnn 作为举例,在mmdetec ...

  6. JavaScript设计模式样例十二 —— 享元模式

    享元模式(Flyweight Pattern) 定义:减少创建对象的数量,以减少内存占用和提高性能.目的:用共享技术有效地支持大量细粒度的对象.场景:系统中有大量对象. // 构建享元对象 class ...

  7. 使用 python flask 框架实现一个简单的抽奖系统

    Flask 实现一个简易的抽奖系统 项目前置知识 目前 python主流的框架: Django .flask .Tornado 简介: 1.框架 框架? 为什莫使用框架? (前置知识讲解比较冗杂,望谅 ...

  8. Clion+OpenCV(C++版)开发环境配置教程WinMac

    Clion+OpenCV(C++版)开发环境配置教程Win/Mac 平时在学习和比赛的时候都是使用的Python版本的OpenCV,最近遇到了一个项目使用的上位机性能有限于是决定视觉方面使用C++的O ...

  9. python pyqt6 颜色弹窗 QColorDialog

    def setColor(self): # 避免窗口置顶后,Dialog被主窗口覆盖,所以需要传递self # 设定默认颜色使用getColor的第一个参数(使用setCurrentColor不生效) ...

  10. .NET 最好用的验证组件 FluentValidation

    前言 一个 .NET 验证框架,支持链式操作,易于理解,功能完善,组件内提供十几种常用验证器,可扩展性好,支持自定义验证器,支持本地化多语言. 项目介绍 FluentValidation 是一个开源的 ...