Java从入门到精通十六(函数式接口编程)

简介: 判断一个接口是不是一个函数式接口的办法就是在接口上方添加注解@FunctionalInterface进行检测。这其实就是一种函数式编程,体现了一种逻辑思维。函数式编程的一个非常方便的体现就是lambda表达式。所以函数式接口非常适合配合lambda去使用。

🍍 函数式接口引入




函数式接口是只含有一个抽象方法的接口。但是可以含有多个非抽象方法。


package function;
@FunctionalInterface
public interface Demo {
    void print();
//    void insert();//不可以含有多个抽象方法
    static  void method()
    {
    }
    public static int age()//静态方法
    {
        return  1;
    }
    default void make()//default修饰的普通方法
    {
        System.out.println(".....");
    }
}


在使用函数式接口的时候,非常适用的是我们可以用lambda去创建接口的对象。很方便判断一个接口是不是一个函数式接口的办法就是在接口上方添加注解@FunctionalInterface进行检测。


这其实就是一种函数式编程,体现了一种逻辑思维。函数式编程的一个非常方便的体现就是lambda表达式。所以函数式接口非常适合配合lambda去使用。


而要配合lambda表达式去使用,就需要要求接口中只有一个抽象方法。否则是无法满足lambda的使用语法规定的。


🍍 自定义函数式接口

我们可以自己定义函数式接口,上面的概述已经说过了。还是比较简单的,其实在文lambda表达式中所举的一些例子中也体现了函数式接口的特点。


简单演示一下使用

先定义一个接口


package function;
@FunctionalInterface
public interface Demo {
    void print();
//    void insert();
    static  void method()
    {
    }
    public static int age()//静态方法
    {
        return  1;
    }
    default void make()//default修饰的普通方法
    {
        System.out.println(".....");
    }
}


然后定义一个测试类


package function;
public class Demo_Use {
    public static void main(String[] args) {
        useDemo(()-> System.out.println("函数式接口的使用"));
    }
    private static void useDemo(Demo p)
    {
        p.print();
        p.make();
        Demo.age();
        Demo.method();//静态方法为类所有,我们可以这样去调用。
    }
}


🍍 java中常见的几种函数式接口


🍌 Predicate函数式接口


Interface Predicate


这是一个功能界面,因此可以用作lambda表达式或方法引用的赋值对象。


方法说明


and(Predicate<? super T> other)

返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND。


isEqual(Object targetRef)

返回根据 Objects.equals(Object, Object)测试两个参数是否相等的 谓词


negate()

返回表示此谓词的逻辑否定的谓词。


or(Predicate<? super T> other)

返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑或


test(T t)

在给定的参数上评估这个谓词。


可以看的出可以进行一些逻辑操作。我们可以去简单使用几个方法感受一些这种编程思维。



package function;
import java.util.ArrayList;
import java.util.function.Predicate;
public class PredicateTest {
    public static void main(String[] args) {
        String[] strArray = {"林青霞,30","柳岩,34","张曼玉,35","貂蝉,31","王祖贤,33"};
        ArrayList<String> array = myFilter(strArray, s -> s.split(",")[0].length() > 2, s -> Integer.parseInt(s.split(",")[1]) > 33);
        for(String str:array)
        {
            System.out.println(str);
        }
    }
    //通过Predicate 接口的拼装,将符合要求的字符串筛选到ArrayList
    private static ArrayList<String> myFilter(String[] strArry, Predicate<String> pre1, Predicate<String> pre2) {
        //定义一个集合
        ArrayList<String> array = new ArrayList<>();
        //遍历数组
        for(String str: strArry)
        {
            if (pre1.and(pre2).test(str))//我们对str进行一个操作,然后满足的就是两个限制条件。
            {
                array.add(str);
            }
        }
        return array;
    }
}


package function;
import java.util.function.Predicate;
public class PredicateDemo01 {
    public static void main(String[] args) {
        checkString("Hello",(String s)->{
            boolean b = s.length() > 8;
            return b;
        });
        //优化
        boolean b1 = checkString("Hello",s->s.length()>8);
        System.out.println(b1);
    }
    private static boolean checkString(String s, Predicate<String> pre)
    {
//        return  pre.test(s);
        //进行逻辑非的操作
        return pre.negate().test(s);
    }
    //判断给定的字符串是否满足要求
}


