Java8新特性 Lambda表达式(一)

前言

Oracle官网提供最新的JDK版本是12.0.1,而博主在工作中用的最多的是Java7,但是平时在学习和开发中还是用Java8。虽然用着Java8的版本,但是却没有用到其新的特性。
Java的每一次更新都会带来一些有代表性的特性。例如:
一、Java5:自动拆装箱、枚举、泛型、增强for循环、可变参数等。
二、Java6:Compiler API,动态编译Java源文件等。
三、Java7:Switch中提供了String类型的支持、类型自动判断等。
四、Java8:Lambda表达式、Stream API、Optional对象判空等。

上面提到的只是Java每次版本更新的冰山一角。虽然Java现在已经更新到了13,但是具有代表性的7和8,才是各个公司目前的选择。随着Java8的成熟,Java7逐渐被8替代。所以,作为程序员的我们,也要学习Java提供的一些新特性,所以,下面记录了博主学习Java8的过程。

Lambda表达式基础

Lambda表达式也可以称为"闭包",在Java中用 ‘->’ 操作符表示,该操作符称为箭头操作符或Lambda操作符。
箭头操作符将Lambda表达式拆分为两部分:
①左边:Lambda表达式的参数列表,对应接口中方法的参数列表。例如:Comparator中compare(T t1,T t2)这个方法有两个参数。
②右边:Lambda体,即所要执行的功能。

就以多线程中Runnable这个类的使用为例。
首先使用匿名内部类的方式创建线程。

    @Test
    public void test1() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world");
            }
        };
        runnable.run();
    }

使用Lambda表达式的方式。

    @Test
    public void test1() {
        Runnable runnable = () -> System.out.println("hello world");
        runnable.run();
    }

执行测试代码,都会打印出"hello world",但是从代码的简洁性和可读性来说,Lambda表达式表现得更加出色。通过查看Runnable的源码。

看到run方法中没有参数,没有返回值。上面Lambda使用()来传入参数列表,因为run方法中没有参数,所以为空。而且没有返回值,所以没有return。右边的输出语句就对应了上面说的Lambda体。

细心的读者会发现,Runnable接口上有一个@FunctionalInterface注解。它表示这个接口是一个“函数式接口”。
那么什么是函数式接口呢?
定义:接口中只有一个抽象方法的接口,称为函数式接口。
Lambda表达式需要函数式接口的支持,如果当前接口不是函数式接口,Lambda无法区别调用的是接口中的哪个抽象方法。

Lambda语法格式

Lambda的语法格式有很多种,但是基本上都是上面所提到的那种形式,只是区别函数式接口的参数和返回值。

无参数,无返回值
    @Test
    public void test1() {
        Runnable runnable = () -> System.out.println("hello world");
        runnable.run();
    }

()参数列表为空,Lambda体只有一条语句。

有一个参数,无返回值
    @Test
    public void test2() {
        Book book = new Book("Java8新特性", 35.0, "清风", 50L);
        Consumer<Book> bookConsumer = (x) -> System.out.println(x.getBookName());
        bookConsumer.accept(book);
    }

这里使用了Consumer这个类,通过源码看,它是一个函数式接口,是Java8提供的一个支持Lambda表达式的API。它的接口方法可以传入一个任意的参数,然后执行自定义的操作。
上面传入了一个Book对象,然后打印了书的名称,此时参数()中是有一个参数,Lambda体有一条语句。

有两个参数,有返回值
    @Test
    public void test3() {
        Comparator<Integer> comparator = (x, y) -> {
            System.out.println("函数式编程");
            return Integer.compare(x, y);
        };
    }

上面使用的是Comparator函数式接口,传递两个参数,然后进行排序,这里的Lambda体中有两条语句,所以需要使用{}括号。同时具有返回值。
如果Lambda体中只有一条语句,大括号和return都可以不写。就像下面的语句形式。

    @Test
    public void test4() {
        Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y);
    }
参数列表的数据类型可有可无


