java之函数式接口2 函数式编程以及各种接口

目录

函数式编程概念

函数式编程

 Supplier接口

Consumer接口

Predicate接口

Function接口


函数式编程概念

函数式接口在java中是指:有且仅有一个抽象方法的接口

在java中的提现就是Lambda

语法糖备注:语法糖指原理不变但是更加方便的写法,例如增强for,从应用层面上讲,Lambda可以被当做匿名内部类的“语法糖”,但是二者上原理不同

 

格式(确保接口中只有一个抽象方法即可)

修饰符 interface 接口名称{

public abstract 返回值类型 方法名称(参数);

}

 

/*

函数式接口:只有一个抽象方法

但是可以有其他类型的方法(默认,静态,私有)

*/

@FunctionalInterface

//该注解用于指定该接口为函数式接口只能有一个抽象方法,有多个时会出现异常

public interface MyFunctionalInterface {

    public abstract void method();

}

 

/*实现接口*/

public class Demo01 {

    public static void main(String[] args) {

        show(new MyFunctionalInterface() {

            @Override

            public void method() {

                System.out.println("匿名内部类");

            }

        });

        show(()-> System.out.println("Lambda")

        );

    }

    public static void show(MyFunctionalInterface myInter){

        myInter.method();

    }

}

 

为什么说Lambda和匿名内部类原理上不同呢?

原因:

 

Demo01$1.class是创建的匿名内部类

而Lambda没有创建类,而且由于不用加载类,速度上也快一些

 

函数式编程

在兼顾面对对象的基础上使用Lambda表达式与方法引用等

 

Lambda的延迟执行:有些场景的代码执行后,结果不一定被使用,从而造成性能浪费,而Lambda表达式是延迟执行的,这正好可以作为解决方法,提升性能

 

/*浪费性能的日志案例*/

public class Demo2 {

    //根据日志的级别,显示日志信息的方法

    public  static void showLog(int level,String message){

        if (level==1){

            System.out.println(message);

        }

    }

    /*

      发现以上代码存在性能浪费问题

      调用showLog方法,传递的第二个参数是一个拼接的字符串

      先把字符串拼接好再调用showLog方法

      showLog方法如果传递的日志等级不是1级

      那么字符串就白拼接了,造成了浪费

      */

    public static void main(String[] args) {

        String msg1="Hello";

        String msg2="World";

        String msg3="Java";

        showLog(2,msg1+msg2+msg3);

    }

 

}

 

为Lambda创建的函数式接口

 

package 函数式接口;

@FunctionalInterface

public interface MessageBuilder {

    String builderMessage();

}

 

/*使用Lambda表达式优化日志案例

Lambda使用前提必须有一个函数式接口

*/

public class Demo3 {

    public static void main(String[] args) {

        String msg1="Hello";

        String msg2="World";

        String msg3="Java";

        showLog(1,()-> msg1+msg2+msg3);

        /*

        使用Lambda表达式作为参数传递,仅仅是把参数传递到showLog方法中

        只有if语句满足条件(日志等级=1)

        才会调用MessageBuilder中的方法buildMessage进行字符串的拼接

        如果条件不满住,那么buildMessage也不会执行,不会存在性能浪费

        简单记:Lambda发生在函数调用后作为一个参数传递,再根据函数类的条件语句判断接口中的方法执不执行

        */

    }

    public static void showLog(int level,MessageBuilder mb){

        if (level==1) System.out.println(mb.builderMessage());

    }

}

 

Lambda可以作为参数同理Lambda也可以作为返回值

/*Lambda作为参数的多线程案例*/

public class Demo4 {

    //Runnable是一个典型的函数式接口

    public static void startThread(Runnable run){

        new Thread(run).start();

    }

    public static void main(String[] args) {

        startThread(()->{

            System.out.println(Thread.currentThread().getName()+"-->"+"线程启动了");

        });

    }

    /*

    Lambda作为方法的返回值

    Comparator接口案例

    */

    @Test

    public void test1(){

        String[]arr={"aaa","bbbb","ccccc","dddddd"};

        //排序前

        System.out.println(Arrays.toString(arr));

        Arrays.sort(arr,getComparator());

        //排序后

        System.out.println(Arrays.toString(arr));

    }

    public static Comparator<String> getComparator(){

        return (String o1,String o2)-> o2.length()-o1.length();

    }

}

 

 Supplier接口

 

Supplier接口

java.util.function.Supplier<T>接口仅包含一个无参的方法:T get()

用来获取一个泛型参数指定类型的对象数据

 

/*常用的函数接口*/

public class Demo5 {

    //Supplier<T>接口

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

    public static String getString(Supplier<String> sup){

        return sup.get();

    }

    @Test

    public void test1(){

        String s = getString(() -> {

            //生产一个字符串并返回

            return "这是一个字符串";

        });

        System.out.println(s);

    }

    //Supplier使用案例获取数组元素最大值

    @Test

