函数式接口

函数式接口
概念

函数式接口在JAVA中指的是:有且仅有一个抽象方法的接口就称为函数式接口。(接口当中可含有其他方法:默认、静态、私有。。。。)
函数式接口,适用于函数式编程的,在Java当中的函数式编程体现在Lambda,所以函数式接口就是用来服务lambda表达式,只有确保接口当中有且仅有一个抽象方法,那么在Java中Lambda才能顺利的进行推导。
备注:“语法糖"是指使用更加便利方便,但是原理不变的代码语法。就比如遍历集合的时候使用for -each语法,其实底层使用的事迭代器,这便是"语法糖”。

格式:
只有确保接口当中有且仅有一个抽象方法即可:

修饰符 interface InterfaceName{
      //只能定义一个抽象方法
      public abstract 返回值类型 方法名称(参数列表);
      //还可以定义其他的非抽象方法
}

示例

public interface FunctionInterfaceOne{
    public abstract void show01();
    public default void show02(){
       //.....
    }
    //void show03();此时就不是了,有且仅有一个抽象方法,才能成为函数式接口


}

@FunctionalInterFace注解(可确保接口是函数式接口(是:编译通过,否:编译不通过))
与@Override注解作用类似,Java 8 中专门为函数式接口引入一个新注解@FunctionalInterFace,该注解主要定义在接口上。一旦在接口上使用该注解,编译期将会强制检查该接口是不是一个函数式接口,该接口中是不是有且仅有一个抽象方法,如果不是,编译报错

@FunctionalInterFace
public interface FunctionInterfaceOne{
    //定义一个抽象方法
    void method();
    //void show();
    default void show02(){
    }
}

用途:
对于自定义的函数式接口:一般作为方法的参数和返回值使用的。

函数式编程

能够在兼顾java的面向对象的特性基础上,使用通过lambda表达式与方法引用,为开发者打开函数式编程的大门。

Lambda表达式的延迟加载
有些场景代码运行执行后,结果不一定会被使用到,从而造成性能的浪费,而lambda表达式是延迟执行的,正好可以解决此问题,提升一定性能。

代码:

备注:实际上使用内部类也可以达到这样的效果,只是将代码操作延迟到另外一个对象当中通过调用方法来完成。后面的代码执行取决于前面的条件判断的结果。
使用Lambda作为方法的参数和返回值
在Java当中,lambda表达式是作为匿名内部类的替代品,如果一个方法的参数是一个函数式接口类型,那么可以使用Lambda表达式进行替代。
java.lang.Runnable接口就是一个函数式接口
代码如下:

