Java基础|Java8新特性

  • 发布时间:2022-02-21 21:33:31
  • 本文热度:浏览 2,040 赞 0 评论 0
  • 全文共1字,阅读约需1分钟

Java基础(1)|Java8新特性

1、Lambda表达式

Lambda表达式是JDK8推出一个重要的新特性,本质只是一个”语法糖”

1.1、背景

Java中万物皆对象,函数无法独立存在,只能依赖于对象来调用。在函数式编程语言中,函数是一等公民,它们可以独立存在,你可以将其赋值给一个变量,或将他们当做参数传给其他函数。JavaScript 就是函数式编程语言最典型的代表。

函数式语言提供了一种强大的功能——闭包(是一个可调用的对象,它记录了一些信息),因此Java 现在提供的最接近闭包的概念便是 Lambda 表达式,虽然闭包与 Lambda 表达式之间存在显著差别,但至少 Lambda 表达式是闭包很好的替代者。

1.2、目的

取代大部分的匿名内部类,极大地优化代码结构

1.3、语法结构

(parameters) -> expression
或
(parameters) ->{ statements; }
  • ():参数列表
  • {}:方法体
  • ->:ambda运算符(读作goes to)
  • parameters:参数集合
  • expression:表达式
  • statements:代码块

结构说明如下:

  • 一个 Lambda 表达式可以有零个或多个参数
  • 参数的类型既可以明确声明,也可以根据上下文来推断。例如:(int a)(a)效果相同
  • 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:
    (a, b)(int a, int b)(String a, int b, float c)
  • 空圆括号代表参数集为空。例如:() -> 42
  • 当只有一个参数,且其类型可推导时,圆括号()可省略。例如:a -> return a*a
  • Lambda 表达式的主体可包含零条或多条语句
  • 如果 Lambda 表达式的主体只有一条语句,花括号{}可省略。匿名函数的返回类型与该主体表达式一致
  • 如果 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空

Lambda表达式重要特征

  • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
  • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
  • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
  • 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

Lambda表达式使用要求

Lambda 规定接口中只能有一个需要被实现的方法(即只能有一个抽象方法),不是规定接口中只能有一个方法,这也称之为“函数式接口”

注意:jdk 8 中有另一个新特性:default, 被 default 修饰的方法会有默认实现,不是必须被实现的方法,所以不影响 Lambda 表达式的使用。

而想定义函数式接口需要使用@FunctionalInterface注解,要求接口中的抽象方法只有一个,如果你尝试添加第二个抽象方法,将抛出编译时错误。这个注解往往会和 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)

// 接口方法多个参数、有返回值、需要多行代码时
(name,age) -> {
     System.out.print(name);
     return name + “ :” + age;
 }

1.4、‘::’用法

  • run(Class::staticMethod)静态方法引用
  • run(new Class()::Method) 非静态(普通方法引用)
  • run(Class::new) 构造方法引用

2、Stream流执行机制

https://laoniu-nblog.oss-cn-beijing.aliyuncs.com/nBlog/article/20220221213331213.png

2.1、生成流

1、appleStore.stream();
2、Arrays.stream(new int[]{});
3、Stream.of(1,2,3,4);

流的不可重复使用(流是针对每一个元素进行流水线式执行)

public static void main(String[] args) {
        //流的不可重复使用
        Stream<Apple> stream1 = appleStore.stream();
        Stream<Apple> stream2 = stream1.filter(a -> a.getColor().equals("red"));
        //stream是每次经过一次流传递后,前面的流就关闭了,是严格按照顺序执行的
        //Exception:stream has already been operated upon or closed
        Stream<Apple> stream3 = stream1.filter(apple -> apple.getWeight() > 100);
    }

图中绿色节点为中间节点,可以拥有多个,并且是懒节点遇到终值节点才会执行

红色为终值节点,只有一个,而且要放在流水线最后

img

3、末尾

关于函数式接口的应用

对未知json返回形式接口数据做必要处理

protected <T> T doCall(JSONObject jsonObject, AbstractCallBack<T> abstractCallBack) {
    T result = null;
    if (jsonObject != null) {
        if (jsonObject.containsKey(ERROR_CODE) && jsonObject.getInteger(ERROR_CODE) != 0) {
            String errorCode = jsonObject.getString(ERROR_CODE);
            String errorMsg = jsonObject.getString(ERROR_MSG);
            try {
                StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
                log.warn("微信返回异常errcode:[{}],errmsg:[{}],当前方法:[{}],调用者:[{}]", errorCode, errorMsg, stackTraceElements[2].toString(), stackTraceElements[3].toString());
            } catch (Exception e) {
                log.warn("微信返回异常并未获取到调用者:errcode:[{}],errmsg:[{}]", errorCode, errorMsg);
            }
            return null;
        } else {
            result = abstractCallBack.execute(jsonObject);
        }
    }
    return result;
}

/**
 * 回调执行方法
 *
 * @param <T>
 */
@FunctionalInterface
public interface AbstractCallBack<T> {

    /**
     * 回调
     *
     * @param jsonObject
     * @return
     */
    T execute(JSONObject jsonObject);
}
正文到此结束
评论插件初始化中...
Loading...