java8新特性Lambda表达式

lambda的语法

其实Lambda表达式的本质只是一个"语法糖",我们可以使用更少的代码来实现同样的功能,它允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

表达式形式
(parameters) -> expression
(parameters) -> {statments;}
() ->{}  // 什么都不做
() ->{ "hello"; } 等价于 () ->{ return "hello"; }
Lambda表达式几个简单例子
// 1. 不需要参数,返回值为 5  
() -> 5  
  
// 2. 接收一个参数(数字类型),返回其2倍的值  
x -> 2 * x  
  
// 3. 接受2个参数(数字),并返回他们的差值  
(x, y) -> x – y  
  
// 4. 接收2个int型整数,返回他们的和  
(int x, int y) -> x + y  
  
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值 (看起来像是返回void)  
(String s) -> System.out.print(s)

需要说明的是,不是每个接口都可以缩写成 Lambda 表达式。只有那些函数式接口(Functional Interface)才能缩写成 Lambda 表示式。

@FunctionalInterface

函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式。
Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。
如定义了一个函数式接口如下:

@FunctionalInterface
interface GreetingService 
{
    void sayMessage(String message);
}

那么就可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):

GreetingService greetService1 = message -> System.out.println("Hello " + message);

常用的@FunctionalInterface在包java.util.function中 它包含了很多类,所如下
在这里插入图片描述

其接口描述有:

接口描述
BiConsumer<T,U>代表了一个接受两个输入参数的操作,并且不返回任何结果
BiFunction<T,U,R>代表了一个接受两个输入参数的方法,并且返回一个结果
BinaryOperator代表了一个作用于于两个同类型操作符的操作,并且返回了操作符同类型的结果
BiPredicate<T,U>代表了一个两个参数的boolean值方法
BooleanSupplier代表了boolean值结果的提供方
Consumer代表了接受一个输入参数并且无返回的操作
Function<T,R>接受一个输入参数,返回一个结果
Predicate接受一个输入参数,返回一个布尔值结果。
Supplier无参数,返回一个结果

我们通过使用Predicate来了解接口方法
已知有一个Apple类,它有weight属性和color属性,我们来通过重量来筛选出合格的苹果

public class LambdaUsage {
public static void main(String[] args) {

// list中有3个不同颜色重量的苹果
List<Apple> list = Arrays.asList(new Apple("green",120), new Apple("red",150),new Apple("yellow",80));

// filterByWeight方法中筛选 质量大于100的苹果 条件
List<Apple> result = filterByWeight(list, w -> w > 100);
// 或者用 stram filter 条件过滤, filter里填写Predict类型
List<Apple> result2 = list.stream().filter(p -> p.getWeight() > 100).collect(Collectors.toList());

System.out.println("result 1:"+result);
System.out.println("result 2:"+result2);

}

// 条件筛选出苹果
private static List<Apple> filterByWeight(List<Apple> source, LongPredicate predicate){
List<Apple> result = new ArrayList<>();
for (Apple a : source) {
    if (predicate.test(a.getWeight()))
        result.add(a);
}
return result;
}

}

输出结果
在这里插入图片描述

Supllier 生产者

它与Function不同,它不接受参数,直接为我们生产一个指定的结果,有点像生产者模式:

Supplier<String> supplier = String::new;
 String s = supplier.get();
 System.out.println(s);

Supplier 接口有一个专属符号“::”,它表示直接返回一个值;

Consumer消费者

我们需要提供入参,用来被消费,没有返回值,如下面这段示例代码:

Consumer<Apple> ap = a -> System.out.println("the color of "+a.getColor()+" apple have"+ a.getWeight()+" kg");
        ap.accept(new Apple("red",100));
Optional,避免空指针问题

空指针异常是我们开发常见的问题,通常我们会写大量的非空条件判断来避免空指针问题。Java 8引入了一个新的Optional类,很好的用于避免空指针的出现,下图为Optinal类的所有方法:
在这里插入图片描述

  • 使用Optional创建类
// 创建一个空对象果篮
Optional<Basket> basket1  = Optional.empty();//Optional.of(new Basket("bamboo-basket",10,null));     
// 创建一个非null的果篮Optional
Optional<Basket> basket2  = Optional.of(new Basket("bamboo-basket",10, Arrays.asList(new Apple("red",120),new Apple("blue",100))));
// 判断果篮是否为空值果篮        System.out.println("basket:"+basket1.isPresent());
  • get()获取对象