    public void test2(){

        int [] arr={100,32,120,33,22,15};

        int maxElement = getMax(() -> {

            int max = arr[0];

            for (int i : arr)

                if (i > max) max = i;

            return max;

        });

        System.out.println("最大的元素是"+maxElement);

    }

    public static int getMax(Supplier<Integer> sub){

        return sub.get();

    }

}

Consumer接口

 

/*

java.util.function.Consumer<T>接口正好与Supplier接口相反,它不是生产一个数据,而是消费一个数据,其数据类型由泛型决定

抽象方法:accept(T t)意为消费一个指定泛型的数据

至于怎么消费,需要自定义

*/

public class Demo6 {

    public static void method(String name,Consumer<String> consumer)

    {

        consumer.accept(name);

    }

    @Test

    public void test1(){

        method("无名者",(String name)->{

            //反转输出

            String reName=new StringBuilder(name).reverse().toString();

            System.out.println(reName);

        });

    }

    //Consumer中的默认方法andThen,如果一个方法的参数和返回值全是Consumer类型

    //那么就可以在消费数据的时候先做一个操作,再做一个操作实现组合。这个方法就是andThen

    /*源码

    default Consumer<T> andThen(Consumer<? super T> after) {

        Objects.requireNonNull(after);

        return (T t) -> { accept(t); after.accept(t); };

    }

    简单来说:

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

    谁写前面谁先消费

    */

    public static void andThenMethod(String s, Consumer<String> con1,Consumer<String> con2){

       /* con1.accept(s);

        con2.accept(s);*/

        con2.andThen(con1).accept(s);//这里con2写前面故意先调用con2

    }

    @Test

    public void test2(){

        andThenMethod("Hello",

                (t)->{

                //将字符串大写输出

                    System.out.println(t.toUpperCase());

                         },

                (t)->{

                //将字符串小写输出

                    System.out.println(t.toLowerCase());

                        });

        //使用andThen将两个接口连接到一起再消费

 

    }

}

 

 

 

练习:

 public static void printInfo(String[] arr,Consumer<String> con1,Consumer<String> con2)

    {

        for (String message : arr) {

            con1.andThen(con2).accept(message);

        }

    }

    @Test

    public void test3(){

        String[] arr={"无名氏1,女","无名氏2,女","无名氏3,男"};

        printInfo(arr,(message)->{

            //获取姓名

            String name = message.split(",")[0];

            System.out.print("姓名:"+name);

        },(message)->{

            String age=message.split(",")[1];

            System.out.print("年龄:"+age+"。");

        });

    }

Predicate接口

 

 

/*java.util.function.Predicate<T>接口

包含一个抽象方法:boolean test(T t)用于对指定数据类型条件判断场景

*/

public class Demo7 {

    //判断字符串的方法

    public static boolean checkString(String s, Predicate<String> pre){

     return pre.test(s);

    }

    @Test

    public void test1(){

        String s="abcde";

        //复习一下能省略的东西:只有一个参数参数类型String可以省略,方法体只有一行{}可以省略

        boolean b = checkString(s, (str) -> str.length()>5);

        System.out.println(b);

    }

    /*

    默认方法and

    将两个Predicate条件使用“与”逻辑连接起来实现并且的效果

    源码:

     default Predicate<T> and(Predicate<? super T> other) {

        Objects.requireNonNull(other);

        return (t) -> test(t) && other.test(t);

    }

    */

    //定义一个方法,传递一个字符串,两个Predicate接口

    //一个判断字符串长度是否大于5,一个用于判断字符串中是否包含a

    //两个条件必须同时满足

    public static boolean checkString2(String s,Predicate<String> pre1,Predicate<String> pre2){

       return pre1.negate().and(pre2).test(s);

    }

    @Test

    public void test2(){

        String s="asd";

        boolean a = checkString2(s, (str) -> str.length() > 5, (str) -> str.contains("a"));

        System.out.println(a);

    }

    /*

    默认方法or方法

    与and方法类似实现逻辑或关系

    示例:

    pre1.or(pre2).test(s);

    negate:取非的方法

    取反写法示例

    pre1.negate().test(s)

    pre1.negate().and(pre2).test(s);

    */

}

Function接口

import java.util.function.Function;

 

public class Demo8 {

    /*

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

    抽象方法:R apply(T t),将t转化成R

    */

    //应用案例将String转化成Integer

    public static void translation(String s,Function<String,Integer> fun){

        Integer in=fun.apply(s);

        System.out.println(in);

    }

    @Test

    public void test(){

        String s="1234";

        translation(s, Integer::parseInt);

        //这里的双冒号代表访问Integer中的方法parseInt

    }

    /*

    andThen方法,用来进行组合操作,也是先做。。后做。。

    */

    public static void method(String s,Function<String,Integer> fun1,Function<Integer,String> fun2){

        String str=fun1.andThen(fun2).apply(s);

        System.out.println(str);

 

    }

    @Test

    public void test2(){

        String s="123";

        //i+""空字符就是将Integer转化成字符串

        method(s,(s1)-> Integer.parseInt(s1)+10,(i)-> i+"");

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值