jdk8新特性——Lambda表达式基础篇
一.什么是Lambda
-
Lambda表达式也被称为箭头函数、匿名函数、闭包
-
体现轻量级函数式编程思想
-
‘->’左侧为操作参数,右侧是操作表达式
-
基于JDK8+的新特性
-
举例
1
2
3
4
5
6
7
8
9
10
11
12
13public static void main(String[] args) {
//1.传统模式下线程创建
new Thread(new Runnable() {
public void run() {
System.out.println("threading..."+Thread.currentThread().getId());
}
}).start();
//2.jdk8新特性,lambda表达式优化线程模式
new Thread(()->{
System.out.println("lambda threading..."+Thread.currentThread().getId());
}).start();
} -
注意:若提示java版本相关问题
1
2
3
4
5
6
7
8
9报错举例:Information:java: javacTask: 源发行版 1.8 需要目标发行版 1.8
原因:没有将jdk版本切换为1.8以上,下面三个地方的版本需要一致。
1,Project Structure里确认两个地方:Project sdk以及project language level
2,Project Structure->Modules里Sources里的Language level
3,Preferences->java Compiler->Per-module bytecode Version
二.Lambda表达表达式基础知识
函数式接口
-
只包含一个接口方法的特殊接口
-
语义化检测注解:@FunctionalInterface
-
举例
1
2
3
4
5
6
7
8
9
10
11
12
13/**
* 消息传输格式化转换接口
*/
public interface iMessageFormat {
/**
* 消息转换方法
* @param message 要转换的消息
* @param format 转换的格式
* @return 返回转换后的数据
*/
String format(String message, String format);
} -
函数式接口中添加默认方法
-
可以实现功能拓展,不影响原来的函数式接口
-
接口类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public interface iUserCredential {
/**
* 通过用户账号,验证用户身份信息接口
* @param username 要验证的用户账号
* @return 返回身份信息【系统管理员 用户管理员 普通用户】
*/
String vertifyUser(String username);
//默认方法
default String getCredential(String username){
//模拟方法
if("admin".equals(username)){
return "admin+管理员用户";
}else if("manager".equals(username)){
return "manager+用户管理员用户";
}else {
return "commons+普通用户";
}
}
} -
测试
1
2
3
4
5public static void main(String[] args) {
iUserCredential ic = new UserCredentialImpl();
System.out.println(ic.vertifyUser("admin"));
System.out.println(ic.getCredential("abc"));
}
-
-
函数式接口中添加静态方法
-
接口类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27/**
* 消息传输格式化转换接口
*/
public interface iMessageFormat {
/**
* 消息转换方法
* @param message 要转换的消息
* @param format 转换的格式
* @return 返回转换后的数据
*/
String format(String message, String format);
/**
* 消息合法性判断
* @param msg 要验证的消息
* @return 返回验证结果
*/
//静态方法
static boolean vertifyMessage(String msg){
if (msg!=null){
return true;
}
return false;
}
} -
测试
1
2
3
4
5//此处直接调用接口静态方法
if(iMessageFormat.vertifyMessage(msg)) {
iMessageFormat format = new MessageFormatImpl();
format.format("hello", "json");
}
-
-
总结
1
2
3
4
5
6函数式接口是只包含“一个方法”的接口,
可用 注解进行检测,
但“一个方法”不包括以下方法:
1.默认接口方法(default)
2.静态接口方法(static)
3.继承自Object的方法( 例如toString() )
Lambda表达式与函数式接口关系
-
传统匿名内部类实现接口
1
2
3
4
5
6
7
8
9//匿名内部类,实现接口抽象方法
iUserCredential ic2 = new iUserCredential() {
public String vertifyUser(String username) {
return "admin".equals(username)?"admin":"user";
}
};
System.out.println(ic2.vertifyUser("manager"));
System.out.println(ic2.vertifyUser("admin")); -
使用lambda表达式实现接口
1
2
3
4
5
6//lambda,针对函数式接口进行简单实现
iUserCredential ic3 = (String username)->{
return "admin".equals(username)?"admin":"user";
};
System.out.println(ic3.vertifyUser("admin"));
System.out.println(ic3.vertifyUser("manager"));
JDK中常见的函数式接口
-
java.util.function提供了大量函数式接口
-
java.util.function.Predicate<\T>
1
2
3
4
5
6//接收参数对象T,返回一个布尔类型
Predicate<String> pre = (String username) -> {
return "admin".equals(username);
};
System.out.println(pre.test("manager"));
System.out.println(pre.test("admin")); -
java.util.function.Comsumer<\T>
1
2
3
4
5
6
7//此方法接收参数对象T,不反回结果
//下面模拟消息发送
Consumer<String> con = (String message) -> {
System.out.println("要发送的消息:"+message);
System.out.println("消息发送完成");
};
con.accept("I'm banana!"); -
java.util.function.Function<T,R>
1
2
3
4
5
6
7//接收对象参数T,返回结果对象R
//下面模拟性别判断
Function<String, Integer> fun = (String gender) -> {
return "male".equals(gender)?1:0;
};
System.out.println(fun.apply("male"));
System.out.println(fun.apply("female")); -
java.util.function.Supplier<\T>
1
2
3
4
5//不接收参数,提供T对象的创建工厂
Supplier<String> sup = () -> {
return UUID.randomUUID().toString();
};
System.out.println(sup.get()); -
java.util.function.UnaryOperator<\T>
1
2
3
4
5
6
7//接收参数对象T,返回结果对象T
//下面模拟图片处理
UnaryOperator<String> uo = (String img) -> {
img += "[100*1020]";
return img;
};
System.out.println(uo.apply("原图")); -
java.util.function.BinaryOperator<\T>
1
2
3
4
5
6//接收两个T对象,返回一个T对象结果
//下面模拟数字比大小
BinaryOperator<Integer> bo = (Integer a, Integer b) -> {
return a>b?a:b;
};
System.out.println(bo.apply(7,9));
-
Lambda表达式基本语法
-
基本语法
1
2
3
4
5
6
7/*
1)声明:和lambda表达式绑定的接口类型
2)参数:包含在一对圆括号中,和绑定的接口中的抽象方法中的参数个数及顺序
3)操作符:->
4)执行代码块:包含在一对大括号中
[接口声明] = (参数) -> {执行代码块};
*/ -
注意
1
2
3
4
5
6
7
8
9
10/*
1)lambda表达式必须和接口进行绑定
2)lambda表达式可以带任意个参数,参数类型可以不指定,jvm运行时会根据绑定的抽象方法进行判断
3)lambda的返回值,代码块只有一行且没有大括号,可以省略return(即单行代码执行结果会自动返回)
例如:Ilambda i1 = (x,y) -> x+y;
接口:interface Ilambda{
int test(int x, int y);
}
*/
变量捕获
-
匿名内部类中的变量捕获
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19public void testInnerClass(){
String s2 = "局部变量";
new Thread(new Runnable() {
String s3 = "内部变量";
public void run() {
//访问全局变量
//System.out.println(this.s1); //this关键字:当前内部类型对象,因此会报错
System.out.println(s1);
//局部变量访问:不能对局部变量数据进行修改[final]
System.out.println(s2);
//访问内部变量,可修改
System.out.println(s3);
System.out.println(this.s3);
}
}).start();
} -
Lambda表达式中的变量捕获
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public void testLambda(){
String s2 = "局部变量lambda";
new Thread( () -> {
String s3 = "内部变量lambda";
//访问全局变量
System.out.println(this.s1); //this关键字表示方法所在类型的对象
//访问局部变量,不能进行数据修改,默认为final
System.out.println(s2);
//访问内部变量,可修改
System.out.println(s3);
s3 = "lambda修改";
System.out.println(s3);
} ).start();
} -
总结
1
2
3lambda变量捕获优化了this关键字,使其不再单独建立内部对象作用域,即:
1)lambda可以通过this访问全局变量
2)普通匿名内部类通过this可访问的是内部变量
Lambda表达式类型检查
-
案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30public class App {
public static void test (MyInterface<String, List> inter){
List<String> list = inter.strategy("hello", new ArrayList());
System.out.println(list);
}
public static void main(String[] args) {
test(new MyInterface<String, List>() {
public List strategy(String s, List list) {
list.add(s);
return list;
}
});
test((x,y)->{
y.add(x);
return y;
});
}
}
interface MyInterface<T, R>{
R strategy(T t, R r);
} -
表达式类型检查
1
(x,y)->{..} --> test(param) --> param==MyInterface --> lambda表达式为MyInterface类型
-
参数类型检查
1
(x,y)->{..} --> MyInterface.strategy(T t, R r) --> 由MyInterface<String, List>确定具体类型 --> T==String R==list --> lambda --> (x,y) == strategy(T t, R r) --> x==T==String, y==R==list
方法重载
-
若定义了两个极其以上函数式接口,又进行了方法重载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42public class App {
interface Param1{
void outInfo(String info);
}
interface Param2{
void outInfo(String info);
}
//定义重载方法
public void lambdaMethod(Param1 param){
param.outInfo("hello param1 banana");
}
public void lambdaMethod(Param2 param){
param.outInfo("hello param2 banana");
}
public static void main(String[] args) {
App app = new App();
//传统匿名内部类调用重载方法
app.lambdaMethod(new Param1() {
public void outInfo(String info) {
System.out.println(info);
}
});
app.lambdaMethod(new Param2() {
public void outInfo(String info) {
System.out.println(info);
}
});
//lambda表达式方式,存在类型检查,lambda无法推导重载方法,要在参数列表中表明类型
app.lambdaMethod((Param1) (String info)->{
System.out.println(info);
});
}
}
Lambda底层原理简单分析
- 编译时生成私有静态方法,在静态方法中做方法实现
- 编译同时,针对lambda目标接口生成内部类型实现接口,完成对静态方法的调用
以上就是Lambda的一些基础知识,接下来可以学习Lambda进阶特性,即其在集合中的运用。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 515code-实验室!
评论