刚毕业入职新工作,在职岗位培训时,老师在操作集合老使用Lambda表达式。这使一个之前完全没有接触过Lambda表达式的少年甚是苦恼,看不懂,闲余时间决定搞一搞Lambda表达式到底是啥东西?底层原理怎么实现的,接下来我将我的学习成果一起分享给大家......
一、Lambda表达式的简介:
Lambda表达式首先不是一种新的知识点,而是Java8推出来的一种新的语法。这种新的语法背后仍然是接口、方法、参数、返回值、匿名内部类等。并且这种语法方便程序员编写,但是JVM在编译时,会自动还原以前我们自己写的代码。
例1:对其学生分数进行升序排序:
public class Test {
class User{
private String name;
private Integer score;
public User(String name, Integer score) {
this.name = name;
this.score = score;
}
@Override
public String toString() {
return this.name + this.score;
}
}
/**
* 传统的写法
*/
public void testOldUse(){
User[] users = new User[]{new User("张三",80),new User("李四",81),new User("王五",82)};
//对User数组按照score排序
Arrays.sort(users, new Comparator<User>() {
public int compare(User o1, User o2) {
//有可能两个数相减,超出int范围,所以我们借用Integer中的compare()方法
//return o1.score - o2.score;
return Integer.compare(o1.score, o2.score);
}
});
System.out.println(Arrays.toString(users));
}
/**
* 使用lambda表达式
*/
@Test
public void testNewUse(){
User[] users = new User[]{new User("张三",83),new User("李四",84),new User("王五",85)};
//对User数组按照score排序new Comparator<User>() {
//Lambda表达式 (切记三个一定)
/* 第一:Arrays.sort()这个方法的第二参数一定是实现了Comparator接口;
* 第二:实现Comparator接口,一定要重写compare()方法;
* 第三:方法compare()执行完毕,一定会返回一个int类型的值;
* 这些JVM在编译的时候,会自动的帮助我们添加这些所缺的内容;
*/
Arrays.sort(users, (User o1, User o2) -> {
return Integer.compare(o1.score,o2.score);
}
);
System.out.println(Arrays.toString(users));
}
/**
* 再次简化lambda表达式
*/
@Test
public void testNewUse2(){
User[] users = new User[]{new User("张三",86),new User("李四",87),new User("王五",88)};
/* Lambda表达式
* 第一:Integer.compare()这个方法会返回一个int值;
* 第二:Comparetor这个接口的compare()方法也会返回一个int值;
* 第三:JVM会自动推导出Integer.compare()这个方法返回的int值即为compare()所要返回的值,所以return可以省略;
*/
Arrays.sort(users, (User o1, User o2) -> Integer.compare(o1.score,o2.score));
System.out.println(Arrays.toString(users));
}
/**
* 最终简化lambda表达式
*/
@Test
public void testNewUse3(){
User[] users = new User[]{new User("张三",89),new User("李四",90),new User("王五",91)};
/* Lambda表达式
* 第一:如果代码块中只有一行代码,
* 第二:Integer.compare()这个方法会返回一个int值;
* 第三:compare()这个方法也会返回一个int值,JVM会自动推导出Integer.compare()这个方法返回的值为compare()的值,所以return可以省略;
* 第四:compare()这个方法的参数类型一定是User类型,所以JVM会推导出要比较两个参数的类型,可以省略User
*/
Arrays.sort(users, (o1,o2) -> Integer.compare(o1.score,o2.score));
System.out.println(Arrays.toString(users));
}
}
实践:大家可以自行实现lambda表达式代替匿名内部类,创建Runnable接口实例,并重写run()方法,然后启动线程!
二、Lambda表达式之变量:(Lambda表达式俗称闭包)
(1) 接口的方法参数:Lambda表达式中()圆括号中的参数变量;
(2) 局部变量:Lambda表达式代码块中声明的变量;
(3) 自由变量:不是参数,也不是局部变量,是外部方法的参数变量;
例2:匿名内部类使用外部变量,该变量一定是final修改的,不可改变
//content、times即为自由变量
public void repeatprint(String content,int times) {
// 第一:匿名内部类若使用外部的变量,该变量一定是使用final修饰;
Runnable runnable = () -> { //若run()方法中有参数,即为接口的方法参数
int i = 0; //声明一个局部变量
for (; i <= times; i++) {
//content = "not update"; //该变量自动被final修饰,不能修改
System.out.println(content);
}
//this指向的是外部类的实例,而不是内部类本身
System.out.println(this);
};
new Thread(run).start();
}
注意1:匿名内部类中的this指代匿名内部类本身,而Lambda表达式中的this指代的外部类实例,即为创建Lambda表表达式方法中的this(就是外部类本身);
注意2:Lambda表达式中访问自由变量(创建Lambda表达式方法的参数),final修饰,不可修改!
三、Lambda表达式之参数列表
(1) 如果Lambda表达式没有参数,直接使用()来表示,()不能省略;
例3:启动线程
//Lambda表达式没有参数时,()不能省略,否则编译出错
public void testTread(){
new Thread(() -> System.out.println("Hello lambda")).start();
}
(2) 如果Lambda表达式只有一个参数,若没写了参数类型,参数外可不加();若写了参数类型,则参数外必须加();
例4:借用Frame中的Button组件添加事件处理:
Frame f = new Frame();
f.setSize(100,100);
Button btn = new Button("lambda");
//原始方式,匿名内部类创建
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Hello lambda");
}
});
/* lambda表达式只有一个参数
* 第一:addActionListener()这个方法的参数一定是ActionListener接口的实现类实例;
* 第二:实现ActionListener接口一定要重写actionPerformed()方法;
* 第三:重写actionPerformed()方法,参数一定是ActionEvent类型;
* JVM会自动的帮助我们推导出来
*/
/* 第一种方式:btn.addActionListener((ActionEvent e) -> System.out.println("Hello lambda"));
* 第二种方式:btn.addActionListener(event -> System.out.pringln("Hello lambda"));
*/
f.add(btn);
f.setVisible(true);
(3) 如果有两个参数或多个参数,不管是否写参数类型,一定要加();若参数要加修饰符,一定要添加完整的类型。
例5:将其字符串数组中升序排序
/**
* Lambda表达式有两个参数
*/
public void testLambda(){
String[] strs = new String[]{"Android","IOS","Java","OS"};
Arrays.sort(strs,(s1,s2) -> Integer.compare(s1.length(), s2.length()));
/* 如果参数要加修饰符或者标签(例如:final、static关键字),参数一定要加完整的类型;
* Arrays.sort(strs,(final String s1,final String s2) -> Integer.compare(s1.length(), s2.length()));
*/
System.out.println(Arrays.toString(strs));
}
虽然例子简单,但想理解Lambda表达式如何从匿名内部类转变而来的原理,底层实现等,需要大家揣摩和思考。继续欢迎大家参考:Java8新特性之Lambda表达式学习二