Java8 新特性 函数式接口

Wesley13
• 阅读 622

什么是函数式接口

  函数式接口是Java8引用的一个新特性,是一种特殊的接口:SAM类型的接口(Single Abstract Method)。但是它还是一个接口,只是有些特殊罢了。  函数式接口的出现主要是为了配合Java8的另一个新特性Lamdba表达式来使用。

  • 接口中只有一个抽象方法
  • 接口中面可以加一个注解*@FunctionalInterface*来检查接口中的方法是不是只有一个抽象方法
  • 在接口里面可以加入 默认方法静态方法
  • 函数式接口也可以继承,但是继承的时候,抽象方法必须一样
  • 函数式接口重写父类的的方法,并不会计入到自己的抽象方法中

自定义函数式接口

//加入这个注解是为了检测接口中是否符合函数式接口的要求
@FunctionalInterface
public interface MyFunctionInterction {
    //唯一的抽象方法
    void absoluMethod();

    //重写Object的方法
    @Override
    String toString();

    //默认方法
    default void defaultMethod() {
        System.out.println("默认方法");
    }

    //静态方法
    static void stativMethod() {
        System.out.println("静态方法");
    }
}

函数式接口的简单使用

里面的默认方法可以直接使用


public class TestFunctionIntection {
    public static void main(String[] args) {
        TestFunctionIntection testFunctionIntection = 
                new TestFunctionIntection();
        testFunctionIntection.test(
                //Lamdba表达式的简单使用
                () -> System.out.println("函数式接口里面的抽象方法"));
    }

    /**
     * 自己定义的一个方法,并使用自定义的一个消费类型的函数式接口
     * @param myFunctionInterction
     */
    public void test(MyFunctionInterction 
                             myFunctionInterction) {

        //函数式接口里面的抽象方法
        myFunctionInterction.absoluMethod();

        //默认方法
        myFunctionInterction.defaultMethod();

        //静态方法
        MyFunctionInterction.stativMethod();
    }
}

java8里面自定义的四个核心的函数式接口

上面我自定义的一个接口,就是一个消费类型的函数式接口。其实这类接口在_java.util.function_里面有定义的,就是void Consumer< T >,消费类型接口,上面代码中的test方法里面的接口其实可以换成Consumer< T >接口,也可以用,下面主要就是介绍这四个函数式接口的简单使用。

Java8 新特性 函数式接口

下面是这四个核心接口的简单使用

public class FunctionTest {
    //Consumer<T> 消费型接口
    @Test
    public void test1() {
        Consumer<String> consumer = (x) -> System.out.println(x);
        consumer.accept("消费型接口,没有返回值!");
    }
    //输出:消费型接口,没有返回值!

    //供给型接口
    @Test
    public void test2() {
        Supplier<String> supplier = () -> "主要的作用就是创建对象!";
        String s = supplier.get();
        System.out.println(s);
    }
    //输出:主要的作用就是创建对象!

    //函数型接口
    //Function<T,R> T 接收的参数,R 返回值类型
    @Test
    public void test3() {
        Function<Integer, String> function = (x) -> x + ":为String类型";
        String apply = function.apply(7);
        System.out.println(apply);
    }
    //输出:7:为String类型    

    //断言型接口
    @Test
    public void test4() {
        Predicate<Integer> predicate = (x) -> x > 10;
        boolean test = predicate.test(11);
        System.out.println(test);
    }
    //输出:true
}

Consumer 的应用

//Consumer<T> 消费型接口
    @Test
    public void test1() {
        //定义一个消费型接口,只输出输入的内容
        Consumer<String> consumer = (x) -> System.out.println(x);
        //在输入的内容后面加上·--加上了默认方法·
        Consumer<String> consumer2 = (x) -> System.out.println(x + "--加上了默认方法");
        //执行顺序  先执行 accept 后面执行 addThen(然后) 
        consumer.andThen(consumer2).accept("消费型接口,没有返回值!");
    }
    //输出:消费型接口,没有返回值                     (accept输出的值) 
    //输出:消费型接口,没有返回值 !--加上了默认方法 (addThen输出的值)

Consumer 的默认方法的源码:

default Consumer<T> andThen(Consumer<? super T> after) {
    Objects.requireNonNull(after);
    return (T t) -> { accept(t); after.accept(t); };
}

  其返回值这一句是重点,先是传入一个Consumer接口,然后返回一个Consumer接口,说明可以用表达式链,然后用这个特性可以把数据进一次进行加工。   (T t) -> { accept(t); after.accept(t); };这一句,返回的顺序首先是调用抽象方法,然后再调用默认方法,说明这个默认方法只可以对数据进行再加工,不能再抽象方法前面。


