Jdk8特性lambda


在这里插入图片描述
在这里插入图片描述
在java的历史中,java8的变化举重若轻

1、让方法参数具备行为能力

1.1、找绿色的苹果

在这里插入图片描述
其中apple类是一个实体类它有颜色、重量等属性
上面的例子是遍历参数中的apple集合找到颜色为绿色的苹果
用下面的这个方法创建出需要的apple集合

List<Apple> list = Arrays.asList(new Apple("green", 150), new Apple("yellow", 120), new Apple("green", 170));

1.2、找红色的苹果

最初级的办法就是另外再写一个方法。
高级一点的就是在上面方法上加一个参数为我们需要找的颜色

在这里插入图片描述

1.3、根据颜色又根据重量去查找

1.3.1、策略模式的应用,方法参数具备了行为

这种仓促的变化代表着需求的不断变化,对于我们写程序的来说如何让调用者察觉不到这种变化?

public class FilterApple {
   定义一个接口作为作为方法的参数,具体的业务算法作为他的实现类
    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 GreenAnd160WeightFilter implements AppleFilter {
        @Override
        public boolean filter(Apple apple) {
            return (apple.getColor().equals("green") && apple.getWeight() >= 160);
        }
    }
     public static void main(String[] args) throws InterruptedException {
         List<Apple> list = Arrays.asList(new Apple("green", 150), new Apple("yellow", 120), new Apple("green", 170));
         List<Apple> result = findApple(list, new GreenAnd160WeightFilter());
        System.out.println(result);、
     }
   }
1.3.2、直接使用匿名内部类来调用

对于上一节的策略模式,如果我们每一个业务逻辑都要写一个filter来实现这个业务的具体算法,是很麻烦的

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

2、使用lamda表达式改写

2.1、优点:相比较上面的例子

  1. 一个是代码量比较大
  2. 另一个是this的混淆(这个理由有点牵强)
    如下在这个匿名类中输出的是多少
    在这里插入图片描述
    当然是5了
  3. 最重要的是java8内存的变化
    在这里插入图片描述

在这里插入图片描述
可以看出jdk8比jdk6少了一个P,多了M、CCS
具体后面再说

2.2、详细使用

当一个接口中有且只有一个抽象方法我们就可以使用lamda表达式(default、static方法除外)
接口上可以标上注解@FunctionalInterface(也可以不写这个注解,它起到标识验证的作用)

 @FunctionalInterface
    public interface AppleFilter {
        boolean filter(Apple apple);
    }

在这里插入图片描述
还可以继续简写

参数类型可以推导,所以不用写参数类型
如果只有一个参数,可以去掉参数两边的括号
在这里插入图片描述

2.3、其他例子

线程的对比

       new Thread(new Runnable() {

            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }).start();

        new Thread(() -> System.out.println(Thread.currentThread().getName())  ).start();
        Thread.currentThread().join();

以及
在这里插入图片描述在这里插入图片描述
这些接口

3、lambda表达式语法

在这里插入图片描述
方法引用、类型推导、组合
他可以被定义、有传递参数、可以有返回值、可以抛出一系列异常

3.1、参数传递

在这里插入图片描述
在这里插入图片描述
红色语句两边没有加花括号,它的返回类型可以自动推导
如果加了花括号就必须写return
在这里插入图片描述

3.2、被定义(function接口)

在这里插入图片描述
lambda是一个最基本的东西,它主要是为我们 的function接口来服务的

  Function<String,Integer> flambda = s->s.length();
  Integer hello = flambda.apply("hello");
  System.out.println(hello);//5

Function源码

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);

    /**
     * Returns a composed function that first applies the {@code before}
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of input to the {@code before} function, and to the
     *           composed function
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the {@code before}
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see #andThen(Function)
     */
    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

Function 接口中还有default static方法

3.3、Predicate接口

可以看出,它是给一个参数返回一个boolean值
源码

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);

使用

        Predicate<String> b = s->s.length()>2;
        System.out.println(b.test("hello")); //true
        System.out.println(b.test("h"));     //false

3.4、其他合法的lambda表达式及语法总结

在这里插入图片描述
在这里插入图片描述
#### 3.5lambda语法总结

4、Lambda使用深入解析

       Runnable r1 = () -> System.out.println("Hello");

        Runnable r2 = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello");
            }
        };

        process(r1);
        process(r2);
        process(() -> System.out.println("Hello"));*/

这三个打印完全一致

4.1、Predicate<`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> list = Arrays.asList(new Apple("green", 120), new Apple("red", 150));
        List<Apple> greenList = filter(list, (apple) -> apple.getColor().equals("green"));
        System.out.println(greenList);

在这里插入图片描述可以接受两个参数
在这里插入图片描述只接受一个int参数
在这里插入图片描述
在这里插入图片描述

4.2、Consumer<`T>

在这里插入图片描述

private static void simpleTestConsumer(List<Apple> source, Consumer<Apple> consumer) {
        for (Apple a : source) {
            consumer.accept(a);
        }
    }
