Lambda表达式记录

Stream流和Optionalhttps://blog.csdn.net/qq_45888932/article/details/123018483

一、Lambda表达式

二、Lambda使用步骤

1.Lambda的语法格式

1.1 lambda和匿名函数的区别

2.无参无返回值

 3.有参数没有返回值

4.有参数有返回值 

 5.方法引用

5.1 引用类的静态方法

5.2 引用对象实例方法

 5.3 引用类的实例方法

 5.4 引用构造器

三、函数式接口

总结


一、Lambda表达式

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

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

        Lambda表达式是函数式编程的体现;可以对匿名内部类的写法进行简化

核心思想:可推导可省略

二、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<T>  消费型接口

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

2.Supplier<T> 供给型接口,如果我们指定了接口的泛型是什么类型,那么接口中的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<String> 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<T,R> 函数型接口, 通常用于参数的处理

方法名说明
R apply(T t)将此函数应用于给定的参数
default <V> 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<String, Integer> fun) {
        int res = fun.apply(str);
        System.out.println(res);
    }
}

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

方法名说明
boolean test(T t)对给定的参数进行判断(判断逻辑由Lambda表达式实现),返回一个布尔值
default Predicate<T> negate()返回一个逻辑的否定,对应逻辑非
default Predicate<T> and(Predicate other)返回一个组合判断,对应短路与
default Predicate<T> 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<String> pred1) {
        return pred1.test(str);
    }
    public static boolean judge(String str, Predicate<String> pred1, Predicate<String> pred2) {
        return pred1.or(pred2).test(str);
    }
}

总结

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

       记录下学习jdk8新特性的lambda表达式和Stream流相关知识

       视频资源:b站搜索三更草堂,up小哥很棒的,支持!!

        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值