目录

函数式编程概念

函数式编程

 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和匿名内部类原理上不同呢?

原因:

java 接口中定义构造方法_java

 

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);
    }
 
}

java 接口中定义构造方法_lambda_02

 

为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";
()-> 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()+"-->"+"线程启动了");
        });
    }

java 接口中定义构造方法_System_03

/*
    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();
    }
}

 

java 接口中定义构造方法_System_04

 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);
    }

java 接口中定义构造方法_java_05

//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();
    }
}

java 接口中定义构造方法_lambda_06

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);
        });
    }

java 接口中定义构造方法_System_07

//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将两个接口连接到一起再消费
 
    }
}

java 接口中定义构造方法_编程语言_08

 

 

 

练习:

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+"。");
        });
    }

java 接口中定义构造方法_编程语言_09

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);
    }
    /*

java 接口中定义构造方法_java 接口中定义构造方法_10

    默认方法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
    }

java 接口中定义构造方法_java_11

/*
    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+"");
    }
}

java 接口中定义构造方法_lambda_12