simpleTestConsumer(list, a -> System.out.println(a));

在这里插入图片描述两个参数

 BiConsumer<String,Integer> bc = (s,i)-> System.out.println(s.concat(i.toString()));
 bc.accept("hello",3000);//hello3000

4.3、Function<T,R>

在这里插入图片描述

 private static String testFunction(Apple apple, Function<Apple, String> fun) {
        return fun.apply(apple);
    }
 String result3 = testFunction(new Apple("yellow", 100), (a) -> a.toString());
        System.out.println(result3);

BiFunction<T, U, R>
在这里插入图片描述
IntFunction
在这里插入图片描述

4.4、Supplier<`T>

在这里插入图片描述

Supplier<String> s = String::new;   //method inference.
System.out.println(s.get().getClass());

  private static Apple createApple(Supplier<Apple> supplier) {
        return supplier.get();
    }
Apple a2 = createApple(() -> new Apple("Green", 100));
System.out.println(a2);

4.5、Runnable

在这里插入图片描述
在这里插入图片描述
lambda表达式实际也是一个匿名函数,和内部类一样,
如果在匿名函数里操作外面的变量,则这个变量必须是final
如果仅仅是引用则不需要

5、Lambda方法推导详细解析

//这个方法是将一个字符串输出两遍
    private static <T> void useConsumer(Consumer<T> consumer, T t) {
        consumer.accept(t);
        consumer.accept(t);
    }
    
    public static void main(String[] args) {
     Consumer<String> consumer = (s) -> System.out.println(s);
     useConsumer(consumer, "Hello Alex");
 }

上面是正常方法调用
下面说方法推导
可以省略Consumer的定义

  useConsumer(s -> System.out.println(s), "Hello Alex");
  useConsumer(System.out::println, "Hello Wangwenjun");

再看 list.sort的方法推导

       List<Apple> list = Arrays.asList(new Apple("abc", 123), new Apple("Green", 110), new Apple("red", 123));
        System.out.println(list);
        list.sort((a1, a2) -> {return a1.getColor().compareTo(a2.getColor());};
        
        list.sort((a1, a2) -> a1.getColor().compareTo(a2.getColor()));

        System.out.println(list);

list.stream().forEach的函数推导

         list.stream().forEach(a -> System.out.println(a));
        System.out.println("==========================");
        list.stream().forEach(System.out::println);  //推导之后更加简洁

什么情况下可以进行方法推导(函数推导)呢
下面分小节细说

5.1、可以通过类的静态方法推断 ::

在这里插入图片描述

        int value = Integer.parseInt("123");

        Function<String, Integer> f = Integer::parseInt;//方法推导
        Integer result = f.apply("123");
        System.out.println(result);

5.2、实例方法推断 ::

在这里插入图片描述

        String  s = new String("hello");
        char c1 = s.charAt(2);
        
        BiFunction<String, Integer, Character> f2 = String::charAt;
        Character c = f2.apply("hello", 2);
        System.out.println(c);

5.3、已有对象的实例方法 ::

在这里插入图片描述

        String str = new String("Hello");
        Function<Integer, Character> f3 = str::charAt;
        Character c2 = f3.apply(4);
        System.out.println(c2);

可以看看与实力方法的区别

5.4、构造函数的推导::

一个参数

        Supplier<String> supplier = String::new;

        String s = supplier.get();
        System.out.println(s);

两个参数

        BiFunction<String, Long, Apple> appleFuntion = Apple::new;

        Apple apple = appleFuntion.apply("red", 100L);
        System.out.println(apple);

三个参数(自己构造)

@FunctionalInterface
public interface ThreeFunction<T, U, K, R> {

    R apply(T t, U u, K k);

}

        ThreeFunction<String, Long, String, ComplexApple> threeFunction = ComplexApple::new;
        ComplexApple complexApple = threeFunction.apply("Green", 123L, "FuShi");
        System.out.println(complexApple);

5.5、list.sort优化

优化

        List<Apple> list2 = Arrays.asList(new Apple("abc", 123), new Apple("Green", 110), new Apple("red", 123));

        System.out.println(list2);
        list2.sort(Comparator.comparing(Apple::getColor));//方法推导
        System.out.println(list2);

推导过程
将前面的sort与这个进行对比发现简洁了很多
在这里插入图片描述
看它源码
java.util.List#sort 方法源码

    @SuppressWarnings({"unchecked", "rawtypes"})
    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }

再看java.util.Comparator.comparing源码

   public static <T, U> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        Objects.requireNonNull(keyExtractor);
        Objects.requireNonNull(keyComparator);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
                                              keyExtractor.apply(c2));
    }

它返回值中使用了一个 & 这个有什么用
在这里插入图片描述
在这里插入图片描述
对比

list.sort((a1, a2) -> a1.getColor().compareTo(a2.getColor()));
          (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1), keyExtractor.apply(c2));


Function<T, R> keyExtractor.apply(c1)
返回 Function 接口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值