// 获取basket
Basket basket = basket2.get();
  • 判断对象是否为空 isPresent
// 判断果篮是否为空,不为空就输出果篮
if (basket2.isPresent())
System.out.println(basket2.toString());
  • 如果不为空,则执行ifPresent
//  如果这个篮子不为空,执行lambda表达式,反之空的就不会执行
basket1.ifPresent((bask)->{
System.out.println("这个篮子是:"+bask.toString());
        });
  • 如果对象为空,就指定一个对象 orElse()
// 如果对象为空,则将它指定为一个塑料篮子
List<Apple> list = Arrays.asList(new Apple("red",200), new Apple("blue",220), new Apple("yellow",210));
// 原来不存在,所以给它一个新的值
Basket basket11 = basket1.orElse(new Basket("plastic-basket", 10, list));
System.out.println("new basket11:"+basket11.toString());
// 原来存在,直接赋原来值
Basket basket21 = basket2.orElse(new Basket("plastic-basket", 10, list));
System.out.println("new basket21:"+basket21.toString());
  • 如果为空,抛出异常 orElseThrow
// 如果果篮为空,抛出异常
 basket1.orElseThrow(IllegalStateException::new);
  • filter过滤
// 判断出有苹果的果篮
basket2.filter(basket -> {return basket.getList().size()>0;}).ifPresent((basket)->{
System.out.println("果篮里有水果");
  • 综上代码
public class OptionalTest {
public static void main(String[] args) {
// 创建一个空对象果篮
Optional<Basket> basket1  = Optional.empty();//Optional.of(new Basket("bamboo-basket",10,null));
// 创建一个非null的果篮Optional
Optional<Basket> basket2  = Optional.of(new Basket("bamboo-basket",10, Arrays.asList(new Apple("red",120),new Apple("blue",100))));
// 判断果篮是否为空值果篮
System.out.println("basket:"+basket1.isPresent());

// 判断果篮是否为空,不为空就输出果篮
if (basket2.isPresent())
   System.out.println(basket2.toString());

//  如果这个篮子不为空,执行lambda表达式,反之空的就不会执行
basket1.ifPresent((bask)->{
   System.out.println("这个篮子是:"+bask.toString());
});

// 如果对象为空,则将它指定为一个塑料篮子
List<Apple> list = Arrays.asList(new Apple("red",200), new Apple("blue",220), new Apple("yellow",210));
// 原来不存在,所以给它一个新的值
Basket basket11 = basket1.orElse(new Basket("plastic-basket", 10, list));
System.out.println("new basket11:"+basket11.toString());
// 原来存在,直接赋原来值
Basket basket21 = basket2.orElse(new Basket("plastic-basket", 10, list));
System.out.println("new basket21:"+basket21.toString());

// 如果果篮为空,抛出异常
basket1.orElseThrow(IllegalStateException::new);

// 判断出有苹果的果篮
basket2.filter(basket -> {return basket.getList().size()>0;}).ifPresent((basket)->{
   System.out.println("果篮里有水果");
});
}
}

水果篮子类

// 水果篮
class Basket{
private String name;
private int size;
private List<Apple> list;


public Basket(String name, int size, List<Apple> list) {
    this.name = name;
    this.size = size;
    this.list = list;
}
// getter and setter...
@Override
public String toString() {
    return "Basket{" +
            "name='" + name + '\'' +
            ", size=" + size +
            ", list=" + list +
            '}';
}
}
Stream流

当我们使用一个流的时候,通常包括三个基本步骤:
获取一个数据源(source)→ 数据转换→执行操作获取想要的结果;
每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换);
这就允许对其操作可以像链条一样排列,变成一个管道;

几种常用的stream
  • map构造平方数
List<Integer> nums = Arrays.asList(1, 2, 3, 4);
List<Integer> squareNums = nums.stream().map(n -> n * n).collect(Collectors.toList());
System.out.println("平方数:"+squareNums);

这里的map是一种映射关系,每输入一个元素,都按照规则转换成另外一个元素

  • filter 筛选出偶数
List<Integer> test = list.stream().filter(integer -> {
    return integer % 2 == 0;
}).collect(Collectors.toList());
System.out.println(test);

list为1到30的整数,通过筛选留下来满足规则的元素

  • sorted 倒排序
List<Integer> test2 = list.stream().sorted((a, b) -> {
    return b-a;
}).collect(Collectors.toList());
System.out.println("test2:"+test2);
  • Match匹配,这里分三种情况
    1、allMatch:Stream 中全部元素符合传入的 predicate,返回 true
    2、anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
    3、noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
  • 全部都是偶数
boolean b = list.stream().allMatch(integer -> {
            return integer % 2 == 0;
        });
System.out.println("全部是偶数:"+b);
  • 存在偶数
b = list.stream().anyMatch(integer -> {
            return integer % 2 == 0;
        });
System.out.println("存在偶数:"+b);
  • 全部都不是偶数
 b = list.stream().noneMatch(integer -> {
            return integer % 2 == 0;
        });
 System.out.println("都不是偶数:"+b);
  • forEach 每个数字前加上小星星
System.out.println("每个数字前加上一个\"*\":");
        list.stream().forEach(integer -> System.out.print("*"+integer+" "));
System.out.println("");
  • reduce
    这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。
    从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的reduce。
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
System.out.println("1:"+concat);
// 求最小值,minValue = -3.0
double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
System.out.println("2:"+minValue);
// 求和,sumValue = 10, 有起始值
int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
System.out.println("3:"+sumValue);
// 求和,sumValue = 10, 无起始值
sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
System.out.println("4:"+sumValue);
// 过滤,字符串连接,concat = "ace"
concat = Stream.of("a", "B", "c", "D", "e", "F").filter(x -> x.compareTo("Z") > 0).reduce("", String::concat);
System.out.println("5:"+concat);

  • 完整代码
public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();

    for (int i = 0; i < 30; i++) {
        list.add(i);
    }
    /**
     *  最常见的几种构造stream
     */

    // map 平方数,这里的map是一种映射关系,每输入一个元素,都按照规则转换成另外一个元素
    List<Integer> nums = Arrays.asList(1, 2, 3, 4);
    List<Integer> squareNums = nums.stream().map(n -> n * n).
            collect(Collectors.toList());
    System.out.println("平方数:"+squareNums);

    // filter 筛选出偶数,通过筛选留下来满足规则都元素
    List<Integer> test = list.stream().filter(integer -> {
        return integer % 2 == 0;
    }).collect(Collectors.toList());
    System.out.println(test);

    // 倒排序
    List<Integer> test2 = list.stream().sorted((a, b) -> {
        return b-a;
    }).collect(Collectors.toList());
    System.out.println("test2:"+test2);

    // Match,这里有3种情况
    /**
     * allMatch:Stream 中全部元素符合传入的 predicate,返回 true
     * anyMatch:Stream 中只要有一个元素符合传入的 predicate,返回 true
     * noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
     */
    // 全都是偶数
    boolean b = list.stream().allMatch(integer -> {
        return integer % 2 == 0;
    });
    System.out.println("全部是偶数:"+b);
    // 存在偶数
    b = list.stream().anyMatch(integer -> {
        return integer % 2 == 0;
    });
    System.out.println("存在偶数:"+b);
    // 都不是偶数
    b = list.stream().noneMatch(integer -> {
        return integer % 2 == 0;
    });
    System.out.println("都不是偶数:"+b);

    //  forEach ,每个数字前加上一个"*"
    System.out.println("每个数字前加上一个\"*\":");
    list.stream().forEach(integer -> System.out.print("*"+integer+" "));
    System.out.println("");

    /**
     * 这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),
     * 然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。
     * 从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。
     */
    // reduce
    // 字符串连接,concat = "ABCD"
    String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
    System.out.println("1:"+concat);
    // 求最小值,minValue = -3.0
    double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
    System.out.println("2:"+minValue);
    // 求和,sumValue = 10, 有起始值
    int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
    System.out.println("3:"+sumValue);
    // 求和,sumValue = 10, 无起始值
    sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
    System.out.println("4:"+sumValue);
    // 过滤,字符串连接,concat = "ace"
    concat = Stream.of("a", "B", "c", "D", "e", "F").filter(x -> x.compareTo("Z") > 0).reduce("", String::concat);
    System.out.println("5:"+concat);
}
其他
两个冒号代表什么