如上图所示,在参数列表中指明了数据类型,但是,这个数据类型可以省略不写。因为JVM在编译的时候,通过上下文,能够推断出数据的类型。即“类型推断”。

Lambda实战

上面总结了Lambda的使用方法和语法格式,下面就进行一些简单的练习。实现自定义函数式接口,然后使用Lambda表达式,代替一些传统的操作。

按书籍的库存数量或价格进行排序
    private final Book[] books = new Book[]{
            new Book("深入理解Java虚拟机", 54.50, "周志明", 10000L),
            new Book("Java多线程编程核心技术", 47.60, "高红岩", 666L),
            new Book("Spring实战(第四版)", 59.60, "Craig Walls", 3500L),
            new Book("Python编程(从入门到实践)", 62.00, "埃里克·马瑟斯", 888L),
            new Book("大话数据结构", 40.70, "程杰", 560L)
    };
    private List<Book> bookList = Arrays.asList(books);

    @Test
    public void test() {
        Collections.sort(bookList, (book1, book2) -> Long.compare(book1.getStock(), book2.getStock()));
        bookList.forEach(System.out::println);

        System.out.println("-----------");

        bookList.sort((x, y) -> Double.compare(x.getPrice(), y.getPrice()));
        bookList.forEach(System.out::println);
    }

可以看到Lambda简化了书写,要是使用传统的Java代码,需要重写compare方法。按书籍价格排序的时候,IDEA提示,可以省略Collections,直接使用需要排序的集合,调用sort方法即可。

System.out::println

上面这段代码是Consumer接口的一个实现,可以输出每一个遍历的结果。至于原理,读者可查阅相关资料。

将字符串转为大写,然后截取子串

首先自己实现一个函数式接口

/**
 * @ClassName: StringUtils
 * @Description: TODO 操作字符串的函数式接口
 * @Date: 2019/6/25 20:55
 * @Version 1.0
 **/
@FunctionalInterface
public interface StringUtils {

    /**
     * //TODO
     * @param str
     * @return java.lang.String
     */
    String getStr(String str);
}

然后写方法,进行字符串的操作

    private String operatorString(String str, StringUtils utils) {
        return utils.getStr(str);
    }

    @Test
    public void test2() {
        final String str = " hello world ";
        String result = operatorString(str, (e) -> e.trim().toUpperCase());
        System.out.println(result);

        String subStr = operatorString(result, (e) -> e.trim().substring(6));
        System.out.println(subStr);
    }
两个数进行计算

同样定义函数式接口

package com.qfcwx.util;

/**
 * @ClassName: ComputeUtil
 * @Description: TODO 计算的函数式接口
 * @Date: 2019/6/26 16:41
 * @Version 1.0
 **/
@FunctionalInterface
public interface ComputeUtil<T, R> {

    /**
     * //TODO
     *
     * @param t1 数值1
     * @param t2 数值2
     * @return R 返回值
     */
    R getValue(T t1, T t2);
}

然后写方法,进行操作。

    private void operatorLong(Long v1, Long v2, ComputeUtil<Long, Long> util) {
        System.out.println(util.getValue(v1, v2));
    }

    @Test
    public void test3() {
        operatorLong(100L, 200L, (x, y) -> x * y);
        operatorLong(100L, 200L, (x, y) -> x + y);
    }

    private void operatorInteger(Integer v1, Integer v2, ComputeUtil<Integer, Integer> util) {
        Integer value = util.getValue(v1, v2);
        System.out.println(value);
    }

    @Test
    public void test() {
        operatorInteger(100, 25, (x, y) -> x * y);
        operatorInteger(100, 25, (x, y) -> x / y);
        operatorInteger(100, 25, (x, y) -> x - y);
        operatorInteger(100, 25, (x, y) -> x + y);
    }

可以看到使用泛型的好处,这里既可以使用long型计算,还可以使用int类型进行计算。使用Lambda表达式,简化了代码的书写,提高了程序的开发效率。

一半现实,一半梦想,努力让后者走进前者的心里。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值