函数式接口-Java 8 新特性

函数式接口-Java 8 新特性

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,可以指定 Object 定义的任何公有方法。。

函数式接口可以被隐式转换为 lambda 表达式。

Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。

@FunctionalInterface
public interface IFuntionSum<T extends Number> {
    T sum(List<T> numbers);      // 抽象方法
}
@FunctionalInterface
public interface IFunctionMulti<T extends Number> {
    void multi(List<T> numbers); // 抽象方法
    
    boolean equals(Object obj);  // Object中的方法
}

如果改为以下形式,则不是函数式接口:

@FunctionalInterface
public interface IFunctionMulti<T extends Number> extends IFuntionSum<T> {
    void multi(List<T> numbers);
    
    @Override
    boolean equals(Object obj);
}
// IFunctionMulti 接口继承了 IFuntionSum 接口,此时 IFunctionMulti 包含了2个抽象方法

说明:

1: 可以用 @FunctionalInterface 标识函数式接口,非强制要求,但有助于编译器及时检查接口是否满足函数式接口定义
2: 在 Java 8 之前,接口的所有方法都是抽象方法,在 Java 8 中新增了接口的默认方法

JDK 1.8中java.util.function包含很多类,支持函数式编程

序号接口 & 描述
1BiConsumer<T,U>代表了一个接受两个输入参数的操作,并且不返回任何结果
2BiFunction<T,U,R>代表了一个接受两个输入参数的方法,并且返回一个结果
3BinaryOperator< T >代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果
4BiPredicate<T,U>代表了一个两个参数的boolean值方法
5BooleanSupplier代表了boolean值结果的提供方
6Consumer< T > 代表了接受一个输入参数并且无返回的操作

很多不一一列举了。

函数式接口实例

参考:https://www.runoob.com/java/java8-functional-interfaces.html

public class UseFunctionInterface {
    public static void main(String args[]){
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

        // Predicate<Integer> predicate = n -> true
        // n 是一个参数传递到 Predicate 接口的 test 方法
        // n 如果存在则 test 方法返回 true

        System.out.println("输出所有数据:");

        // 传递参数 n
        eval(list, n->true);

        // Predicate<Integer> predicate1 = n -> n%2 == 0
        // n 是一个参数传递到 Predicate 接口的 test 方法
        // 如果 n%2 为 0 test 方法返回 true

        System.out.println("输出所有偶数:");
        eval(list, n-> n%2 == 0 );

        // Predicate<Integer> predicate2 = n -> n > 3
        // n 是一个参数传递到 Predicate 接口的 test 方法
        // 如果 n 大于 3 test 方法返回 true

        System.out.println("输出大于 3 的所有数字:");
        eval(list, n-> n > 3 );
    }

    public static void eval(List<Integer> list, Predicate<Integer> predicate) {
        for(Integer n: list) {

            if(predicate.test(n)) {
                System.out.println(n + " ");
            }
        }
    }
}

控制台输出:

在这里插入图片描述

自定义函数式接口

//注解可加可不加,建议加上
@FunctionalInterface
public interface MyFunctionInterface {
    void saySomething(String message);
}

实现类:

public class MyFunctionInterfaceImpl implements MyFunctionInterface{
    @Override
    public void saySomething(String message) {
        System.out.println("重写了抽象方法 "+message);
    }
}

测试类:

public static void show(MyFunctionInterface myInter) {
    myInter.saySomething("");
}

public static void main(String[] args) {
    //调用show方法,方法的参数是一个接口,可以传递接口的实现类对象
    show(new MyFunctionInterfaceImpl());

    //调用show方法,方法的参数是一个接口,可以传递接口的匿名内部类
    show(new MyFunctionInterface() {
        @Override
        public void saySomething(String message) {
            System.out.println("使用匿名内部类重写接口中的抽象方法");
        }
    });

    //调用show方法,方法的参数是一个接口,可以使用Lambda表达式
    show((s)->{
        System.out.println("使用Lambda表达式重写接口中的抽象方法"+s);
    });

    //简化Lambda表达式
    show((s)-> System.out.println("使用简化的Lambda表达式重写接口中的抽象方法"+s));
}

