-
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流执行机制
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);
}
图中绿色节点为中间节点,可以拥有多个,并且是懒节点,遇到终值节点才会执行
红色为终值节点,只有一个,而且要放在流水线最后
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);
}
__EOF__