Lamdba表达式

目录

函数式接口

Lamdba表达式的延迟执行

常用的函数式接口

1.Supplier接口

2.Consumer接口

3.Predicate接口

4.Function接口(主要是用来进行数据类型之间的转化)


Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

使用 Lambda 表达式可以使代码变的更加简洁紧凑。

lamdba表达式的写法:

(parameters) -> expression

(parameters) ->{ statements; }

函数式接口

当且只有一个抽象方法的接口,称之为函数式接口,当然接口中可以包含其他的方法(默认,静态,私有)

@FunctionalInterface

这个注解的作用是可以检查接口是否是一个函数式接口 是:编译成功 否:编译失败(接口中没有抽象方法或者是抽象方法有多个) 

/**
 * Created by asus on 2020/6/8.
 */
/*
    函数式接口:当且只有一个抽象方法的接口,称之为函数式接口
    当然接口中可以包含其他的方法(默认,静态,私有)
 */

/*
    @FunctionalInterface这个的作用是可以检查接口是否是一个函数式接口
    是:编译成功
    否:编译失败(接口中没有抽象方法或者是抽象方法有多个)
 */

//加了这个注解之后,如果是有多个抽象方法或者是没有抽象方法都会编译不通过
@FunctionalInterface
public interface MyFunctionInterface {
    //这里的public abstract是可以省略的,可以写成void method()
    public abstract  void method();
}

实现类

/**
 * Created by asus on 2020/6/8.
 */
public class MyFunctionInterfaceImpl implements MyFunctionInterface {
    @Override
    public void method() {
        System.out.println("这是个函数式接口的实现类");
    }
}

main方法中对于前两个方法的调用属于普通的调用,后面两个是lamdba表达式的使用,各个符号的含义,还有lamdba表达式的简化

/**
 * Created by asus on 2020/6/8.
 */
/*
函数式接口的使用:一般可以作为方法的参数和返回值类型
 */
public class Demo {
    //定义一个方法,方法的参数是函数式接口MyFunctionInterface
    public static void show(MyFunctionInterface myInter)
    {
        myInter.method();
    }

    public static void main(String[] args) {
        /*
        第一个和第二个方法使用是正常接口的使用方法
         */
        //调用show方法,方法参数一个接口,所以可以传递接口的实现类
        show(new MyFunctionInterfaceImpl());

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

        //调用show方法,方法的参数是一个函数式接口,所以可以使用lambda表达式
        //这里的小括号()里面写的是抽象方法的参数,大括号是方法的方法体
        show(()->{
            System.out.println("这是个lambda表达式");
        });

        //简化lambda表达式
        //小括号已经是最简的了,大括号里面有且只有一行语句,就可以将大括号省略,并且输出语句的分号;也可以省略
        show(()-> System.out.println("lambda表达式的简化"));

    }
}

Lamdba表达式的延迟执行

例子:日志的性能优化

1.普通的日志

/**
 * Created by asus on 2020/6/8.
 */
//这里我们定义一个日志,只有等级为1才会输出后面的message
public class LogTest {
    public static void log(int level,String message)
    {
        if(level==1)
        {
            System.out.println(message);
        }
    }

    public static void main(String[] args) {
        //定义三个日志信息
        String mess1 = "hello";
        String mess2 = " word";
        String mess3 = " !";
        
        //这里我们看到如果是级别为1,就不会造成浪费
        log(1,mess1+mess2+mess3);

        //但是如果级别为其他的话,mess1+mess2+mess3就会造成浪费
        log(2,mess1+mess2+mess3);
    }
}

这里的例子如果日志的级别不为1的话,字符串的拼接也是会执行,这样会浪费性能

2.使用lamdba表达式

例子1:

定义函数式接口

/**
 * Created by asus on 2020/6/8.
 */
public interface LogLa {
    public abstract String message();
}

/**
 * Created by asus on 2020/6/8.
 */
/*
这里我们使用lamdba表达式,lamdba有延迟执行的特性,所以如果日志级别不是为1的话,也不会执行message()的方法
这样的话就不会造成性能的浪费
 */