控制台输出:

在这里插入图片描述

函数式编程

这里模拟一个简单的不同用户登录发送不同的消息功能

public class demo1 {
    public static void showMessage(int level, String message) {
        //对用户类型判断,不同类型发送不同消息
        if(level == 1) {
            System.out.println("hello "+message);
        }else {
            System.out.println("hello admin");
        }
    }

    public static void main(String[] args) {
        //定义用户信息
        String name =  "周杰伦";
        String position =  "good!!!!!!!!";
        showMessage(1,name+position);
    }
}

代码存在的问题:无论 level 是否满足要求,作为 showMessage方法的第二个参数,三个字符串一定会首先被拼接并传入方法内,然后才会进行级别判断。如果级别不符合要求,那么字符串的拼接操作就白做了,存在性能浪费。

写一个函数式接口

@FunctionalInterface
public interface MessageBuilder {
    String buildMessage();
}
public class demo2 {
    public static void showMessage(int level, MessageBuilder mb) {
        //对用户类型判断,不同类型发送不同消息
        if(level == 1) {
            System.out.println("hello "+mb.buildMessage());
        }else {
            System.out.println("hello admin");
        }
    }

    public static void main(String[] args) {
        //定义用户信息
        String name =  "周杰伦";
        String position =  "good!!!!!!!!";
        showMessage(1,()->{
            System.out.println("Lambda执行!");
            return name+position;
        });
    }
}

使用 Lambda 表达式作为参数传递时,仅仅是把参数传递到showMessage方法中,只有满足1的条件,才会调用接口MessageBuilder中的方法builderMessage,再进行字符串拼接,如果不满足,接口MessageBuilder中的方法就不会执行,拼接字符串的代码也不会执行,所以就不会存在性能上的浪费。

在这里插入图片描述

在这里插入图片描述

使用Lambda作为参数和返回值

public class demo3 {
    public static void startThread(Runnable r) {
        new Thread(r).start();
    }

    //runnable是一个函数式接口
    public static void main(String[] args) {
        startThread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName()+"-->"+"线程启动了。");
            }
        });

        //使用Lambda简化
        startThread(()-> System.out.println(Thread.currentThread().getName()+"-->"+"线程启动了。"));
    }
}
//方法的返回值类型是一个函数式接口,那么就可以直接返回一个Lambda表达式
public class demo4 {
    public static Comparator<String> getComparator() {
//        return new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                return o2.length()-o1.length();
//            }
//        };

        //参数可以省略
//        return (String o1, String o2)->{
//            return o2.length()-o1.length();
//        };

        //简化
        return (o1, o2) -> o2.length() - o1.length();
    }

    public static void main(String[] args) {
        String[] arr = {"aaa", "b", "cccccc", "ddddddddd"};
        System.out.println("排序前:" + Arrays.toString(arr));
        Arrays.sort(arr, getComparator());
        System.out.println("排序后:" + Arrays.toString(arr));
    }
}

函数式接口

Supplier接口

public class demo5 {
    public static String getString(Supplier<String> sup) {
        return sup.get();
    }

    public static void main(String[] args) {
        String s = getString(()->{
            return "周杰伦";
        });
        System.out.println(s);

        String s1 = getString(()->"完美主义");
        System.out.println(s1);
    }
}

Customer接口

抽象方法:accept

Consumer 接口中包含抽象方法 void accept(T t) ,意为消费一个指定泛型的数据。

public class demo6 {
    public static void method(String name, Consumer<String> con) {
        con.accept(name);
    }

    public static void main(String[] args) {
        method("周杰伦出新专辑拉",(name)->{
            //对传递的字符串进行消费
            //消费方式:直接输出字符串
            System.out.println(name);
            //消费方式:反转字符串
            String reName = new StringBuilder(name).reverse().toString();
            System.out.println(reName);
        });
    }
}
默认方法:andThen

需要两个Consumer接口,可以把两个Consumer接口组合到一起,再对数据进行消费。

注意:谁写前面谁先消费

