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 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
13 6
|
1天前
|
存储 Java 数据处理
Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。
【10月更文挑战第16天】Java Set:无序之美,不重复之魅!Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。通过 hashCode() 和 equals() 方法实现唯一性,适用于需要唯一性约束的数据处理。示例代码展示了如何使用 HashSet 添加和遍历元素,体现了 Set 的高效性和简洁性。
11 4
|
3天前
|
存储 Java 数据处理
Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。
Java Set:无序之美,不重复之魅!Set 是 Java 集合框架中的一个接口,不包含重复元素且不保证元素顺序。它通过 hashCode() 和 equals() 方法确保元素唯一性,适用于需要唯一性约束的数据处理。示例代码展示了如何使用 HashSet 实现这一特性。
11 5
|
1天前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
7 2
|
3天前
|
存储 Java 数据处理
在Java集合框架中,Set接口以其独特的“不重复”特性脱颖而出
【10月更文挑战第14天】在Java集合框架中,Set接口以其独特的“不重复”特性脱颖而出。本文通过两个案例展示了Set的实用性和高效性:快速去重和高效查找。通过将列表转换为HashSet,可以轻松实现去重;而Set的contains方法则提供了快速的元素查找功能。这些特性使Set成为处理大量数据时的利器。
11 4
|
3天前
|
Java
Java Set 是一个不包含重复元素的集合接口,确保每个元素在集合中都是唯一的
【10月更文挑战第14天】Java Set 是一个不包含重复元素的集合接口,确保每个元素在集合中都是唯一的。本文介绍了 Set 的独特特性和两个常用实现类:基于哈希表的 HashSet 和基于红黑树的 TreeSet。通过示例代码展示了它们如何高效地处理唯一性约束的数据。
15 3
|
3天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其独特的“不重复性”要求,彻底改变了处理唯一性约束数据的方式。
【10月更文挑战第14天】从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其独特的“不重复性”要求,彻底改变了处理唯一性约束数据的方式。本文深入探讨Set的核心理念,并通过示例代码展示了HashSet和TreeSet的特点和应用场景。
8 2
|
3天前
|
存储 Java 索引
Java 中集合框架的常见接口和类
【10月更文挑战第13天】这些只是集合框架中的一部分常见接口和类,还有其他一些如 Queue、Deque 等接口以及相关的实现类。理解和掌握这些集合的特点和用法对于高效编程非常重要。
|
3天前
|
存储 安全 Java
了解final关键字在Java并发编程领域的作用吗?
在Java并发编程中,`final`关键字不仅用于修饰变量、方法和类,还在多线程环境中确保对象状态的可见性和不变性。本文深入探讨了`final`关键字的作用,特别是其在final域重排序规则中的应用,以及如何防止对象的“部分创建”问题,确保线程安全。通过具体示例,文章详细解析了final域的写入和读取操作的重排序规则,以及这些规则在不同处理器上的实现差异。
了解final关键字在Java并发编程领域的作用吗?
|
2月前
|
算法 Java 开发者
Java 编程入门:从零到一的旅程
本文将带领读者开启Java编程之旅,从最基础的语法入手,逐步深入到面向对象的核心概念。通过实例代码演示,我们将一起探索如何定义类和对象、实现继承与多态,并解决常见的编程挑战。无论你是编程新手还是希望巩固基础的开发者,这篇文章都将为你提供有价值的指导和灵感。