双冒号运算就是Java中的[方法引用],[方法引用]的格式是 类名::方法名
一般是用作Lambda表达式

例如:
表达式

person -> person.getName();

可以替换成:

Person::getName

表达式

() -> new HashMap<>();

可以替换成:

HashMap::new

这种[方法引用]或者说[双冒号运算]对应的参数类型是Function<T,R> T表示传入类型,R表示返回类型。

注解

类型注解
重复注解
### 回答1: Java 8引入了lambda表达式作为一种新的编程语言特性。lambda表达式是一种匿名函数,它可以作为参数传递给方法或存储在变量中。它可以简化代码,使代码更加易读和易维护。lambda表达式的语法非常简洁,可以用来替代匿名内部类。它可以在集合框架中使用,使代码更加简洁和易读。lambda表达式Java 8中最重要的新特性之一,它使Java编程更加现代化和高效。 ### 回答2: Lambda 表达式Java 8 中最重要的新增特性之一,它可以让我们以更简洁的方式来编写代码,并且能够更优雅的解决许多问题。 Lambda 表达式本身是一个匿名函数,它可以被当做对象进行传递和处理。它强调的是函数式编程思想,将函数作为一等公民,并支持灵活的函数组合。Lambda 表达式通常由左侧的参数列表、箭头符号和右侧的函数体组成。例如: ``` (x, y) -> x + y ``` 上述代码定义了一个 lambda 表达式,这个表达式接受两个参数 x 和 y,然后返回它们的和。 Lambda 表达式的用途非常广泛,它们通常用于简化代码,比如用于普通的遍历集合和数组: ``` List<String> names = Arrays.asList("alice", "bob", "charlie"); names.forEach(name -> System.out.println(name)); ``` Lambda 表达式还可以用于函数式接口,这是一种只包含一个抽象方法的接口。函数式接口可以被当做 lambda 表达式类型,这意味着我们可以使用 lambda 表达式来创建这种类型的对象。例如: ``` interface Calculator { int calculate(int a, int b); } Calculator add = (a, b) -> a + b; Calculator sub = (a, b) -> a - b; ``` 上述代码定义了一个接口类型 Calculator,它包含一个抽象方法 calculate,并且使用 lambda 表达式来定义 add 和 sub 两个对象,它们分别代表加法和减法。 Lambda 表达式还支持方法引用,这是一种更简洁的语法形式,它允许我们使用方法名来代替 lambda 表达式的函数体。例如: ``` List<String> names = Arrays.asList("alice", "bob", "charlie"); names.forEach(System.out::println); ``` 上述代码使用了方法引用,它代替了之前的 lambda 表达式。 总之,Java 8 的 Lambda 表达式是一项非常有用的功能,它提供了一种更简单的方式来编写代码,让我们的代码更加简约且易于阅读。同时,它也是一种函数式编程思想的体现,让 Java 开发者能够更好的应用这些思想来解决实际问题。 ### 回答3: Java8的lambda表达式是一个Java编程语言的新特性,它可以方便地为函数式接口创建实例。Lambda表达式允许你直接以更加简单和精简的方式来定义内部类,并且能够省略掉那些没有用的代码。 在Java 8中,Lambda表达式通过一个箭头“->”来定义。在箭头左边是参数列表,这些参数可以是任何类型,但是Lambda表达式中只能有一个方法参数。在箭头右边是Lambda表达式的主体,也就是这个Lambda表达式所要执行的代码块。 Lambda表达式还可以访问外部作用域中的变量,这是通过捕获变量的方式来实现的。Lambda表达式在使用外部变量时会将其捕获到Lambda表达式内部,从而形成一个闭包,这使得Lambda表达式能够访问外部的变量。 Lambda表达式的使用能够使得代码更加简洁,能够将代码逻辑更加清晰地表达。在Java8中,Lambda表达式被广泛应用于集合的处理,比如通过对集合进行排序、过滤、映射等操作,能够更加简单地处理数据集合。Lambda表达式还被应用于多线程的编程中,能够使得并发编程更加方便和简单。 总之,Java 8的Lambda表达式是一个很有用的新特性。它能够使得Java代码更加简洁和易于理解,减少了冗余的结构和语法。同时,它也提供了更加灵活的编程方式,使得Java编程能够更加高效和便利。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值