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中有主要的体现。当然也可以在调用的函数定义中进行提前的逻辑处理。注意泛型等返回特点就好了。


相关文章
|
1月前
|
自然语言处理 Java
Java中的字符集编码入门-增补字符(转载)
本文探讨Java对Unicode的支持及其发展历程。文章详细解析了Unicode字符集的结构,包括基本多语言面(BMP)和增补字符的表示方法,以及UTF-16编码中surrogate pair的使用。同时介绍了代码点和代码单元的概念,并解释了UTF-8的编码规则及其兼容性。
109 60
|
7天前
|
缓存 Java 应用服务中间件
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
java语言后台管理若依框架-登录提示404-接口异常-系统接口404异常如何处理-登录验证码不显示prod-api/captchaImage 404 (Not Found) 如何处理-解决方案优雅草卓伊凡
35 5
|
2月前
|
存储 缓存 Java
Java 并发编程——volatile 关键字解析
本文介绍了Java线程中的`volatile`关键字及其与`synchronized`锁的区别。`volatile`保证了变量的可见性和一定的有序性,但不能保证原子性。它通过内存屏障实现,避免指令重排序,确保线程间数据一致。相比`synchronized`,`volatile`性能更优,适用于简单状态标记和某些特定场景,如单例模式中的双重检查锁定。文中还解释了Java内存模型的基本概念,包括主内存、工作内存及并发编程中的原子性、可见性和有序性。
Java 并发编程——volatile 关键字解析
|
2月前
|
算法 Java 调度
java并发编程中Monitor里的waitSet和EntryList都是做什么的
在Java并发编程中,Monitor内部包含两个重要队列:等待集(Wait Set)和入口列表(Entry List)。Wait Set用于线程的条件等待和协作,线程调用`wait()`后进入此集合,通过`notify()`或`notifyAll()`唤醒。Entry List则管理锁的竞争,未能获取锁的线程在此排队,等待锁释放后重新竞争。理解两者区别有助于设计高效的多线程程序。 - **Wait Set**:线程调用`wait()`后进入,等待条件满足被唤醒,需重新竞争锁。 - **Entry List**:多个线程竞争锁时,未获锁的线程在此排队,等待锁释放后获取锁继续执行。
87 12
|
2月前
|
存储 安全 Java
Java多线程编程秘籍:各种方案一网打尽,不要错过!
Java 中实现多线程的方式主要有四种:继承 Thread 类、实现 Runnable 接口、实现 Callable 接口和使用线程池。每种方式各有优缺点,适用于不同的场景。继承 Thread 类最简单,实现 Runnable 接口更灵活,Callable 接口支持返回结果,线程池则便于管理和复用线程。实际应用中可根据需求选择合适的方式。此外,还介绍了多线程相关的常见面试问题及答案,涵盖线程概念、线程安全、线程池等知识点。
234 2
|
2月前
|
数据采集 JSON Java
利用Java获取京东SKU接口指南
本文介绍如何使用Java通过京东API获取商品SKU信息。首先,需注册京东开放平台账号并创建应用以获取AppKey和AppSecret。接着,查阅API文档了解调用方法。明确商品ID后,构建请求参数并通过HTTP客户端发送请求。最后,解析返回的JSON数据提取SKU信息。注意遵守API调用频率限制及数据保护法规。此方法适用于电商平台及其他数据获取场景。
|
Java
Java接口和抽象类
Java接口和抽象类
97 0
|
6月前
|
设计模式 Java
【惊天揭秘】Java编程绝技大曝光:接口、抽象类、静态类与非静态类的神秘面纱终被揭开!
【8月更文挑战第22天】Java支持面向对象编程,通过接口、抽象类、静态类(如枚举与工具类)及普通类实现设计原则。接口定义行为规范,允许多重继承;抽象类含未实现的抽象方法,需子类完成;静态类常为工具类,提供静态方法;普通类则实例化对象。恰当运用这些结构能提升程序质量。
54 2
|
9月前
|
设计模式 搜索推荐 Java
java接口和抽象类的区别,以及使用选择
java接口和抽象类的区别,以及使用选择
95 0
|
6月前
|
Java 开发者
Java中的接口和抽象类
Java中的接口和抽象类
45 3