JDK8新特性-Lambda表达式

1.什么是Lambda表达式

    Lambda表达式实际上是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更加简洁,灵活的代码。作为一种更紧凑的代码风格,使得Java的语言表达能力得到提升。

    @Test
    public void test1() {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello, World!");//Hello, World!
            }
        };
        r.run();
        //Lambda表达式
        Runnable r2 = () -> System.out.println("Hello, Lambda!");//Hello, Lambda!
        r2.run();
    }

2.Lambda表达式语法

     Lambda表达式在Java语言中引入了一个新的语法元素操作符 ->  ,该操作符被称为Lambda操作符或箭头操作符。它将Lambda分割成为两部分:左侧和右侧。

    左侧:指定了Lambda表达式所需要的参数列表。

    右侧:指定了Lambda体,即Lambda表达式执行的代码功能。

    Lambda表达式采用了上线文类型推断,可以在左侧参数列表中

3.什么函数式接口

     只包含一个抽象方法的接口称为函数式接口,使用@FunctionalInteface注解标识。函数式接口也是可以有default方法的,但是,只能有一个未实现的方法。

4.Java内置核心函数式接口

函数式接口参数类型返回类型用途
java.util.function.Consumer<T>void对类型为T的对象应用操作,包含方法void accept(T t);
消费型
java.util.function.Supplier<T>T

返回类型为T的对象,包含方法 T get();

供给型

java.util.function.Function<T,R>TR

参数类型T,返回类型R,包含方法 R apply(T t);

函数型

java.util.function.Predicate<T>Tboolean

参数类型T,返回类型boolean,包含方法 boolean test(T t);

断言型

    @Test
    public void test2() {
        Consumer<String> consumer = x -> System.out.println(x);
        consumer.accept("我是一个带参数无返回类型消费型Consumer");//我是一个带参数无返回类型Consumer

        Supplier<String> supplier = () -> "我是一个无参有返回值的供给型Supplier";
        System.out.println(supplier.get());//我是一个无参有返回值的供给型Supplier

        Function<String, String> function = (x) -> x.toUpperCase();
        System.out.println(function.apply("我是一个带有参数和返回值的函数式接口,lambda!"));//我是一个带有参数和返回值的函数式接口,LAMBDA!

        Predicate<String> predicate = x -> x.contains("Lambda");
        System.out.println(predicate.test("Test,Lambda"));//true
    }

5.其他内置函数式接口

    在java.util.function.* 包下可以看到内置的其他函数式接口


6.自定义函数式接口

    基本上内置的函数式接口通常会满足我们的需求,当不能满足我们需求的时候需要自己自定义函数接口。

    1.新建MyFun.class的接口。

    2.添加注解@FunctionalInteface。

    3.此接口只能有一个抽象方法,多了则会编译报错。

@FunctionalInterface
public interface MyFun<T> {

    void print(T t);
}
    @Test
    public void test3() {
        MyFun<String> fun = x -> System.out.println(x);
        fun.print("自定义函数式接口");//自定义函数式接口
    }
7.方法引用与构造器引用
    方法引用:若 Lambda 体中的功能,已经有方法提供了实现,可以使用方法引用(可以将方法引用理解为 Lambda 表达式的另外一种表现形式)主要有三种情况:

    1.对象::实例方法

    2.类::静态方法

    3.类::实例方法

      1.对象::实例方法例子

    @Test
    public void test4() {
        PrintStream ps = System.out;
        Consumer<String>  consumer = (x) -> ps.println(x);
        consumer.accept("对象引用::实例方法名");//对象引用::实例方法名

        System.out.println("-----------------------");

        Consumer<String> consumer2 = ps::println;
        consumer2.accept("对象引用::实例方法名");//对象引用::实例方法名

        System.out.println("-----------------------");

        Consumer<String> consumer3 = System.out::println;
        consumer3.accept("对象引用::实例方法名");//对象引用::实例方法名
    }

注意:

①方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致! 

②若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName


 public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }
 /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
Employee emp = new Employee(101, "张三", 18, 9999.99);
        Supplier<String> sup = () -> emp.getName();
        System.out.println(sup.get());//张三
        System.out.println("------------------------");

        Supplier<String> sup2 = emp::getName;
        System.out.println(sup2.get());//张三

2.类::静态方法

    @Test
    public void test5() {
        BiFunction<Double, Double, Double> fun = (x,y) -> Math.max(x, y);
        System.out.println(fun.apply(1D,0D));

        BiFunction<Double, Double, Double> fun2 = Math::max;
        System.out.println(fun2.apply(1D,0D));

        Comparator<Integer> com = (x, y) -> Integer.compare(x,y);
        System.out.println("--------------------------");

        Comparator<Integer> com2 = Integer::compare;
        System.out.println(com2.compare(1,2));
    }

