java8新特性之Lambda表达式

java8在2014年就推出了,整天喊着8版本稳定,企业都用jdk8,结果8的特性现在才系统的学,罪过罪过啊!此系列博客可能3-4篇,带你全面地了解java8新特性。

其实我平常学习的时候看某些入门博客,总担心写的不全,所以希望自己以后写的技术博客能够把必须的尽可能全的总结出来,做到看一篇就能够入门的水平。

lambda快速体验

入门最快就是看demo啦,现在有个需求,让你在众多苹果中挑选出红色的苹果

  • 苹果类

    1public class Apple {2  String color;3  int weight;4  //省略构造函数,get方法5}
    

写法1:

 1public static List<Apple> filterGreenAppleWithNormal(List<Apple> apples) { 2    List<Apple> res = new ArrayList<>(); 3    for (Apple apple : apples) { 4        if ("red".equals(apple.getColor())) { 5            res.add(apple); 6        } 7    } 8    return res; 9}1011//调用12List<Apple> normal = filterGreenAppleWithNormal(apples);

如果再有一个需求说挑选出绿色的苹果呢,按照这种写法就需要创建一个新的类,然后仅仅把"red" 修改成"green" 其它都不变,这明显是不显示的。所以可以把颜色当成参数传进去

写法2:

 1public static List<Apple> filterGreenAppleWithArg(List<Apple> apples, String color) { 2    List<Apple> res = new ArrayList<>(); 3    for (Apple apple : apples) { 4        if (color.equals(apple.getColor())) { 5            res.add(apple); 6        } 7    } 8    return res; 9}1011//调用12List<Apple> arg = filterGreenAppleWithArg(apples, "red");

此时再有一个需求,需要筛选出一定重量或者某个颜色的苹果,需要怎么办呢,按照上述想法是把能想到的属性都堆到方法的参数中。

 1public static List<Apple> filterWeightOrColorWithArg(List<Apple> apples, String color, int weight, boolean flag) { 2    List<Apple> res = new ArrayList<>(); 3 4    for (Apple apple : apples) { 5        if (flag && color.equals(apple.getColor()) || !flag && apple.getWeight() > weight) { 6            res.add(apple); 7        } 8    } 9    return res;10}1112//调用13List<Apple> weightOrColor = filterWeightOrColorWithArg(apples, "", 500, false);

可以这样写吗,当然可以解决问题,但是如果有5个属性呢,6个属性呢,还有,参数中的flag是什么意思呢。

仔细一想,筛选颜色,筛选重量,这些的本质是在筛选,是一个行为(后面更专业称谓语),可以把行为抽象成一个接口

  • 行为接口
1public interface AppleFilter {2    boolean filter(Apple apple);3}

写法3:

首先需要实现这个接口来具体化行为

  • 筛选红色苹果实现类
1public class RedFilter implements AppleFilter {2    @Override3    public boolean filter(Apple apple) {4        return "red".equals(apple.getColor());5    }6}

回到使用

 1public static List<Apple> filterApples(List<Apple> apples, AppleFilter filter) { 2    List<Apple> res = new ArrayList<>(); 3 4    for (Apple apple : apples) { 5        if (filter.filter(apple)) { 6            res.add(apple); 7        } 8    } 910    return res;11}1213//调用14List<Apple> behavior = filterApples(apples, new GreenFilter());

这样看就舒服多了,当有新需求的时候,只需要再添加一个类,比如需求是筛选出重量超200g的苹果,只需要新建一个筛选类实现上述接口即可。

1public class WeightGt200Filter implements AppleFilter {2    @Override3    public boolean filter(Apple apple) {4        return apple.getWeight() > 200;5    }6}

还能怎样精简代码呢?熟悉Java的小伙伴到这里应该就想到了匿名内部类

写法4:

1List<Apple> innerClass = filterApples(apples, new AppleFilter() {2    @Override3    public boolean filter(Apple apple) {4        return "green".equals(apple.getColor());5    }6});

一般到这一步,比较不错的IDE就会开始提醒建议了

image-20210413193608641

<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">image-20210413193608641</figcaption>

这就到了我们今天的重点,lambda表达式

写法5:

1List<Apple> lambda = filterApples(apples, apple -> apple.getWeight() > 500);

没错,就是这么精简,不过filterApples 这个方法是不能省略的,但是扩展性相较1,2,简洁性相较3,4都好了很多

什么是lambda

可以把Lamdba表达式理解为简洁地表示可传递的匿名函数的一种形式:它没有名称,但它有参数列表、函数主题、返回类型,可能还有一个可以抛出的异常列表

书写格式: (参数) -> {主体}

正如上面写法5一样(apple) -> {apple.getWeight() > 500;}

  • lambda表达式对参数能够自动推断类型,当然也可以显示书写类型
  • 没有return语句,应为已经有隐含了return
  • lambda中可以有多行语句

使用案例:

  • () -> {}

  • () -> "java"

  • () -> {return "java";}

  • (int a, int b) -> a * b

  • () -> {System.out.println("hello"); System.out.println("java");}

如何才能使用lambda

使用函数式接口的时候才能使用lambda表达式

所谓函数式接口就是仅仅定义了一个抽象方法,比如一开始把行为抽象成一个AppleFilter 接口,该接口只有一个filter() 方法。注意是只有一个抽象方法,并不是只有一个方法,通俗来说是继承该接口的类只需要实现一个方法。

最常见的两个接口是ComparatorRunnable

image-20210413200933737

<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">image-20210413200933737</figcaption>

后来为了更方便地区分函数式接口,Java新的API中多了一个@FuntionalInterface ,该注解仅仅是表明该类是函数式接口(并不是必须的),如果有该注解的同时声明了两个抽象方法,那么将会报错

image-20210413201531957

<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">image-20210413201531957</figcaption>

java.util.function下4个常用的函数式接口

java.util.function 下主要有4个常用的函数式接口,FunctionPredicateConsumerPredicate ,随便截取其中的一个源码片段来看,其实也没啥好看的

image-20210413202124036

<figcaption style="line-height: inherit; margin: 0px; padding: 0px; margin-top: 10px; text-align: center; color: rgb(153, 153, 153); font-size: 0.7em;">image-20210413202124036</figcaption>

对这些函数式接口也是得看接口是如何声明的,这里就拿Predicate 举例,该接口主要是对传进来的对象进行一个处理,然后返回boolean 值。是不是有点熟悉,没错,就是和筛选苹果一样

  • predicateDemo
 1public static List<Apple> predicateDemo(List<Apple> apples, Predicate<Apple> predicate) { 2    List<Apple> res = new ArrayList<>(); 3    for (Apple apple : apples) { 4        if (predicate.test(apple)) { 5            res.add(apple); 6        } 7    } 8    return res; 9}1011//调用12List<Apple> predicate = predicateDemo(apples, apple -> "green".equals(apple.getColor()));

其他的也是同理,上才艺

  • functionDemo
 1public static List<Integer> functionDemo(List<Integer> nums, Function<Integer, Integer> function) { 2    List<Integer> res = new ArrayList<>(); 3    for (int num : nums) { 4        res.add(function.apply(num)); 5    } 6    return res; 7} 8 9//调用10List<Integer> function = functionDemo(Arrays.asList(1, 8, 7, 3, 9, 2), (num) -> num * 2);
  • consumerDemo
1public static void consumerDemo(List<Integer> list, Consumer<Integer> consumer) {2    for (int num : list) {3        consumer.accept(num);4    }5}67//调用8consumerDemo(Arrays.asList(1, 5, 6), (num) -> System.out.println(num));9consumerDemo(Arrays.asList(1, 5, 6), System.out::println);
  • supplierDemo
 1public static void supplierDemo(List<Integer> nums, Supplier<String> supplier) { 2    StringBuilder sb = new StringBuilder(); 3    for (int num : nums) { 4        sb.append(num).append(supplier.get()); 5    } 6    System.out.println(sb); 7} 8 9//调用10supplierDemo(Arrays.asList(1, 5, 6), ()->"java");

方法引用

上面的lambda写法是最精简的吗,不,不是的,还有最最最精简的写法,那就是利用方法引用

方法引用主要有3类:

  • 指向静态方法的方法引用
1Comparator<Integer> normalComparator = (a, b) -> a.compareTo(b);2Comparator<Integer> referenceComparator = Integer::compareTo;
  • 指向任一类型实例方法的方法引用
1Function<String, Integer> normalFunction = (str) -> str.length();2Function<String, Integer> referenceFunction = String::length;34BiPredicate<List<String>, String> normalPredicate = (strings, str) -> strings.contains(str);5BiPredicate<List<String>, String> referencePredicate = List::contains;
  • 指向现有对象的实例方法引用
1Apple apple = new Apple();2Supplier<Integer> normal = () -> apple.getWeight();3Supplier<Integer> reference = apple::getWeight;
  • 当然也可以用于构造函数
1Supplier<Apple> normalSupplier = () -> new Apple();2Supplier<Apple> referenceSupplier = Apple::new;

总结

以上就是java8中的lambda表达式,还有一些知识点是没有讲的,但是觉得不是特别必须,比如类型推断是怎么推断的,还有Lambda复合,抛出异常,拆箱装箱同样没有讲。然后一些东西也不是全盘托出,需要各位小伙伴去idea中进入到源码观看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容