public class demo7 {
    public static void method(String s, Consumer<String> con1, Consumer<String> con2) {
//        con1.accept(s);
//        con2.accept(s);

        //先执行con1 再执行 con2
        con1.andThen(con2).accept(s);
    }

    public static void main(String[] args) {
        method("Hello", (t) -> {
            //消费方式:把字符串转换为大写输出
            System.out.println(t.toUpperCase());    //HELLO
        }, (t) -> {
            //消费方式,把字符串转换为小写输出
            System.out.println(t.toLowerCase());    //hello
        });
    }
}

Predicate接口

需要对某种类型的数据进行判断,从而得到一个boolean值结果。

抽象方法:test
public class demo8 {
    public static boolean checkString(String s, Predicate<String> pre) {
        return pre.test(s);
    }

    public static void main(String[] args) {
        String s = "ABCDE";
        boolean b = checkString(s, (String str) -> {
            //对参数传递的字符串进行自定义判断
            return s.length() > 5;
        });
        System.out.println(b); //false

        //优化Lambda
        boolean b1 = checkString(s,str->s.length() > 4);
        System.out.println(b1);       //true
    }
}
默认方法:and

表示并且关系,也可以用于连接两个判断条件,其JDK源码为:

default Predicate<T> and(Predicate<? super T> other) { 
       Objects.requireNonNull(other); 
       return (t)> test(t) && other.test(t);  
 }
public class demo9 {
    public static boolean checkString(String s, Predicate<String> pre1, Predicate<String> pre2) {
//        return pre1.test(s) && pre2.test(s);
        return pre1.and(pre2).test(s);
    }

    public static void main(String[] args) {
        String s = "abfsgsgs";
        boolean b = checkString(s,(String str)->{
            return str.length()>6;
        },(String str)->{
            return str.contains("a");
        });
        System.out.println(b);    //true
    }

}
默认方法:or

与 and 的“与”类似,默认方法 or 实现逻辑关系中的“或”。JDK源码为:

default Predicate<T> or(Predicate<? super T> other) { 
	Objects.requireNonNull(other); 
	return (t)> test(t) || other.test(t); 
}
 public static boolean checkString(String s, Predicate<String> pre1,Predicate<String> pre2) {
//        return pre1.test(s) || pre2.test(s);
        return pre1.or(pre2).test(s);
    }
    
public static void main(String[] args) {
    String s = "abfsg";
    boolean b = checkString(s,(String str)->{
        return str.length()>10;
    },(String str)->{
        return str.contains("a");
    });
    System.out.println(b);  // true
}
默认方法:negate

取反

default Predicate<T> negate() { 
	return (t)> !test(t); 
}
public class demo11 {
    public static boolean checkString(String s, Predicate<String> pre) {
        return pre.negate().test(s);
    }

    public static void main(String[] args) {
        String s = "abfsg";
        boolean b = checkString(s,(String str)->{
            return str.length()>10;
        });
        System.out.println(b);  // true
    }
}

Function接口

Function<T,R> 接口用来根据一个类型的数据得到另一个类型的数据,前者称为前置条件, 后者称为后置条件。

抽象方法:apply

根据类型T的参数获取类型R的结果。

public class demo12 {
    public static void change(String s, Function<String,Integer> fun) {
        Integer in = fun.apply(s);
        System.out.println(in);
    }

    public static void main(String[] args) {
        String s = "1234";
        change(s,(String str)->{
            return Integer.parseInt(str);   //1234
        });

        change(s,str->Integer.parseInt(str));   //1234
    }
}
默认方法:andThen

用来进行组合操作。

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
	Objects.requireNonNull(after); 
	return (T t)> after.apply(apply(t)); 
}
public class demo13 {
    public static void change(String s, Function<String,Integer> fun1, Function<Integer,String> fun2) {
        String ss = fun1.andThen(fun2).apply(s);
        System.out.println(ss);
    }

    public static void main(String[] args) {
        String s = "123";
        change(s,(String str)->{
            return Integer.parseInt(s)+10;
        },(Integer i)->{
            return i+"";    //133
        });
        //优化
        change(s,str->Integer.parseInt(s)+10,i->i+"");  //133
    }
}

参考链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

清尘丿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值