package function;
import java.util.function.Predicate;
public class PredicateDemo02 {
    public static void main(String[] args) {
        boolean b1 = checkString("hello",s->s.length()>8);
        System.out.println(b1);
        boolean b2 = checkString("helloworld",s->s.length()>8);
        boolean b3 = checkString("hello",s->s.length()>8,s->s.length()<15);
        System.out.println(b3);
    }
    //同一个字符串给出不同的条件,最后把这两个判断的结果做逻辑与运算的结果作为返回
    private static boolean checkString(String s,Predicate<String>pre,Predicate<String>pre1)
    {
        boolean test = pre.test(s);
        boolean test2 = pre1.test(s);
        boolean b = test && test2;
        return  b;
    }
    private static boolean checkString(String s, Predicate<String> pre)
    {
        return  pre.test(s);
    }
}


这种编程思维还是很有趣的,是java8推出的函数式编程。相关的方法,只要一看代码就明白了。


🍌 Supplier函数式接口

Interface Supplier


这是一个功能界面,因此可以用作lambda表达式或方法引用的赋值对象。


@FunctionalInterface

public interface Supplier代表结果供应商。

没有要求每次调用供应商时都会返回新的或不同的结果。

这是一个functional interface的功能方法是get() 。


这个函数式接口非常简单,提供的唯一一个方法就是get()


直接举例使用


package function;
import java.util.function.Supplier;
public class SupplierTest {
    public static void main(String[] args) {
        //定义一个int数组
        int[] arr = {16,13,14,35};
        int max1 = getMax(() -> {
            int max = arr[0];
            for (int i = 0; i < arr.length; i++) {
                if (arr[i] > max) {
                    max = arr[i];
                }
            }
            return max;
        });
        System.out.println(max1);
    }
    private static int  getMax(Supplier<Integer>sup)
    {
        return sup.get();
    }
}


package function;
import java.util.function.Supplier;
public class SupplierDemo {
    public static void main(String[] args) {
//       String s = getString(()->{
//            return "jgdabc";
//        });
        String s = getString(() -> "jgdabc");
        Integer i = getInteger(() -> 30);
        System.out.println(i);
    }
    //定义一个方法,返回整数
    private static Integer getInteger(Supplier<Integer> sup)
    {
        return  sup.get();
    }
    //定义一个方法,返回一个字符串数据
    private static String getString(Supplier<String >sup)
    {
        return  sup.get();
    }
}


🍌Consumer函数式接口


Interface Consumer


表示接受单个输入参数并且不返回结果的操作。 与大多数其他功能界面不同, Consumer预计将通过副作用进行操作。


我们通常也可以把这个接口函数称作消费类型接口


主要提供了两个方法


accept(T t)

对给定的参数执行此操作。


andThen(Consumer<? super T> after)

返回一个组合的 Consumer ,按顺序执行该操作,然后执行 after操作。


package function;
import java.util.function.Consumer;
public class ConsumerDemo {
    public static void main(String[] args) {
//        operatorString("jgdabc",(String s)->{
//            System.out.println(s);//消费的动作
//        });
        //优化
        operatorString("jgdabc",s-> System.out.println(s));
        //方法引用
        operatorString("jgdabc",System.out::println);
        //反转
        operatorString("jgdabc",s ->{
            String s1 = new StringBuilder(s).reverse().toString();
            System.out.println(s1);
        } );
        //优化
        operatorString("jgdabc",s-> System.out.println(new StringBuilder(s).reverse().toString()));
        operator("jgdabc",s-> System.out.println(new StringBuilder(s).reverse().toString()),s-> System.out.println(s));
    }
    //定义一个方法,对一个字符串数据进行两次消费
    private static void operator(String name,Consumer<String>con1,Consumer<String>con2)
    {
        con1.accept(name);
        con2.accept(name);
        //代替两次消费优化
        con1.andThen(con2).accept(name);
    }
    // 定义一个消费接口,消费一个字符串数据
    private static void operatorString(String name, Consumer<String>con)
    {
        con.accept(name);//传入字符串
    }
}


package function;
import java.util.function.Consumer;
public class ConsumerTest {
    public static void main(String[] args) {
        String[] strArray = {"jgdabc,16", "nsaasj,23", "sjansak,15"};
        printInfo(strArray, (String str) -> {
            String name = str.split(",")[0];
            System.out.println("姓名" + name);
        }, (String str) -> {
            int age = Integer.parseInt(str.split(",")[1]);
            System.out.println(",年龄:" + age);
        });
        //优化
        printInfo(strArray,str-> System.out.println("姓名"+str.split(",")[0]),str-> System.out.println("年龄"+Integer.parseInt(str.split(",")[1])));
    }
    private static void printInfo(String[] strArray, Consumer<String> con1, Consumer<String> con2) {
        for (String str : strArray) {
            con1.andThen(con2).accept(str);
        }
    }
}


