Java8新特性——Lambda表达式的使用

67 篇文章 16 订阅

1、Lambda表达式的简介

Java8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。当开发者在编写Lambda表达式时,也会随之被编译成一个函数式接口。

Lambda 表达式(Lambda Expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的Lambda抽象(Lambda Abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

【示例】下面这个例子是使用Lambda表达式的简单示例,代码不仅简洁,而且还可读。

/**
 * Lambda表达式的使用
 * @author pan_junbiao
 */
@Test
public void simpleTest()
{
    //1、使用传统方式创建线程
    Thread thread1 = new Thread(new Runnable()
    {
        //重写run()方法
        @Override
        public void run()
        {
            System.out.println("线程启动(使用传统方式)");
        }
    });
    thread1.start();

    //2、使用Lambda表达式创建线程
    Thread thread2 = new Thread(()->System.out.println("线程启动(使用Lambda表达式)"));
    thread2.start();
}

执行结果:

 

2、Lambda表达式的语法

Lambda表达式的语法如下:

() -> {}

Lambda的语法定义,它由三部分组成:

参数列表:Lambda表达式的参数列表,参数的类型可以省略,因为编译器会根据方法体中的参数来确定类型。

操作符(->):Java8中引入了一个新的操作符 "->" 该操作符称为箭头操作符或Lambda操作符。

代码块:Lambda表达式中所需执行的功能, 即Lambda方法体,如果代码块只有一条语句时可以将“{}”省略;如果只有一条return语句,那么“return”可以省略。

Lambda表达式本质上是一个匿名方法。让我们来看下面这个例子:

public int add(int x, int y) {
    return x + y;
}

转成Lambda表达式:

(int x, int y) -> x + y;

参数类型也可以省略,因为编译器会根据方法体中的参数来确定类型:

(x, y) -> x + y;

或者:

(x, y) -> { return x + y; } //显式指明返回值

2.1 无参数,无返回值

/**
 *  无参数,无返回值
 *  @author pan_junbiao
 */
@Test
public void test1()
{
    Runnable runnable = ()->System.out.println("线程启动");
    runnable.run();
}

执行结果:

2.2 有参数,无返回值

/**
 *  有参数,无返回值
 *  @author pan_junbiao
 */
@Test
public void test2()
{
    Consumer<String> consumer = s -> System.out.println(s);
    consumer.accept("您好,欢迎访问 pan_junbiao的博客");
}

执行结果:

2.3 无参数,有返回值

/**
 *  无参数,有返回值
 *  @author pan_junbiao
 */
@Test
public void test3()
{
    Supplier<String> supplier = ()->"您好,欢迎访问 pan_junbiao的博客".substring(8, 22);
    System.out.println(supplier.get());
}

 执行结果:

2.4 有一个参数,有返回值

/**
 *  有一个参数,有返回值
 *  @author pan_junbiao
 */
@Test
public void test4()
{
    Function<String, String> function = (s)->s.substring(8, 22);
    System.out.println(function.apply("您好,欢迎访问 pan_junbiao的博客"));
}

 执行结果:

2.5 有两个参数,有返回值

/**
 *  有多个参数,有返回值
 *  @author pan_junbiao
 */
@Test
public void test5()
{
    BiFunction<String,String,String> biFunction = (String s1, String s2) -> s1.concat(s2);
    System.out.println(biFunction.apply("您好,欢迎访问 ","pan_junbiao的博客"));
}

 执行结果:

 

3、函数式接口

Lambda表达式的目标类型必须是“函数式接口(functional interface)”。函数式接口:只包含一个抽象方法的接口。接口可以包含多个默认方法、类方法,但关键是一个抽象方法。所谓函数式接口,指的是只有一个抽象方法的接口。函数式接口可以被隐式转换为Lambda表达式。函数式接口可以用@FunctionalInterface注解标识。

3.1 自定义函数式接口

Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。@FunctionalInterface 就是用来指定某个接口必须是函数式接口,所以 @FunInterface 只能修饰接口,不能修饰其它程序元素。

【示例】使用@FunctionalInterface注解自定义函数式接口,要求接受两个参数,并且有返回值。

(1)创建名称为MyFunction的函数式接口。

/**
 * 自定义函数式接口
 * @author pan_junbiao
 **/
@FunctionalInterface
public interface MyFunction<T, U, R>
{
    R apply(T t, U u);
}

(2)使用函数式接口实现数字的加法、减法、乘法、除法、字符串拼接。

/**
 *  使用自定义函数式接口
 *  @author pan_junbiao
 */
@Test
public void MyFunctionTest()
{
    //加法
    MyFunction<Integer,Integer,Integer> addFunction1 = (Integer x,Integer y) -> x+y;
    System.out.println("加法执行结果:" + addFunction1.apply(3,5));

    //减法
    MyFunction<Integer,Integer,Integer> subFunction1 = (Integer x,Integer y) -> x-y;
    System.out.println("减法执行结果:" + subFunction1.apply(10,4));

    //乘法
    MyFunction<Integer,Integer,Integer> mulFunction1 = (Integer x,Integer y) -> x*y;
    System.out.println("乘法执行结果:" + mulFunction1.apply(20,5));

    //除法
    MyFunction<Integer,Integer,Integer> divFunction1 = (Integer x,Integer y) -> {
        //被除数不能为0
        if(y==0)
        {
            return 0;
        }

        return x/y;
    };
    System.out.println("除法执行结果:" + divFunction1.apply(20,4));

    //字符串拼接
    MyFunction<String,String,String> strFunction = (String s1, String s2) -> s1.concat(s2);
    System.out.println("字符串拼接结果:" +strFunction.apply("您好,欢迎访问 ","pan_junbiao的博客"));
}

执行结果:

3.2 Java内置的函数式接口

Java已经提供了一些函数式接口,这些接口在 java.util.function 包下,常用的函数式接口如下:

函数式接口参数类型返回类型说明
Consumer<T>T接受一个参数T,无返回结果。
Supplier<T>T不接受任何参数,返回结果T。
Function<T, R>TR接受一个参数T,返回结果R。
Predicate<T>Tboolean接受一个参数T,返回结果boolean类型。
UnaryOperator<T>TT继承自Function<T, T>,接受一个参数T,返回相同类型T的结果。
BiFunction<T, U, R>T, UR接受两个参数T和U,返回结果R。
BinaryOperator<T>TT继承自BiFunction<T, T, T>,接受两个相同类型T的参数,返回相同类型T的结果。

【示例】使用Consumer<T>、Supplier<T>、Function<T, R>、Predicate<T>内置的函数式接口。

/**
 * 使用内置的函数式接口
 * @author pan_junbiao
 */
@Test
public void FunctionalInterfaceTest()
{
    Consumer<String> consumer = (s) -> System.out.println(s);
    consumer.accept("您好,欢迎访问 pan_junbiao的博客");

    Supplier<String> supplier = () -> "您好,欢迎访问 pan_junbiao的博客".substring(8, 22);
    System.out.println(supplier.get());

    Function<String, String> function = (s) -> s.substring(8, 22);
    System.out.println(function.apply("您好,欢迎访问 pan_junbiao的博客"));

    Predicate<String> predicate = (s) -> {
        String userName = "pan_junbiao的博客";
        return userName.equals(s);
    };
    System.out.println(predicate.test("pan_junbiao的博客"));
}

执行结果:

 

4、方法引用与构造器引用(::操作符)

方法引用和构造器引用可以让Lambda表达式的代码在简洁的基础上再简洁,使用::双冒号来使用方法引用,看看有几种引用方式:

  • 对象::实例方法名
  • 类::静态方法名
  • 类::实例方法名
//静态方法引用
Comparator<Integer> c1 = (x, y) -> Integer.compare(x, y);
Comparator<Integer> c2 = Integer::compare;

//实例方法引用1
userList.forEach(user -> System.out.println(user));
userList.forEach(System.out::println);

//实例方法引用2
userList.forEach(user -> user.getName());
userList.forEach(User::getName);

//构造器引用
strList.stream().map(s -> new String(s));
strList.stream().map(String::new);

【示例】遍历用户列表。

/**
 * 遍历用户列表
 * @author pan_junbiao
 */
@Test
public void forEachTest()
{
    //创建用户列表
    List<String> userList = Arrays.asList("pan_junbiao","阿标","pan_junbiao的博客","KevinPan");

    //遍历用户信息
    userList.forEach(System.out::println);
    //上述语句等同于如下:
    //userList.forEach(user -> System.out.println(user));
}

执行结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pan_junbiao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值