public class LambdaLog {
    public static void log(int level,LogLa log)
    {
        if(level==1)
        {
            System.out.println(log.message());
        }
    }

    public static void main(String[] args) {
        //定义三个日志信息
        String mess1 = "hello";
        String mess2 = " word";
        String mess3 = " !";
        //这里我们看到如果是级别为1,就不会造成浪费
        log(1,()->{
            return mess1+mess2+mess3;
        });

        //这里的话是逐层进行的,只有满足条件,才会执行后面的
        //因为lamdba有延迟执行,所以并不会执行message()的方法
        log(2,()-> {
            return mess1 + mess2 + mess3;
        });
    }
}

例子2:

多线程的Runnable接口也是一个函数式接口

/**
 * Created by asus on 2020/6/8.
 */
//Runnable也是一个函数式接口
public class LamdbaThread {
    public static void main(String[] args) {
        //普通的线程执行
        MyRunnable run = new MyRunnable();
        Thread thread = new Thread(run);
        thread.start();

        //使用Lamdba表达式
        Thread thread1 = new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"执行了");
        });

        //简化Lamdba
        Thread thread2 = new Thread(()->
            System.out.println(Thread.currentThread().getName()+"执行了")
        );
        thread1.start();
        thread2.start();
    }
}


class MyRunnable implements Runnable
{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"执行了");
    }
}

有返回值和参数的函数式接口的使用

Comparator是一个函数式接口,我们以这个为例

import java.util.Arrays;
import java.util.Comparator;

/**
 * Created by asus on 2020/6/9.
 */
//comparator是一个函数式接口
public class ComparatorLambda {
    public static Comparator<String> getComparator()
    {
        /*
        //这里是使用的匿名内部类
        return new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                //这里表示按照字符串的长度降序排序,也就是字符串长度长的在前面
                return o2.length()-o1.length();
            }
        };
        */

        /*
        //使用lamdba表达式
        return (o1,o2)->{
            return o2.length()-o1.length();
        };
        */

        //简化lambda表达式
        return (o1,o2)->o2.length()-o1.length();

    }

    public static void main(String[] args) {
        String [] strings={"aaaaaaa","bbbb","cccccccccccc","d"};
        System.out.println(Arrays.toString(strings));
        //输出结果为[aaaaaaa, bbbb, cccccccccccc, d]

        //使用arrays的sorts方法进行排序
        Arrays.sort(strings,getComparator());
        System.out.println(Arrays.toString(strings));
        //输出的结果为[cccccccccccc, aaaaaaa, bbbb, d]
    }
}

常用的函数式接口

jdk8之后给我们提供了部分函数式接口,都在java.util.function包下

1.Supplier接口

import java.util.function.Supplier;

/**
 * Created by asus on 2020/6/9.
 */
/*
常用的函数式接口,java.util.function包下
Supplier<T>被称之为生产型接口,指定接口的泛型是什么,那么接口中的get()方法返回的就是什么
 */
public class SupplierLamdba {
    public static String getString(Supplier<String> sup){
        return sup.get();
    }

    public static void main(String[] args) {
        //使用lamdba表达式
        String message = getString(()->{
            return "sipplier是个常用的函数式接口";
        });
        System.out.println(message);
        
        //简化版
        String message1 = getString(()->"sipplier是个常用的函数式接口2");
        System.out.println(message1);
    }
}

import java.util.function.Supplier;

/**
 * Created by asus on 2020/6/9.
 */
//获取数组元素中的最大值
public class MaxSupplier {
    public static int getMax(Supplier<Integer> supplier){
        return supplier.get();
    }

    public static void main(String[] args) {
        int [] sort = {111,22,4455,75,3,6};

        int maxsort=getMax(()->{
            int max = sort[0];
            for(int i:sort){
                if(i>max)
                {
                    max = i;
                }
            }
            return max;
        });
        System.out.println(maxsort);

    }
}