public class DomeLambda{
    //定义一个开启线程的方法
    public static void startThread(Runnable r){
        new Thread(r).start();
    }
    public static void main (String[] args){
        startThread(() -> {
            System.out.println("开启一个新线程,线程任务被执行了!")
           
        });
        startThread(() ->System.out.println("开启一个新线程,线程任务被执行了!");
    }

}

如果一个方法的返回值类型是一个函数式接口,那么我们可以直接使用一个Lambda表达式
java.util.Comparator接口是一个函数个表达式
代码如下:

public class Dome02Lambda{
     //定义一个方法,方法的返回值式一个函数式接口类型Comparator
     public static Comparator<String> createComparator(){
     //返回值就是一个函数式接口
          return new Comparator(){
              @Override
              public int compare (String o1,String o2){
              //自定义比较的规则,升序降序
              //字符串长度
              return 01.length-o2.length();//升序
              }
          }
          //使用lambda
          return(o1,o2)->01.length-o2.length();
     }
     public static void main(String[] args){
         String[] strs={"aaa","a","ahgfgsj","gggg"};
         Arrays.sort(strs,createComparator());
         System.out.println(Arrays.toString(strs));//{"a","aaa","gggg","ahgfgsj"}
     }
} 

常用的函数式接口
JDK提供了大量常用的函数式接口,丰富Lambda表达式的使用场景。他们主要在java.util.function包中被提供。

Supplier接口
java.util.function.Supplier接口,该接口有且仅有一个无参的方法:T get()。用来获取一个泛型参数指定类型的对象数据。由于该接口是一个函数式接口,所以我们可以使用Lambda表达式来操作它。

Supplier接口被称之为生产型接口,指定接口的泛型是什么类型,那么接口中的get()方法就会生产什么类型的数据。

代码

//定义一个方法,方法参数传递一个Supplier<T>接口,泛型指定
public static String getString(Supplier<String> sup){
    return sup.get();
}

//定义一个方法,方法的参数传递一个Supplier<T>接口,
public static int getNum(Supplier<Integer> sup){
    return sup.get();
}

public static void main(String[] args) {
    //调用getString方法,方法的参数传递Supplier<T>是一个函数式接口,那么我们就可以使用Lambda
    String str = getString(() -> {
        return new String("你好java");
    });
    System.out.println(str);

    int arr[] = {10,20,30,5,7,8};

    int maxNum = getNum(() -> {
        //求出最大值
        int max = arr[0];
        for (int i : arr) {
        //判断
            if (max < i) {
                max = i;
            }
        }
        return max;
    });
    //输出最大值
    System.out.println(maxNum);//50
}

Consumer接口
java.util.function.Consumer刚好和Supplier相反,他不是用来生产一个数据的,而是用来消费一个数据,数据类型由泛型来指定。
accept方法
意思就是消费一个指定泛型的数据。
代码如下:

//accept()方法
// 消费一个指定类型的数据
/*
Consumer接口是一个消费接口,泛型指定什么数据类型,使用accept方法就消费什么样的类型
至于具体怎么消费(使用),需要自定义(统计,求和,输出。。。)
 */
 
//定义一个方法,方法的参数传递一个Consumer<String>接口,传递一个字符串变量
public static void consumer (Consumer<String> con,String str){
    //使用消费型接口对象,消费传递的字符串值
    con.accept(str);
}

public static void main(String[] args) {
    //来调用消费方法consumer,Consumer<String>接口是一个函数式接口,所以可以使用Lambda表达式
    consumer(name->{
        //把里面的abcdefg字符串改为大写输出消费的规则自定义
        String s = name.toLowerCase();
        //翻转字符串
        String s1 = new StringBuffer(s).reverse().toString();
        
        System.out.println(s1);//GFEDCBA
    },"abcdefg");
}

默认方法:andThen

如果一个方法的参数和返回值全都是Consumer类型,那么就可以实现这样的效果:消费数据的时候,首先先做一个消费的操作,再做一个消费的操作。实现组合。可以通过Consumer接口当中的默认方法:andThen来实现。

代码如下:

//定义一个方法,方法的参数传递一个字符串和两个Consumer接口。Consumer接口的泛型指定为字符串
public static void consumers(String str , Consumer<String> con1,Consumer<String> con2){
    /*con1.accept(str);
    con2.accept(str);*/
    //andThen连续消费 default Consumer<String> andThen
    //先执行左边的Consumer--con1动作,andThen---->再次执行Consuner--con2动作
    con1.andThen(con2).accept(str);
    //规则 con1连接con2,先执行con1消费数据,在执行con2消费数据
}

public static void main(String[] args) {
    //由于consumers方法的参数Consumer接口是一个函数式接口,可以使用Lambda表达式
    consumers("java31-中国最棒-都是业界大佬",(nameone)->{
        //消费规则
        //截取传入的字符串
        String sub = nameone.substring(0, 6);
        System.out.println(sub);

    },(nametwo)->{
        //定义消费规则
        String[] str = nametwo.split("-");
        System.out.println(Arrays.toString(str));
    });
}

通过查看源码得知:andThen方法不允许传入一个null对象,否则就会抛出空指针异常。
要想把两次消费的动作连接起来,需要传入两个Consumer接口,通过andThen方法实现一步一步执行消费动作。

Stream流
在java1.8中,由于Lambda表达式这种函数式编程,JDK引入了一个全新的概念"Stream流"。用于解决已有集合类库的一些弊端的。
给定你一些集合的数据

public class Dome01Stream{
    public static void main(String[] args){
        //构建一个集合
        List<String> list = new ArratList<String>();
        list.add("abc123");
        list.add("aaa22");
        list.add("bcd125");
        list.add("abcd120");
        list.add("bbb230");
        //我需要字符串中包含1的元素取出来
        List<String> list2 = new ArratList<String>();
        for(String str:lis){
            if(str.contains("1")){
                 list2.add(str);
            }
        }
        //需要字符串长度不能超过6个的元素取出来
        List<String> list3 = new ArrayList<String>();
        for(String str:list2){
            if(str.length()<=6){
            list3.add(str);
            }
        }
        //遍历查看最终想要的元素集合
        for(String str:list3){
        System.out.println(str)
        }
    }
}

当我们需要对集合中的元素进行操作的时候,总是需要对集合循环遍历,再次循环遍历…
一定需要这样做吗?不一定!
它只是用来找到你需要元素的一种方式,并不是一种目的,我只想遍历一次就能实现效果。目的就是想要取出想要的元素并且循环打印出来。以往的方式就是每次循环都需要重头开始遍历,下一次循环还是重头开始
Java1.8可以使用Lambda表达式来优化你遍历集合的方式。
代码如下:

public class Dome01Stream{
    public static void main(String[] args){
        //构建一个集合
        List<String> list = new ArratList<String>();
        list.add("abc123");
        list.add("aaa22");
        list.add("bcd125");
        list.add("abcd120");
        list.add("bbb230");
        //我需要字符串中包含1的元素取出来
            //需要字符串长度不能超过6个的元素取出来
           //遍历查看最终想要的元素集合
        list.stream()
                .filter(str -> str.contains("1"))
                .filter(str ->str.length()<=6)
                .forEach(str ->System.out.println(str))
        /*
         abc123
         bcd125
        */
    }
}

一般我们把流式思想称之为"生产流水线"。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Java中,函数接口是指只有一个抽象方法的接口。Java 8 中引入了Lambda表达函数接口,使得我们可以更方便地编写函数代码。除了Java预定义的函数接口外,我们还可以自定义函数接口。 自定义函数接口的步骤如下: 1. 创建一个接口并且使用@FunctionalInterface注解来标记它为函数接口。 2. 在该接口中定义一个抽象方法,这个抽象方法就是我们自定义的函数接口的唯一方法。 3. 如果需要,可以在接口中定义默认方法和静态方法。 下面是一个示例: ```java @FunctionalInterface interface MyFunctionInterface { int operation(int x, int y); default void printResult(int result) { System.out.println("Result: " + result); } } ``` 在上面的代码中,我们定义了一个自定义函数接口 `MyFunctionInterface` ,它有一个抽象方法 `operation`,这个方法接受两个整数参数,并且返回一个整数。我们还定义了一个默认方法 `printResult`,用于打印结果。 我们可以使用Lambda表达来创建一个实现 `MyFunctionInterface` 的对象,如下所示: ```java MyFunctionInterface sum = (x, y) -> x + y; int result = sum.operation(10, 20); sum.printResult(result); // Output: Result: 30 ``` 在上面的代码中,我们使用Lambda表达来实现 `MyFunctionInterface` 接口,并且使用这个实现来执行加法操作。最后,我们调用 `printResult` 方法来打印结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值