Java Lambda初体验

296 阅读3分钟

一、入门示例

代码git地址:gitee.com/ggg/TestJav…

需求:有一堆苹果,这些苹果的颜色不同、大小不一。现在要从中筛选出黄色的苹果。

public class Apple {
    private String color;
    private Integer weight;
    ....省略get set toString 方法
}

1.采用硬编码的方式

public class AppleFilterTest {
    private static List<Apple> apples;
    @BeforeClass
    public static void initApples(){
        apples = Arrays.asList(
                new Apple("red",1),
                new Apple("yellow",2),
                new Apple("black",3),
                new Apple("green",2)
                );
    }
    @Test
    public void filterApples1(){
        List<Apple> appleList = filterApplesByColor(apples);
        for (Apple apple : appleList) {
            System.out.println(apple);
        }
    }
   
    private List<Apple> filterApplesByColor(List<Apple> apples){
        List<Apple> result = new ArrayList<>();
        for (Apple apple : apples) {
            if("yellow".equals(apple.getColor())){
                result.add(apple);
            }
        }
        return result;
    }

缺陷,需求一旦变更,就需要去修改原来的代码,灵活性太差。比如,现在的需求变为需要筛选出红色的苹果。

2.采用参数传递

@Test
    public void filterApples2(){
        List<Apple> appleList = filterApplesByColor1(apples,"red");
        for (Apple apple : appleList) {
            System.out.println(apple);
        }
    }

缺陷,如果需求变更为根据重量去筛选,也需要去修改代码。

3.采用策略模式

@Test
public void filterApples3(){
    List<Apple> appleList = filterApples(apples,new PredicateByColor("red"));
    for (Apple apple : appleList) {
        System.out.println(apple);
    }
}

public class PredicateByColor implements MyPredicate<Apple>{
    private String color;
    public PredicateByColor(String color) {
        this.color = color;
    }
    @Override
    public boolean test(Apple e) {
        return e.getColor().equals(color);
    }
}

public interface MyPredicate<T> {
    boolean test(T e);
}

这种方式看似很完美了,如果需求变更,只需要去实现MyPredicate接口,还有没有更好的呢?

4.采用匿名内部类

@Test
public void filterApples4(){
        List<Apple> appleList = filterApples(apples, new MyPredicate<Apple>() {
            @Override
            public boolean test(Apple e) {
                return "red".equals(e.getColor());
            }
        });
        for (Apple apple : appleList) {
            System.out.println(apple);
        }
}

匿名内部类减少了类的数量,还有没有更好的呢?

5.采用函数式

@Test
public void filterApples5(){
        List<Apple> appleList = filterApples(apples, e -> "red".equals(e.getColor()));
        for (Apple apple : appleList) {
            System.out.println(apple);
        }
}

函数式,将函数作为参数传递到方法中,这样代码看起更简洁。其实Java中的函数式和匿名类在JVM层面是有不同实现的,具体可采用javap去查看生成的字节码。

二、Java Lambda语法

1.Lambda操作符(也可称为箭头符号)

->

箭头符号左侧:参数列表

箭头符号右侧:方法体

()->{}

2.方法分类

2.1 无参、无返回值

@Test
    public void test1() {
    //普通写法
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("------1-----");
            }
        };
        r.run();
        System.out.println("---------------------------");
        //函数式写法
        Runnable r2 = () -> System.out.println("------2------");
        r2.run();
        System.out.println("---------------------------");
        //方法体要是多行,需要加上 {}
        Runnable r3 = () -> {
            System.out.println("------2------");
            System.out.println("------2------");
        };
        r3.run();
    }

2.2 无参、有返回值

 @Test
    public void test2(){
    // 普通写法
        Supplier<Integer> supplier = new Supplier<Integer>() {
            @Override
            public Integer get() {
                return 100;
            }
        };
        System.out.println(supplier.get());
        System.out.println("-------------");
        //函数式写法
        supplier=()->{
            System.out.println("******");
            return 110;
        };
        System.out.println(supplier.get());
    }

2.3有参、无返回值

@Test
    public void test3() {
        //非Lambda写法
        Consumer<String> consumer = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println("-----" + s + "---------");
            }
        };
        System.out.println("----------一个参数、无返回值的普通写法------------");
        consumer.accept("hello");

        //如果只有一个参数,箭头符号左边的小括号可以省略
        Consumer<String> consumer2 = s -> System.out.println("-----" + s + "---------");
        System.out.println("----------一个参数、无返回值的Lambda写法------------");
        consumer.accept("hello");

        //有两个或者多个参数
        BiConsumer<Integer,String> biConsumer= (integer, s) -> System.out.println("---integer="+integer+"-----s=" + s + "---------");
        biConsumer.accept(1,"aa");
    }

2.4有参、有返回值

@Test
    public void test4(){
        //如果方法体中是一行代码,可以省略{}、return 省略大括号之后加上return 还会报错,所以大括号和return都不能写.
        Comparator<Integer> comparator= (x,y) ->  Integer.compare(x,y);
        System.out.println(comparator.compare(1,6));
        //方法体中多行代码,不能省略{},return 也不能省略
        Comparator<Integer> comparator2= (x,y) -> {
            System.out.println("--------");
            return Integer.compare(x,y);
        };
        System.out.println(comparator2.compare(10, 9));
    }

三、JAVA8内置四大核心函数式接口

1.Consumer void accept(T t); 有参数 无返回值

2.Supplier T get();无参数 有返回值

3.Predicate boolean test(T e);有参数 返回值为boolean类型

4.Function<T, R> R apply(T t);有参数 有返回值

这四个函数式接口,能满足我们的很多场景,减少了我们自定义函数式接口。

四、方法引用和构造器引用

1.方法引用

1.1 实例方法引用

1.2 静态方法引用

2.构造器引用

2.1 无参

2.2 有参

3.数组引用

五、接口中的默认方法和静态方法