Java Lambda表达式的使用及内部实现

Lambda表达式介绍

Lambda表达式是Java8中添加的新功能。使用Lambda表达式可以替代只有一个抽象函数接口实现,告别匿名内部类,代码看起来更简洁。Lambda表达式同时还提升了对集合、框架的迭代、遍历、过滤数据的操作。

函数式接口

只有一个抽象方法的接口称为函数式接口,在使用该类接口时可以用lambda表达式对该类接口的实现进行简化
案例

//注解,可自定义
@FunctionalInterface
public interface InterfaceTest{
	
	public void add();
}

Runnable接口也是函数式接口之一

Lambda表达式的使用

Lambda表达式也称为匿名函数,下面为最基本的使用方式

Lambda表达式的基本格式
x,y表示参数,可以有,也可以没有,参数类型可以由JVM自动推断,也可以显示写出,多个参数用逗号分隔, ->操作符后面的是执行的逻辑代码,一行以内可以不加花括号,多行需要加上花括号,只有一个参数时可以不加小括号,多于一个或0个参数都必须加小括号

(x,y)->{System.out.println(x+y)};
()->{};
()->{System.out.println(1);};
()->System.out.println(1);
()->{return 100;};//有return关键字必须加花括号
()->100;//无return关键字,但直接返回100
()->null;//无return关键字,直接返回null
(int x)->{return x+1;};
(int x)->x+1;//显示声明类型返回x+1后的结果
(x)->x+1;//JVM自动推导类型返回x+1后的结果
x->x+1;//只有一个参数可以不加小括号,非规范写法

lambda表达式最直观的简化
lambda对函数式接口进行简化时的返回值,需与lambda所简化实现的函数式接口下的的抽象函数一致!!!

简化方式如下

import java.awt.*;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.function.BiFunction;//jdk自带的函数式接口
import java.util.function.Consumer;//jdk自带的函数式接口
import java.util.function.Function;//jdk自带的函数式接口
import java.util.function.Supplier;//jdk自带的函数式接口

public class LambdaTest {
    public static void main(String[] args) throws Exception {
        Runnable runnable = new Runnable() {//匿名内部类+多态的写法
            @Override
            public void run() {
                System.out.println("running1 .....");
            }
        };
        runnable.run();

        Runnable runnable2 = ()->{//lambda+多态 = 声明一个匿名类实现Runnable接口的run方法,并创建后赋值给runnable2
            System.out.println("running2....");
        };
        runnable2.run();
		
		//同上
        Runnable runnable3 = ()-> System.out.println("running3....");
        runnable3.run();

        Callable<String> c1 = new Callable() {
            @Override
            public String call() throws Exception {
                return "zhangsan";
            }
        };
        System.out.println(c1.call());

		//指定Callable接口需要返回一个String
        Callable<String> c2 = ()->{return "lisi";};//lambda返回一个String
        System.out.println(c2.call());
		//同上
        Callable<String> c3 = ()->"wangwu";
        System.out.println(c3.call());
}

lambda表达式对匿名内部类的简化

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;//jdk自带的函数式接口
import java.util.List;

public class LambdaDemo {
    public static void main(String[] args) {
    	//原写法
//        Thread thread = new Thread(new Runnable() {
//            @Override
//            public void run() {
//                System.out.println("running.....");
//            }
//        });
//        thread.start();
//
		//lambda表达式简化
        new Thread(()->{System.out.println("running2.....");}).start();

        List<String> list = Arrays.asList("java","javascript","scala","python");
        //原写法
//        Collections.sort(list, new Comparator<String>() {
//            @Override
//            public int compare(String o1, String o2) {
//                return o1.length()-o2.length();
//            }
//        });
//        for(String str:list){
//            System.out.println(str);
//        }
		//lambda表达式简化
        Collections.sort(list,(a,b)->a.length()-b.length());
        list.forEach(System.out::println);
    }
}

lambda的返回值
先看下面几行lambda的实现

()->100;//无return关键字,但直接返回100
()->null;//无return关键字,直接返回null
()->get();

上面方式直接调用自定义get()方法的lambda,如果get()有返回值时,lambda有无返回值取决于它所实现的函数式接口,若lambda所实现的函数式接口的抽象方法返回值与get()的返回值不一致将报错


方法的引用

把一个方法作为参数传递,实现回调函数功能,方法的引用类似于C/C++的函数指针
如下代码,对一个list进行遍历的两种方法

List<String> list = Arrays.asList("a","b","c");
for (String s : list) {
System.out.println(s);
}
//传入printlin函数引用作为参数
list.forEach(System.out::println);//注意是::运算符,不是.运算符

同样的传入方法的引用也可以是lambda表达式所实现的方法(请记得lambda表达式也称为匿名函数),但作为方法的引用传递lambda表达式时不会立即执行,而是等待传入的方法进行调用(这里文字立即有歧义,其实如上面代码就是println等待forEach函数执行到某一处时调用println)


方法引用的分类
方法引用的分类
静态方法引用代码示例

import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class Test1 {

    static String put(){
        System.out.println("put.....");
        return "put";
    }

    public static void main(String[] args) {
//        System.out.println(put());
        Supplier<String> s1 = ()->Test.put();//lambda表达式实现接口
        System.out.println(s1.get());
		//Supplier jdk自带函数式接口,有一个get抽象函数
		//作为函数引用实现Supplier的get抽象方法,调用get等同于调用put
        Supplier<String> s2 = Test1::put;
        System.out.println(s2.get());
		//原理同上
		Supplier<String> s3 = Fun::hehe;
        System.out.println(s3.get());
    }
}

class Fun{
    public static String hehe(){
        return "hehe";
    }