Supplier 的应用

    //供给型接口,这个方法若以用在工厂方法中
    @Test
    public void test2() {
        //跟据一个字符串创建对象
        Supplier<String> supplier = () -> "主要的作用就是创建对象!";
        //获取一个对象
        String s = supplier.get();
        //获取两个以象
        String s1 = supplier.get();
        //两个对象内容一样
        System.out.println(s.equals(s1));
        System.out.println(s);
        //用方法引用的方式创建一个对象
        Supplier<SupplierTest> testSupplier = SupplierTest::new;
        //用new的方式创建一个对象
        Supplier<SupplierTest> supplierTestSupplier = () -> new SupplierTest("张三");
        //可以通过supplierTestSupplier 来获取一个对象,并且可以调用里面的方法
        String name = supplierTestSupplier.get().getName();
        System.out.println(name);
    }
    //输出:true
    //输出:主要的作用就是创建对象!
    //输出:张三

  Supplier< T >接口类型就有一个方法签名。T get()方法,没有默认方法。


Function< T,R > 的应用

//默认主法addThen
//函数型接口
    //Function<T,R> T 接收的参数,R 返回值类型
    @Test
    public void test3() {
        Function<String, String> f1 = (x) -> x +"+ ";
        Function<String, String> f2 = (x) -> x + "- ";
        //addThen(然后的意思)执行顺序先执行f1,并且把执行后的结果作为f2的输入参数
        String apply = f1.andThen(f2).apply("1");
        System.out.println(apply);
    }
    //输出:1+ -

addThen的源码:

default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
    Objects.requireNonNull(before);
    return (V v) -> apply(before.apply(v));
}

源码中最重要的一句

(V v) -> apply(before.apply(v)); 规定了执行顺序

    //默认主法compose
    //函数型接口
    //Function<T,R> T 接收的参数,R 返回值类型
    @Test
    public void test3() {
        Function<String, String> f1 = (x) -> x +"+ ";
        Function<String, String> f2 = (x) -> x + "- ";
        //addThen(然后的意思)执行顺序先执行f2,并且把执行后的结果作为f1的输入参数
        String apply = f1.compose(f2).apply("1");
        System.out.println(apply);
    }
    //输出:1- +

  三个默认方法,但是最后一个用的不多,这里也就不再介绍了。


Predicate< T > 的应用

//默主方法negate 非
//断言型接口
    @Test
    public void test4() {
        Predicate<Integer> predicate = (x) -> x > 10;
        boolean test = predicate.negate().test(11);
        System.out.println(test);
    }
    //输出:false


    //断言型接口
    //默认方法 or 和 and
    @Test
    public void test4() {
        Predicate<Integer> p1 = (x) -> x > 10;
        Predicate<Integer> p2 = (x) -> x < 5;
        //默认方法 or 或
        boolean test = p1.or(p2).test(3);
        //默认方法 and 且
        boolean test2 = p1.and(p2).test(3);

        System.out.println(test);
        System.out.println(test2);
    }
    //输出:true
    //输出:false

函数式接口的使用

  函数式接口的的使用,大部分都是在流操作里面进行,现在可以不太理解,但是可以在学习完流操作以后,再过来看,并且跟着写一遍。代码光看是没有用的。如果不写是不知道意思的。

参考的博客:浅浅的函数式接口



细节决定成败! 个人愚见,如有不对,恳请扶正!

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java Lambda表达式
简介  Lambda可以理解为简洁的表示可传递的匿名函数,包括:参数列表、函数主体、返回类型、抛出的异常列表(可以不存在)。  函数式接口:定义一个抽象方法的接口(接口可以拥有默认方法:default)。  函数式接口有什么用?    Lambda可以以内联的形式为函数式接口的抽象方法提供实现。虽然内部类也可以实现,但lambda表达
Wesley13 Wesley13
3年前
java8函数式接口
转自:https://blog.csdn.net/u012706811/article/details/77096257(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fblog.csdn.net%2Fu012706811%2Farticle%2Fdetails%2F77096257)
Wesley13 Wesley13
3年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Wesley13 Wesley13
3年前
Java8函数式编程(A)
将行为作为数据传递函数编程的最直接的表现,莫过于将函数作为数据自由传递,结合泛型推导能力,使代码表达能力获得飞一般的提升。Java8怎么支持函数式编程?主要有三个核心概念:函数接口(Function)流(Stream)聚合器(Collector)函数接口关于函数接口,两件事:函数接口是行为
Wesley13 Wesley13
3年前
Java8之Stream
在使用Stream之前先介绍几个概念:1、函数式接口2、常用的函数式接口3、Lambda4、方法引用 1、函数式接口  1.只定义了一个抽象方法的接口。  2.JDK8接口中的静态方法和默认方法,都不算是抽象方法。  3.接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,
Wesley13 Wesley13
3年前
Java8—一万字的Lambda表达式的详细介绍与应用案例
  基于Java8详细介绍了lambda表达式的语法与使用,以及方法引用、函数式接口、lambda复合等Java8的新特性!文章目录1Lambda的概述2函数式接口2.1Consumer消费型接口2.2Supplier供给型接口2.3Function<T,R函数型接口
Wesley13 Wesley13
3年前
Java8新特性学习
1简述公司自年初终于开始使用java8作为项目的标准jdk,在开发过程中,逐渐认识到java8的很多新特性,确实很方便.其中内容的核心,在于函数式编程,即将函数本身作为对象参数去处理.其中涉及到三个关键新特性:1.lambda表达式(及函数式接口)2.stream3.方法引用这三个新特性的使用是相辅相