Java8新特性 (一)Lambda
前言:
这两天彻底的复习了一遍Java8的各种新特性,趁着热乎劲,把知识点整理成博客的形式保存一下。
### 一、Lambda介绍
**Lambda表达式 :** 也可称为闭包,Lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中),免去了使用匿名方法的麻烦,并且给予Java简单但是强大的函数化的编程能力
语法格式:
(parameters) -> expression
或者
(parameters) ->{ statements; }格式说明:
():接口中抽象方法的参数列表,没有参数就空着,有参数则写出参数,多个参数用逗号分隔
->:传递的意思,将参数传递给方法体{}
{}:重写接口的抽象方法的方法体
二、Lambda用法实例
1.简单实例(基础用法的规则)
1.1 无参数时,可以省略括号内容
()->10 //返回结果值:10
1.2 传入String类型的参数
(String s)->System.out.print(s) //打印s的内容
1.3 传入的参数类型可以省略,如下
//
a->a*10 //返回结果值:a*10(传入一个参数时,可以省略括号)
(a,b)->a*b //返回结果值:a*b(传入两个或以上参数时,不能省略括号,)
#### 2.函数式接口
##### 2.1 Lambda实现自定义接口Calculator
首先定义一个函数式接口 ` Calculator `,包含唯一一个抽象方法 ` Calcu() `
```
public interface Calculator {
public abstract int Calcu(int x, int y);
}
```
其次定义一个 ` invokeCalcu() `,接收参数类型为接口
```
public static void invokeCalcu(int x, int y, Calculator calculator) {
int sum = calculator.Calcu(x, y);
System.out.println("sum = " + sum);
}
```
最后调用 ` invokeCalcu() `,一共有两种方法实现:
1)使用匿名内部类传入接口,并实现抽象方法
```
invokeCalcu(10, 20, new Calculator() {
@Override
public int Calcu(int x, int y) {
return x + y;
}
});
```
2)使用Lambda表达式,简化操作
```
invokeCalcu(120, 130, (a, b) -> a + b);
```
##### 2.2 Lambda表达式实现**多线程**接口实例 ` Runnable `
```
//使用匿名内部类的方式实现多线程的创建
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("currentThreadName = " + Thread.currentThread().getName());
}
}).start();
//使用lambda表达式实现多线程
new Thread(() -> System.out.println("currentThread().getName() = " + Thread.currentThread().getName())).start();
<br><hr>
##### 2.3 Lambda表达式实现**比较器**接口实例 ` Comparator `
定义一个Person类,保存姓名和年龄
public class Person {
private String name;
private int age;
public Person() { }
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
<br>
然后分别使用匿名内部类和Lambda表达式对Person类的年龄进行排序
Person[] arr = {
new Person("佟丽娅", 26),
new Person("范冰冰", 22),
new Person("柳岩", 21)
};
//匿名内部类重写comparator接口里的compare()
System.out.println("=匿名内部类升序排序:===========");
Arrays.sort(arr, new Comparator() {
@Override
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
});
for (Person person : arr) {
System.out.println(person);
}
//使用Lambda表达式,简化匿名内部类
System.out.println("=Lambda表达式降序排序:=========");
Arrays.sort(arr, (o1, o2) -> o2.getAge() - o1.getAge());
/**
- jdk1.8 也可以这样写 方法引用
- Arrays.sort(arr,Comparator.comparingInt(Person::getAge).reversed());
**/
for (Person person : arr) {
System.out.println(person);
}
//Stream API 也是Java8的新特新写法
System.out.println("=Stream-sort升序排序:=========");
Arrays.stream(arr).sorted(Comparator.comparing(Person::getAge)).forEach(System.out::println);
<br><hr>
> 接口中 **有且仅有唯一一个抽象方法** (接口中可以包含其他私有、默认、静态的方法),称之为函数式接口(这种类型的接口也称为SAM接口,即Single Abstract Method interfaces)
> > **使用前提:**
> > - 使用Lambda必须具有接口,且要求**接口中有且仅有一个抽象方法**
> > - 无论是 JDK内置的 ` Runnable ` 、` Comparator ` 接口还是自定义的接口,只有当接口中的抽象方法存在且唯一时,才可以使用Lambda
> > - 使用Lambda必须具有**上下文推断**
> > - 方法的**参数或局部变量类型**必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例
> > > 有且仅有一个抽象方法的接口,称为 ` “函数式编程” `
### 三、Lambda变量作用域
##### 3.1在 Lambda 表达式当中不允许声明一个与局部变量同名的参数或者局部变量
String[] str = {"1","12","123"};
Comparator comparator = (str, second) -> Integer.compare(str.length(), second.length()); //str处的编译会出错
<br><hr>
#####3.2 Lambda 表达式只能引用标记了 final 的外层局部变量
> 也就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
可以直接在 lambda 表达式中访问外层的局部变量:
public static void main(String args[]) {
final int num = 1;
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2); // 输出结果为 3
}
public interface Converter<T1, T2> {
void convert(int i);
}
<br>
lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)
int num = 1;
Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));
s.convert(2);
num = 5; //由于在Lambda表达式中引用了num,所以num是隐形的final修饰,但是这里修改了num的值,final就不存在了
最新文章
- visio二次开发初始化问题
- Power-BI 预警触发的设定
- 仓储管理系统500bug记录一下mysql 8小时超时解决办法
- SqlCommand执行带GO的SQL脚本文件
- ASP.NET SignalR 与 LayIM2.0 配合轻松实现Web聊天室(二) 之 ChatServer搭建,连接服务器,以及注意事项。
- SQL Server 小技巧【2】
- canvas小知识
- ASP.NET Cookie对象到底是毛啊?(简单小例子)
- Nginx下防御HTTP GET FLOOD(CC)攻击
- jsp 嵌套iframe 从iframe中表单提交并传值到外层
- SQL 范式(转载)
- MaterialEditText 控件学习
- 【转】mysql中文乱码的一点理解
- html5 离线存储 地理信息与本地存储
- C#、Java中的一些小功能点总结(持续更新......)
- spring框架整合springMVC时关于AOP无法切入的问题
- Openresty+redis实现灰度发布
- MyEclipse下自定义(支持html5的)JSP模板--JSP
- andrdoid内置视频文件
- WebAPI Post接收数据
热门文章
- select_region_point和select_region_spatial
- unity shader入门(一):基本结构话痨版
- 【体系结构】有关Oracle SCN知识点的整理
- Shell: sh,bash,csh,tcsh等shell的区别(转)
- C++中string的实现原理
- c#在WinForm和WebForm中根据控件和属性名获取控件属性值
- 微信支付之获取openid
- Alpha冲刺(8/10)——追光的人
- 深度学习Keras框架笔记之激活函数详解
- 【Selenium-WebDriver实战篇】ScreenRecorder的实际输出路径设置(转)