温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java8中Lambda的特性是什么

发布时间:2021-06-30 17:48:48 来源:亿速云 阅读:142 作者:Leah 栏目:编程语言

Java8中Lambda的特性是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

lambda快速体验

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

  • 苹果类

public class Apple {
    String color;
    int weight;
	//省略构造函数,get方法
}
写法1:
public static List<Apple> filterGreenAppleWithNormal(List<Apple> apples) {
    List<Apple> res = new ArrayList<>();
    for (Apple apple : apples) {
        if ("red".equals(apple.getColor())) {
            res.add(apple);
        }
    }
    return res;
}

//调用
List<Apple> normal = filterGreenAppleWithNormal(apples);

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

写法2:
public static List<Apple> filterGreenAppleWithArg(List<Apple> apples, String color) {
    List<Apple> res = new ArrayList<>();
    for (Apple apple : apples) {
        if (color.equals(apple.getColor())) {
            res.add(apple);
        }
    }
    return res;
}

//调用
List<Apple> arg = filterGreenAppleWithArg(apples, "red");

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

public static List<Apple> filterWeightOrColorWithArg(List<Apple> apples, String color, int weight, boolean flag) {
    List<Apple> res = new ArrayList<>();

    for (Apple apple : apples) {
        if (flag && color.equals(apple.getColor()) || !flag && apple.getWeight() > weight) {
            res.add(apple);
        }
    }
    return res;
}

//调用
List<Apple> weightOrColor = filterWeightOrColorWithArg(apples, "", 500, false);

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

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

  • 行为接口

public interface AppleFilter {
    boolean filter(Apple apple);
}
写法3:

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

  • 筛选红色苹果实现类

public class RedFilter implements AppleFilter {
    @Override
    public boolean filter(Apple apple) {
        return "red".equals(apple.getColor());
    }
}

回到使用

public static List<Apple> filterApples(List<Apple> apples, AppleFilter filter) {
    List<Apple> res = new ArrayList<>();

    for (Apple apple : apples) {
        if (filter.filter(apple)) {
            res.add(apple);
        }
    }

    return res;
}

//调用
List<Apple> behavior = filterApples(apples, new GreenFilter());

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

public class WeightGt200Filter implements AppleFilter {
    @Override
    public boolean filter(Apple apple) {
        return apple.getWeight() > 200;
    }
}

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

写法4:
List<Apple> innerClass = filterApples(apples, new AppleFilter() {
    @Override
    public boolean filter(Apple apple) {
        return "green".equals(apple.getColor());
    }
});

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

Java8中Lambda的特性是什么

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

写法5:
List<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

Java8中Lambda的特性是什么

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

Java8中Lambda的特性是什么

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

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

Java8中Lambda的特性是什么

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

  • predicateDemo

public static List<Apple> predicateDemo(List<Apple> apples, Predicate<Apple> predicate) {
    List<Apple> res = new ArrayList<>();
    for (Apple apple : apples) {
        if (predicate.test(apple)) {
            res.add(apple);
        }
    }
    return res;
}

//调用
List<Apple> predicate = predicateDemo(apples, apple -> "green".equals(apple.getColor()));

其他的也是同理,上才艺

  • functionDemo

public static List<Integer> functionDemo(List<Integer> nums, Function<Integer, Integer> function) {
    List<Integer> res = new ArrayList<>();
    for (int num : nums) {
        res.add(function.apply(num));
    }
    return res;
}

//调用
List<Integer> function = functionDemo(Arrays.asList(1, 8, 7, 3, 9, 2), (num) -> num * 2);
  • consumerDemo

public static void consumerDemo(List<Integer> list, Consumer<Integer> consumer) {
    for (int num : list) {
        consumer.accept(num);
    }
}

//调用
consumerDemo(Arrays.asList(1, 5, 6), (num) -> System.out.println(num));
consumerDemo(Arrays.asList(1, 5, 6), System.out::println);
  • supplierDemo

public static void supplierDemo(List<Integer> nums, Supplier<String> supplier) {
    StringBuilder sb = new StringBuilder();
    for (int num : nums) {
        sb.append(num).append(supplier.get());
    }
    System.out.println(sb);
}

//调用
supplierDemo(Arrays.asList(1, 5, 6), ()->"java");

方法引用

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

方法引用主要有3类:

  • 指向静态方法的方法引用

Comparator<Integer> normalComparator = (a, b) -> a.compareTo(b);
Comparator<Integer> referenceComparator = Integer::compareTo;
  • 指向任一类型实例方法的方法引用

Function<String, Integer> normalFunction = (str) -> str.length();
Function<String, Integer> referenceFunction = String::length;

BiPredicate<List<String>, String> normalPredicate = (strings, str) -> strings.contains(str);
BiPredicate<List<String>, String> referencePredicate = List::contains;
  • 指向现有对象的实例方法引用

Apple apple = new Apple();
Supplier<Integer> normal = () -> apple.getWeight();
Supplier<Integer> reference = apple::getWeight;
  • 当然也可以用于构造函数

Supplier<Apple> normalSupplier = () -> new Apple();
Supplier<Apple> referenceSupplier = Apple::new;

看完上述内容,你们掌握Java8中Lambda的特性是什么的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注亿速云行业资讯频道,感谢各位的阅读!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI