JAVA8学习笔记-Lambda

JAVA8学习笔记-Lambda

声明:本文仅为学习记录,不保证绝对的准确性

1.一次关于苹果的改良

先定义一个苹果的实体类

public class Apple {
    private String color;
    private long weight;
    //省略了构造函数,getter和setter,toString
}

版本一

这是一段筛选出绿色苹果的代码,缺点很明显,扩展性很差。

public static List<Apple> findGreenApple(List<Apple> apples){

    List<Apple> list = new ArrayList<>();

    for (Apple apple : apples){
        if("green".equals(apple.getColor())){
            list.add(apple);
        }
    }
    return list;
}

版本二

版本二就是在版本一的基础上,加了一个入参,颜色。这样可以进一步选择要筛选的颜色,但仍旧很局限。

版本三

准备工作

public interface AppleFilter {
    boolean filter(Apple apple);
}
public static List<Apple> findApple(List<Apple> apples, AppleFilter appleFilter){
    List<Apple> list = new ArrayList<>();
    for (Apple apple : apples){
        if(appleFilter.filter(apple)){
            list.add(apple);
        }
    }
    return list;
}
//实现类
public static class GreenFilter implements AppleFilter{
    @Override
    public boolean filter(Apple apple) {
        return (apple.getColor().equals("green"));
    }
}

版本三定义了一个过滤接口,通过不停的增加这个接口的实现,可以满足各种各样的需求。但是随着需求不停的增加,会多出很多几乎只使用一次的实现类,这样就会显得不优雅。(大佬们都爱拿优雅说事情,跟个风不会挨打吧)

//新定义一个苹果类的list
List<Apple> list = Arrays.asList(new Apple("green",120),
                new Apple("red",130),new Apple("green",140));
//传入新定义的实现类
List<Apple> apples = findApple(list, new GreenFilter())

版本四

版本四采用了匿名内部类的方法,但是java8实战的作者说,这样代码还是很多,而且可读性不好。(心里有一丢丢的认同)

List<Apple> apples = findApple(list, new AppleFilter() {
    @Override
    public boolean filter(Apple apple) {
        return apple.getColor().equals("red");
    }
});
System.out.println(apples);

版本五

这个就是我们的lambda表达式了,是不是感觉和匿名内部类很像,其实本来就很像,底层实现也很像。但是,代码变少了对不对,对不对!(其实我觉得还行,但是还是向大佬们看齐,绝不向不优雅的代码做出妥协)

List<Apple> apples = findApple(list, apple -> {
    return apple.getColor().equals("green");
});
System.out.println(apples);

匿名内部类背锅系列

这段代码是作者为了diss匿名内部类的易读性差的特点贴出来的。

可以看出,核心就在于方法里的this代指的是谁,我们可以看出,this代表runnable类,因此结果是5。

public class MeaningOfThis
{
    public final int value = 4;
    public void doIt()
    {
        int value = 6;
        Runnable r = new Runnable(){
            public final int value = 5;
            public void run(){
                int value = 10;
                System.out.println(this.value);
            }
        };
        r.run();
    }
    public static void main(String...args)
    {
        MeaningOfThis m = new MeaningOfThis();
        m.doIt();
    }
}

2.@FunctionalInterface

这个接口要求类有且只有一个方法,包括继承过来的方法(default方法除外);如果没有标注的话,也可以用lambda表达式(在满足上面要求的情况下)。jdk1.8在很多方法中都加上了这个接口,例如runnable(),comparator()。

runnable()的演示。

//匿名内部类
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}).start();
//lambda表达式
new Thread(() -> System.out.println(Thread.currentThread().getName())).start();

这段程序的结果是

Thread-0
Thread-1

Comparator()的演示。

//匿名内部类
Comparator<Apple> byColor = new Comparator<Apple>() {
    @Override
    public int compare(Apple o1, Apple o2) {
        return o1.getColor().compareTo(o2.getColor());
    }
};
//lambda表达式
Comparator<Apple> byColor2 = (o1, o2) -> o1.getColor().compareTo(o2.getColor());
//list的sort实现,但没有单独定义comparator
list.sort((a1, a2) -> a1.getColor().compareTo(a2.getColor()));

3.Lambda语法和函数式接口

语法

先总结一下。

(parameters) -> expression
(parameters) -> { statements; }

举例子。

() -> {} // public void run()
() -> "haha" // public String run()
() -> {return "haha";} // public String run()

Predicate

