栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Lambda表达式记录

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Lambda表达式记录

一、Lambda表达式

二、Lambda使用步骤

1.Lambda的语法格式

1.1 lambda和匿名函数的区别

2.无参无返回值

 3.有参数没有返回值

4.有参数有返回值 

 5.方法引用

5.1 引用类的静态方法

5.2 引用对象实例方法

 5.3 引用类的实例方法

 5.4 引用构造器

三、函数式接口

总结


一、Lambda表达式

        java8中推出Lambda表达式。其底层还是通过编译器自动推断并生成匿名类来实现。可以使用更少的代码来实现同样的功能,使代码简洁的同时也使得Java支持闭包的功能

         面向函数,忽略面向对象的复杂语法;强调做什么,而不是以什么形式去做

二、Lambda使用步骤

1.Lambda的语法格式

        - 格式:

        (形式参数)-> {代码块}

        - Lambda表达式的使用前提:

        有一个接口,接口中有且仅有一个抽象方法

1.1 lambda和匿名函数的区别

所需类型不同

匿名内部类:可以是接口,也可以是抽象类,还可以是具体类

Lambda表达式:只能是接口

使用限制不同

如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类

如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式

实现原理不同

匿名内部类:编译之后,产生一个单独的.class字节码文件

Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成

2.无参无返回值

  正常写法:

public class demo01 {

    public static void main(String[] args) {
        Thread t1 = new Thread(new MyRunnable());   
    }
}
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程启动了");
    }
}

使用匿名内部类:

public class demo01 {

    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                System.out.println("线程又被启动了");
            }
        });
        t1.start();
    }
}

 使用Lambda表达式:

public class demo01 {

    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            System.out.println("线程又又被启动了");
        });
        t1.start();
    }
}

 3.有参数没有返回值

        在参数列表的部分传递参数即可 

public class demo02 {

    public static void main(String[] args) {
        // 使用匿名内部类
        test(new Test1() {
            @Override
            public void test1(String st) {
                System.out.println("创建实体类:" + st);
            }
        });

        // 使用Lamada
        test((String st) -> {
            System.out.println("lambda创建:" + st);
        });

    }

    public static void test(Test1 t1) {
        t1.test1("测试t1");
    }
}

// lamada表达式只能实现具有一个方法的接口,不能是抽象类
interface Test1 {
    void test1(String st);
}

4.有参数有返回值 

        在Lambda表达式中,当代码块中只有一句的情况下,参数列表的括号和return可以省略

public class demo03 {

    public static void main(String[] args) {
        // 正常lambda
         test((int a, int b) -> {return a + b;});

        // 缺省参数 参数类型可以省略
        test((a, b)-> {return a + b;});

        // 缺省参数 当函数体中只有一条语句,可以省略花括号和return
        test((a, b) -> a + b);
    }

    public static void test(Test3 t3) {
        int res = t3.sum(2, 3);
        System.out.println("返回结果:" + res);
    }
}

interface Test3 {
    int sum(int a, int b);
}

 5.方法引用

        在使用Lambda表达式的时候,我们实际上传递进去的代码就是一种解决方案:拿参数做操作

        如果我们在Lambda中所指定的操作方案,已经有地方存在相同方案,就没有必要重复书写代码;这里的意思方法调用处给定了参数,并且方法实现中代码使用了给定的参数,那么在方法的实现时参数就没必要传递了,由编译器自动推断就行(我这么理解的)

 通过方法引用来使用已经存在的方案

public class demo04 {

    public static void main(String[] args) {
        usePrintable(new Printable() {
            @Override
            public void PrintString(String s) {
                System.out.println("我正在修改:" + s + " 新加");
            }
        });

        // 正常lambda
        usePrintable((String s) -> {System.out.println("我正在修改:" + s + " 新加使用lambda");});

        //缺省参数
        usePrintable(s -> {
            System.out.println("省略参数类型的lambda " + s);
        });

        // 这种简化方法不能对原来的字符串进行修改等其他操作;由于传入的参数就是之后使用的,所以就将前后的直接省略了
        usePrintable(System.out::println);
    }

    public static void usePrintable(Printable p) {
        p.PrintString("hello java");
    }

}

interface Printable {
    void PrintString(String s);
}

推导与省略

如果使用Lambda,那么根据“可推导就是可省略”的原则,无需指定参数类型,也无需指定的重载形式,它们都将被自动推导

如果使用方法引用,也是同样可以根据上下文进行推导

方法引用是Lambda的孪生兄弟

5.1 引用类的静态方法

       public static int parseInt(String s)  是Integer类中的静态方法

public class demo05 {
    public static void main(String[] args) {
        test((String s) -> {return Integer.parseInt(s);});

        // 简化
        test(Integer::parseInt);
    }

    public static void test(Convert test) {
        int res = test.convert("123");
        System.out.println("返回结果:" + res);
    }
}
interface Convert {
    int convert(String str);
}