3.类::实例方法

    @Test
    public void test6() {
        BiPredicate<String, String> bp = (x, y) -> x.equals(y);
        System.out.println(bp.test("abcde", "abcde"));

        System.out.println("-----------------------------------------");

        BiPredicate<String, String> bp2 = String::equals;
        System.out.println(bp2.test("abc", "abc"));

        System.out.println("-----------------------------------------");


        Function<Employee, String> fun = (e) -> e.show();
        System.out.println(fun.apply(new Employee()));

        System.out.println("-----------------------------------------");

        Function<Employee, String> fun2 = Employee::show;
        System.out.println(fun2.apply(new Employee()));

    }

构造器引用 :构造器的参数列表,需要与函数式接口中参数列表保持一致!

    @Test
    public void test7(){
        Supplier<Employee> sup = () -> new Employee();
        System.out.println(sup.get());//Employee [id=0, name=null, age=0, salary=0.0]

        System.out.println("------------------------------------");

        Supplier<Employee> sup2 = Employee::new;
        System.out.println(sup2.get());//Employee [id=0, name=null, age=0, salary=0.0]

        Function<String, Employee> fun = Employee::new;
        System.out.println(fun.apply("aaa"));//Employee [id=0, name=aaa, age=0, salary=0.0]

        BiFunction<String, Integer, Employee> fun2 = Employee::new;
        System.out.println(fun2.apply("aaa",1));//Employee [id=0, name=aaa, age=1, salary=0.0]
    }

数组引用

    @Test
    public void test8(){
        Function<Integer, String[]> fun = (args) -> new String[args];
        String[] strs = fun.apply(10);
        System.out.println(strs.length);//10

        System.out.println("--------------------------");

        Function<Integer, Employee[]> fun2 = Employee[] :: new;
        Employee[] emps = fun2.apply(20);
        System.out.println(emps.length);//20
    }
8.Lambda表达式本质探寻
    前面,我们讲了一些Lambda表达的一些语法,我们说Lambda的本质实际上就是一个匿名函数,比如Runnable接口的run方法,在jdk7以前,通常的写法是new一个匿名的内部类在run方法里面实现功能,然而我们发现run方法里面真正有用的代码实际上就只有一行
System.out.println("Hello World!" + num);
为了实现这个功能,从而写了很多不必要的代码,代码的可读性降低了,java的工程师为了解决这样的繁琐的代码问题而实现了一个Lambda表达式,Lambda表达式代替了匿名内部类真正要实现的代码功能。如下
        @Test
	public void test1(){
		int num = 0;//jdk 1.7 前,必须是 final
		
		Runnable r = new Runnable() {
			@Override
			public void run() {
				System.out.println("Hello World!" + num);
			}
		};
		
		r.run();
		
		System.out.println("-------------------------------");
		
		Runnable r1 = () -> System.out.println("Hello Lambda!");
		r1.run();
	}
Runnable r1 = () -> System.out.println("Hello Lambda!");

一行代码就此解决,从代码的角度来说,可读性增加了,更加简洁。我们注意观察Runnable接口

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

1.它是一个接口

2.接口中出现了@FunctionalInterface

3.抽象方法run无参数无返回值

我们在来看这个,Lambda表达式是由三部分组成而来,左侧参数值列表 ->Lambda操作符 和 Lambda体。

Runnable r1 = () -> System.out.println("Hello Lambda!");

左边的参数对应run中的无参数方法,Lambda体直接输出一句话Hello Lambda 对应无返回值的run。Lambda表达式刚好与接口中抽象方法保持一致。要是接口中有多个抽象方法,怎么调用? @FunctionalInterface注解标志着这个接口中只能有一个未实现的抽象方法,超过两个则会编译出错。

结论:要实现一个Lambda表达式需要与函数式接口中的抽象方法保持一致。

9.Lambda表达式练习

    根据结论,要实现一个Lambda表达式需要与函数式接口中的抽象方法保持一致。我们来找找一些函数式接口。   

    @Test
    public void test9() {
        //打印一句话
        Runnable r = () -> System.out.println("hello,lambda!");

        Consumer<String> con = (x)-> System.out.println("hello,lambda!");
        //如果参数列表只有一个值,()可以省略
        Consumer<String> con2 = x-> System.out.println("hello,lambda!");

        //1.如果有多行Lambda体需要用{}包起来
        Comparator<Integer> com = (x,y)-> {
            if (x > y) {
                return 1;
            } else if (x<y) {
                return -1;
            } else {
                return 0;
            }
        };
        //2.如果只有一行可以不用写{}并且return也可以省略
        Comparator<Integer> com2 = (x,y)-> Integer.compare(x,y);
        //3.使用方法引用
        Comparator<Integer> com3 = Integer::compare;
        //创建对象
        Function<String,String> fun = String::new;
        Function<Integer,String[]> fun2 = String[]::new;
        Supplier<Object> sup = Object::new;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值