2.Consumer接口

是一个消费型接口,泛型执行什么类型,就可以使用accept方法消费什么类型的数据

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

import java.util.function.Consumer;

/**
 * Created by asus on 2020/6/9.
 */
public class ConsumerLamdba {
    public static void getConsumer(String name, Consumer<String >consumer)
    {
        consumer.accept(name);
    }

    public static void main(String[] args) {
        getConsumer("赵丽颖",(String name)->{
            System.out.println(name);
        });

        //对字符串进行反转
        getConsumer("赵四是个人渣",(String name)->{
            StringBuilder builder = new StringBuilder(name);
            String outname =builder.reverse().toString();
            System.out.println(outname);
        });
    }
}

Consumer中的andThen方法,可以将两个Consumer接口结合起来消费

具体使用看下面的例子

import java.util.function.Consumer;

/**
 * Created by asus on 2020/6/9.
 */
/*
andThen是将两个Consumer结合起来消费

 */
public class ConsumerAndThen {
    public static void getAndThen(String name, Consumer<String> con1,Consumer<String> con2)
    {
        /*
        //这里是两个Consumer接口分别对name进行消费
        con1.accept(name);
        con2.accept(name);
        */
        //这里的意思跟上面是一样的,那个Consumer在前面,那个先消费
        con1.andThen(con2).accept(name);
    }

    public static void main(String[] args) {
        getAndThen("Hello",
                (t)->{
                    //将字符串转化为大写
                    System.out.println(t.toUpperCase());
                },(t)->{
            //将字符串转化为小写
                    System.out.println(t.toLowerCase());
                });
    }
}

Demo

import java.util.function.Consumer;

/**
 * Created by asus on 2020/6/9.
 */
/*
要求:将数组格式为["迪丽热巴,女","胡歌,男","马尔扎哈,兽"],打印出来的格式是  姓名:迪丽热巴 性别:女 这种形式
这里要使用两个Consumer,第一个负责消费姓名,第二个负责消费性别,最后将两个组合起来
 */
public class ConsumerTest {
    public static void getMessage(String[] array, Consumer<String> con1,Consumer<String> con2)
    {
        for(String message:array)
        {
            con1.andThen(con2).accept(message);
        }
    }

    public static void main(String[] args) {
        String [] arr = {"迪丽热巴,女","胡歌,男","马尔扎哈,兽"};
        getMessage(arr,
                (message)->{
                    String name = message.split(",")[0];
                    System.out.print("姓名:"+name+"   ");
                },
                (message)->{
                    String name = message.split(",")[1];
                    System.out.print("性别:"+name);
                    System.out.println();
                });
    }
}

3.Predicate接口

import java.util.function.Predicate;

/**
 * Created by asus on 2020/6/9.
 */
/*
java.util.function.Predicate<T>接口
Predicate接口包含一个抽象方法:
boolean test(T t):用来对于制定数据类型进行判断方法
    结果:
        符合条件:true
        不符合条件:false
 */
//判断字符串的长度是否大于5
public class PredicateLamdba {
    public static boolean getPredicate(String message, Predicate<String>pre)
    {
        return pre.test(message);
    }

    public static void main(String[] args) {
        String message = "abcderfg";
        Boolean b = getPredicate(message,(String m)->{
            return m.length()>5;
        });
        System.out.println(b);

        //简化版
        Boolean c = getPredicate(message,(m)->m.length()>5);
        System.out.println(c);
    }
}

(1)Predicate接口的and方法,相当于&&

import java.util.function.Predicate;

/**
 * Created by asus on 2020/6/9.
 */
/*
    逻辑表达式:可以连接多个判断的条件
    &&:与运算,有false则为false
    ||:或运算,有true则为true
    !:非(取反)运算,非真则假,非假则真

    需求:判断一个字符串,有两个判断的条件
        1.判断字符串的长度是否大于5
        2.判断字符串是否包含a
        两个条件必须同时满足,我们就可以使用&&运算符连接两个条件

        predicate接口中有一个方法and,表示并且关系也可以用来连接两个判断条件
 */