    public static String toUpperCase(String str){
        return str.toUpperCase();
    }
}

实例方法引用代码示例

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class Test2 {
    public String put(){
        return "put...";
    }

    public void getSize(int size){
        System.out.println("size:"+size);
    }
    
    public static void main(String[] args) {
        System.out.println(new Test2().put());
        
        Supplier<String> s1 = ()->new Test2().put();
        Supplier<String> s2 = ()->{return new Test2().put();};
        Supplier<String> s3 = new Test2()::put;
        
        System.out.println(s1.get());
        System.out.println(s2.get());
        System.out.println(s3.get());

        //唯一的创建一个test2对象
        Test2 test = new Test2();

        Consumer<Integer> c1 = (size)->new Test2().getSize(size);
        Consumer<Integer> c2 = new Test2()::getSize;
        Consumer<Integer> c3 = test::getSize;

        c1.accept(123);
        c2.accept(123);
        c3.accept(123);
    }
}

对象方法引用代码示例

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;

public class Test3 {
    public static void main(String[] args) {

        BiConsumer<Too,String> bc = (too,str)->new Too().show(str);//现在传入的参数类型为Too和String,但后面new Too()创建了一个新的临时对象调用show
        BiConsumer<Too,String> bc2 = Too::show;
        bc.accept(new Too(),"abc");
        bc2.accept(new Too(),"def");

        BiFunction<Exec,String,Integer> bf1 = (e,s)->new Exec().test(s);//new Exec()创建新对象,与前面的e没关系
        BiFunction<Exec,String,Integer> bf2 = (e,s)-> e.test(s);
        BiFunction<Exec,String,Integer> bf3 = Exec::test;
        bf1.apply(new Exec(),"abc");
        bf2.apply(new Exec(),"def");
        bf3.apply(new Exec(),"ghi");
    }
}

class Exec{
    public int test(String name){
        return 1;
    }
}

class Too{
    public void show(String str){
        System.out.println("show ---too2"+str);
    }
}
}

构造方法引用代码示例

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class Test4 {
    public static void main(String[] args) {
        Supplier<Person> s1 = ()->new Person();
        Supplier<Person> s2 = Person::new;//构造方法引用
        s1.get();
        s2.get();//等同于调用Person();

        Supplier<List> s3 = ArrayList::new;
        Supplier<Set> s4 = HashSet::new;
        Supplier<Thread> s5 = Thread::new;
        Supplier<String> s6 = String::new;
        //Supplier<Integer> s7 = Integer::new; //Integer的构造方法必须传入一个参数,所以这条语句是错的
        
		//带参数的构造方法引用
        Consumer<Integer> c1 = (age)->new Account(age);
        Consumer<Integer> c2 = Account::new;
        c1.accept(123);
        c2.accept(456);

		//另外一种方式
        Function<String,Account> f1 = (str)->new Account(str);
        Function<String,Account> f2 = Account::new;
        f1.apply("abc");
        f2.apply("def");

    }
}

class Account{
    public Account(){
        System.out.println("调用无参构造方法");
    }

    public Account(int age){
        System.out.println("age 参数构造" +age);
    }

    public Account(String str){
        System.out.println("str 参数构造" +str);
    }
}

class Person{
    public Person(){
        System.out.println("调用无参的构造方法");
    }
}

Lambda表达式实现原理

Java Lambda表达式 实现原理分析

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页