predicate的作用像是筛选用的,或者说做判断。

//Predicate<T> 传入T
private static List<Apple> filter(List<Apple> source, Predicate<Apple> predicate) {
    List<Apple> result = new ArrayList<>();
    for (Apple a : source) {
        if (predicate.test(a))
            result.add(a);
    }
    return result;
}
//运行,筛选出绿色苹果
List<Apple> result = filter(list, (apple) -> apple.getColor().equals("green"));

//LongPredicate  传入一个Long型的值
private static List<Apple> filterByLongPredicate(List<Apple> source, 
                                                 LongPredicate predicate) {
    List<Apple> result = new ArrayList<>();
    for (Apple a : source) {
        if (predicate.test(a.getWeight()))
            result.add(a);
    }
    return result;
}
//运行,筛选出中重量大于100的苹果
List<Apple> result = filterByLongPredicate(list, w -> w > 100);

//BiPredicate 传入两个参数
private static List<Apple> filterByBiPredicate(List<Apple> source, 
                                               BiPredicate<String, Long> predicate) {
    List<Apple> result = new ArrayList<>();
    for (Apple a : source) {
        if (predicate.test(a.getColor(), a.getWeight()))
            result.add(a);
    }
    return result;
}
//运行,选出绿色和大于100克的苹果
List<Apple> result = filterByBiPredicate(list, (s, w) -> s.equals("green") && w > 100);

Consumer

consumer像是拿过来用掉了,没有判断,更没有返回值,单纯自己做一些处理。

//接收T,此处为apple
private static void simpleTestConsumer(List<Apple> source, Consumer<Apple> consumer) {
    for (Apple a : source) {
        consumer.accept(a);
    }
}
//运行,打印传进来的apple
simpleTestConsumer(list, a -> System.out.println(a));

//接收两个T,一个String,一个apple
private static void simpleBiConsumer(String c, List<Apple> source, BiConsumer<Apple, String> consumer) {
    for (Apple a : source) {
        consumer.accept(a, c);
    }
}
//运行,打印传进去的string和apple
simpleBiConsumer("XXX", list, (a, s) -> System.out.println(s + a);

Function

返回什么值,自己定义,最后一个参数为返回值。

//返回值为String,传入apple
private static String testFunction(Apple apple, Function<Apple, String> fun) {
    return fun.apply(apple);
}
//运行,只是做了个toString处理
String result = testFunction(new Apple("yellow", 100), (a) -> a.toString());

//返回值为apple,传入string和long
private static Apple testBiFunction(String color, long weight, BiFunction<String, Long, Apple> fun) {
    return fun.apply(color, weight);
}
//运行,新建apple对象
Apple a = testBiFunction("Blue", 130, (s, w) -> new Apple(s, w));

Supplier

//没有参数,只有返回值,此处定义为apple
private static Apple createApple(Supplier<Apple> supplier) {
    return supplier.get();
}
//运行,初始化一个apple对象
Apple a2 = createApple(() -> new Apple("Green", 100));
//等价于下面,不过下面的是string对象
//TODO,不太懂
Supplier<String> s = String::new;
String abc = s.get();//abc是空字符串

Runnable中用到的变量默认为final

int i = 0;
Runnable r = new Runnable() {
    @Override
    public void run() {
        System.out.println(i);//此处的i会报错,因为需要i为final型,下面的i++破坏了这个条件
    }
};
i++;

4.函数推导

静态方法

//静态方法,这段代码的作用为把字符串转为数字,Function的两个参数,String为入参,Integer为返回值,parseInt则为Integer的静态方法
Function<String, Integer> f = Integer::parseInt;
Integer result = f.apply("123");
System.out.println(result);

类方法

//类方法,这段代码的作用为找出字符串中特定位置的字符,BiFunction的String和Integer为入参,含义分别为要处理的字符串和要取出字符的位置,Character则为返回值类型,显然调用的String类的成员方法,因为双引号前为类名,而不是实例,所以直接传字符串即可
BiFunction<String, Integer, Character> f2 = String::charAt;
Character c = f2.apply("hello", 2);
System.out.println(c);

实例方法

//实例方法,作用于上面的一致,只不过不用传字符串,因为调用的方法本身就是这个实例的方法。
String string = new String("hello");
Function<Integer, Character> f3= string::charAt;
Character c2 = f3.apply(4);
System.out.println(c2);

猜你喜欢

转载自blog.csdn.net/qq_41620800/article/details/85538872