public class PredicateAnd {
    public static boolean getAnd(String name, Predicate<String>p1,Predicate<String>p2)
    {
        //return p1.test(name)&&p2.test(name);

        //这里也可以使用predicate接口的and方法
        return p1.and(p2).test(name);
    }


    public static void main(String[] args) {
        String name = "abcder";
        boolean b = getAnd(name,
                (String n)->{
                    return n.length()>5;
                },
                (String n)->{
                    return n.contains("a");
                });

        System.out.println(b);
    }
}

(2)Predicate接口的or方法,相当于||

import java.util.function.Predicate;

/**
 * Created by asus on 2020/6/9.
 */
/*
    逻辑表达式:可以连接多个判断的条件
    &&:与运算,有false则为false
    ||:或运算,有true则为true
    !:非(取反)运算,非真则假,非假则真

    需求:判断一个字符串,有两个判断的条件
        1.判断字符串的长度是否大于5
        2.判断字符串是否包含a
        两个条件只需要满足其中一个,我们就可以使用||运算符连接两个条件

        predicate接口中有一个方法or,表示并且关系也可以用来连接两个判断条件
 */
public class PredicateOr {
    public static boolean getAnd(String name, Predicate<String>p1,Predicate<String>p2)
    {
        //return p1.test(name)||p2.test(name);

        //这里也可以使用predicate接口的and方法
        return p1.or(p2).test(name);
    }


    public static void main(String[] args) {
        String name = "abcder";
        boolean b = getAnd(name,
                (String n)->{
                    return n.length()>5;
                },
                (String n)->{
                    return n.contains("a");
                });

        System.out.println(b);
    }
}

(3)Predicate接口的negate方法,相当于!

import java.util.function.Predicate;

/**
 * Created by asus on 2020/6/9.
 */

/*
    逻辑运算符的取反是使用!,predicate接口的取反是使用negate方法
    需求:字符串长度大于5,则为false
    字符串长度不大于5,则为true
 */
public class PredicateNegate {
    public static boolean getNegate(String name, Predicate<String> p1){
        //return !p1.test(name);
        return p1.negate().test(name);
    }

    public static void main(String[] args) {
        String name  = "abcdefg";
        boolean b  =getNegate(name,(String n)->{
            return n.length()>5;
        });
        System.out.println(b);
        //输出结果为false
    }
}

4.Function接口(主要是用来进行数据类型之间的转化)

import java.util.function.Function;

/**
 * Created by asus on 2020/6/9.
 */
/*
    java.util.function.Function<T,R>接口是用来根据一个类型的数据得到另一个类型的数据
    前者称之为前置条件,后者称之为后置条件
    Function接口中最主要的抽象方法为 R apply(T t),根据类型T的参数获取类型R的结果
    使用场景例如:将String类型转换为Integer类型
 */
public class FunctionApply {
    public static  void getApply(String number, Function<String,Integer>fun)
    {
        Integer num = fun.apply(number);
        System.out.println(num);
    }

    public static void main(String[] args) {
        String number ="122345";
        getApply(number,(String n)->{
            return Integer.parseInt(n);
        });
        //这里是简化版本
        getApply(number,(n)->Integer.parseInt(n));
    }
}

import java.util.function.Function;

/**
 * Created by asus on 2020/6/9.
 */
/*
    需求,将字符串的数字转换为int类型之后加20
    在吧int类型的数字转换为字符串
 */
public class FunctionTest {
    public static void funTest(String number,Function<String,Integer> fun1,Function<Integer,String>fun2)
    {
//        Integer num = fun1.apply(number);
//        String n = fun2.apply(num);
        String n = fun1.andThen(fun2).apply(number);
        System.out.println(n);
    }

    public static void main(String[] args) {
        String number = "121234";
        funTest(number,(String n)->{
            return Integer.parseInt(n)+20;
        },(Integer nu)->{
            return String.valueOf(nu);
        });
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值