🍌Function函数式接口


public interface Function<T,R>


表示接受一个参数并产生结果的函数。


注意它的泛型和说明,我们可以认为接收T类型的参数,然后返回R类型的结果。表达的就是这个意思。


然后我们去使用它,先看一下提供的方法。


andThen(Function<? super R,? extends V> after)

返回一个组合函数,首先将该函数应用于其输入,然后将 after函数应用于结果。


apply(T t)

将此函数应用于给定的参数。


compose(Function<? super V,? extends T> before)

返回一个组合函数,首先将 before函数应用于其输入,然后将此函数应用于结果。


identity()

返回一个总是返回其输入参数的函数。


代码举例


package function;
import java.util.function.Function;
public class FunctionTest {
    public static void main(String[] args) {
        String s = "林青霞,30";
        convert(s, (String ss) -> {
                    return ss.split(",")[1];
                }
                , (String ss) -> {
                    return Integer.parseInt(ss);
                }, (Integer i) -> {
                    return i + 70;
                });
    }
    private static void convert(String s, Function<String, String> fun1, Function<String, Integer> fun2, Function<Integer, Integer> fun3) {
        Integer i = fun1.andThen(fun2).andThen(fun3).apply(s);
        System.out.println(i);
    }
}


package function;
import java.util.function.Function;
public class FunctionDemo {
    public static void main(String[] args) {
        convert("100",(String s)->{
            return  Integer.parseInt(s);
        });
        //优化
        convert("100",Integer::parseInt);
        convert(100,i->String.valueOf(i+100));
        convert("100",s->Integer.parseInt(s),i->String.valueOf(i+66));
    }
    //定义一个方法,把一个字符串转换为int类型,加上一个整数,然后转换为字符串,在控制台输出
    private static void convert(String s,Function<String,Integer>fun1,Function<Integer,String> fun2)
    {
        Integer i = fun1.apply(s);
        String s1 = fun2.apply(i);
        System.out.println(s1);
        //改进
        String ss = fun1.andThen(fun2).apply(s);
        System.out.println(ss);
    }
    //定义一个方法,把一个int类型的数据加上一个整数之后,然后转换为字符串在控制台输
    private static void convert(int i,Function<Integer,String>fun)
    {
        String s = fun.apply(i);
        System.out.println(s);
    }
    //定义一个方法,将字符串转换为int类型,并在控制台输出
    private  static void convert(String s, Function<String,Integer>fun)
    {
        Integer i = fun.apply(s);
    }
}


这些函数接口函数都是十分简单的,提供的方法接收实际的处理逻辑还是在lambda中有主要的体现。当然也可以在调用的函数定义中进行提前的逻辑处理。注意泛型等返回特点就好了。


相关文章
|
8天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
7天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####
|
6天前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
9天前
|
安全 Java 开发者
Java多线程编程中的常见问题与解决方案
本文深入探讨了Java多线程编程中常见的问题,包括线程安全问题、死锁、竞态条件等,并提供了相应的解决策略。文章首先介绍了多线程的基础知识,随后详细分析了每个问题的产生原因和典型场景,最后提出了实用的解决方案,旨在帮助开发者提高多线程程序的稳定性和性能。
|
6月前
|
安全 Java
从零开始学习 Java:简单易懂的入门指南之不可变集合、方法引用(二十六)
从零开始学习 Java:简单易懂的入门指南之不可变集合、方法引用(二十六)
|
5月前
|
存储 Java API
Java——Stream流(1/2):Stream流入门、Stream流的创建(认识Stream、体验Stream流、Stream流的使用步骤、获取Stream流的方法)
Java——Stream流(1/2):Stream流入门、Stream流的创建(认识Stream、体验Stream流、Stream流的使用步骤、获取Stream流的方法)
89 0
|
Java 索引
从零开始学习 Java:简单易懂的入门指南之方法(六)
方法的概念:方法(method)是程序中最小的执行单元注意:方法必须先创建才可以使用,该过程成为方法定义,方法创建后并不是直接可以运行的,需要手动使用后,才执行,该过程成为方法调用
从零开始学习 Java:简单易懂的入门指南之方法(六)
Java入门------static关键字和静态属性、方法
Java入门------static关键字和静态属性、方法
131 0
|
Java 程序员
Java 学习博客_10 入门——抽象类、抽象方法、接口
以黑马程序员全套Java教程网课为主。
102 0
Java 学习博客_10 入门——抽象类、抽象方法、接口
下一篇
无影云桌面