5.2 引用对象实例方法

         即引用类的成员方法,这里调用的  PrintString.printStringCase()

public class demo06 {

    public static void main(String[] args) {
        // 使用匿名内部类
        test(new Printer() {
            @Override
            public void printUpperCase(String s) {
                PrintString ps = new PrintString();
                ps.printStringCase(s);
            }
        });

        // 正常lambda
        test((String s) -> {
           PrintString ps = new PrintString();
           ps.printStringCase(s);
        });

        // 在抽取一层
        PrintString ps = new PrintString();
        test((s) -> ps.printStringCase(s));  // 此时这个就是方法引用,参数可以省略

        // 引用对象的实例方法
        test((ps::printStringCase));
    }

    public static void test(Printer p) {
        p.printUpperCase("hello world");
    }
}

interface Printer {
    void printUpperCase(String s);
}

class PrintString {
    public void printStringCase(String s) {
        String str = s.toUpperCase();
        System.out.println("转换后的字符串:" + str);
    }
}

 5.3 引用类的实例方法
public interface MyString {
    String mySubString(String s,int x,int y);
}

public class MyStringDemo {
    public static void main(String[] args) {
		//Lambda简化写法
        useMyString((s,x,y) -> s.substring(x,y));

        //引用类的实例方法
        useMyString(String::substring);
    }

    private static void useMyString(MyString my) {
       String s = my.mySubString("HelloWorld", 2, 5);
       System.out.println(s);
    }
}

 5.4 引用构造器

创建一个实体类:

class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

对象实例化,匿名函数到lambda的转换 

public class demo13 {

    public static void main(String[] args) {
        test(new StudentFactory() {
            @Override
            public Student build(String name, int age) {
                return new Student(name, age);
            }
        });

        test((name, age) -> {return new Student(name, age);});

        test((name, age) -> new Student(name, age));

        test(Student::new);
    }

    public static void test(StudentFactory sf) {
        Student student = sf.build("张三", 18);
        System.out.println(student);
    }

}

interface StudentFactory {
    Student build(String name, int age);
}

三、函数式接口

        只有一个抽象方法的接口就是函数式接口,可以添加@FunctionalInterface标明,但这个注解是可选项,可以不写。

常用的函数式接口:

根据不用的作用,java8中,内置了4个核心接口

1.Consumer  消费型接口

方法名说明
void accept(T t)对给定的参数执行此操作
default Consumer andThen(Consumer after)返回一个组合的Consumer,依次执行此操作,然后执行 after操作

2.Supplier 供给型接口,如果我们指定了接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据供我们使用。

方法名说明
T get()按照某种实现逻辑(由Lambda表达式实现)返回一个数据
import java.util.function.Supplier;

public class demo08 {

    public static void main(String[] args) {
        System.out.println(getString(() -> "乔巴"));
    }

    public static String getString(Supplier sup) {
        return sup.get();
    }
}

 自己实现获取的数据:

public class demo08 {

    public static void main(String[] args) {
        System.out.println(getString1(str -> str));
    }
    public static String getString1(TestSupplier ts) {
        String res = ts.getString("乔巴");
        return res;
    }
}
interface TestSupplier {
    String getString(String str);
}

3.Function 函数型接口, 通常用于参数的处理

方法名说明
R apply(T t)将此函数应用于给定的参数
default Function andThen(Function after)返回一个组合函数,首先将该函数应用于输入,然后将after函数应用于结果
import java.util.function.Function;

public class demo11 {

    public static void main(String[] args) {
        convert("123", (str) -> {
           return Integer.parseInt(str);
        });
        convert("123", Integer::parseInt);
    }

    // 将字符串转换为整数
    public static void convert(String str, Function fun) {
        int res = fun.apply(str);
        System.out.println(res);
    }
}

4.Predicate 断言型接口,或者判断型的接口

方法名说明
boolean test(T t)对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
default Predicate negate()返回一个逻辑的否定,对应逻辑非
default Predicate and(Predicate other)返回一个组合判断,对应短路与
default Predicate or(Predicate other)返回一个组合判断,对应短路或

import java.util.function.Predicate;

public class demo10 {

    public static void main(String[] args) {

        // 测试一个条件
        boolean res = judge("Helloworld", (str) -> str.length() < 11);
        System.out.println(res);
//        测试两个条件
        res = judge("Helloworld", (str) -> str.length() > 2, (str) -> str.length() < 7);
        System.out.println(res);

    }
    public static boolean judge(String str, Predicate pred1) {
        return pred1.test(str);
    }
    public static boolean judge(String str, Predicate pred1, Predicate pred2) {
        return pred1.or(pred2).test(str);
    }
}

总结

        简单对Lambda表达式的学习进行记录,包括基本Lambda和常用的函数式接口

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/704506.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号