什么是lambda表达式
lambda表达式,是Java8的新特性,lambda表达式本质来讲,就是一个匿名函数,使用 Lambda 表达式可以使代码变的更加简洁紧凑。
lambda表达式的语法
- 基础语法:(参数列表) -> {lambda体}
以下是lambda表达式的重要特征: - **可选类型声明:**不需要声明参数类型,编译器可以通过上下文统一识别出参数类型”。
tips:如果要省略参数的类型,则每一个参数的类型都必须省略。不能出现有些参数写类型,有些参数不写类型。
//接受两个参数(数字),返回值为他们的和
(x,y) -> y+x
//接受两个int参数(数字),返回值为他们的和
(int x,int y) -> y+x
- **可选的参数圆括号:**一个参数可以省略圆括号,但多个参数需要定义圆括号。
//一个参数,返回值为4
x -> 2+x
//两个参数,返回值为他们的和
(x,y) -> y+x
- **可选的大括号:**如果lambda体只包含了一个语句,可以省略大括号,如果是返回语句,则return也省略。
//只有一个语句
x -> 2+x
//只有一个语句
x -> { return 2+x}
lambda表达式的应用
lambda表达式通常用来简化接口的实现,但是只能实现函数式接口
函数式接口:只有一个抽象方法的接口,可以通过使用注解
@FunctionalInterface
来验证接口是否为函数式接口
下面以Collections的sort方法比较lambda表达式和匿名内部类
//使用匿名内部类
Collections.sort(new ArrayList<String>(), new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
//使用lambda表达式
Collections.sort(new ArrayList<String>(),((o1, o2) -> {
return o1.compareTo(o2);
}));
可以看到lambda表达式实现这个方法的时候,比匿名内部类更加的简洁。
方法引用
如果在lambda表达式中要实现的功能已经在其他的方法中实现了,我们可以直接引用这个方法
1.静态方法使用类引用,非静态方法使用对象引用
2.只能引用参数、返回值都与接口中的定义一致的方法
public class Test {
public static void main(String[] args) {
// 1、静态方法的引用
ICalculate calc1 = CalculateTest ::calculate1;
// 2、非静态方法的引用
// ICalculate calc2 = new CalculateTest () ::calculate2;
// 3、私有权限在类外不能访问,不能进行方法引用
ICalculate calc3 = CalculateTest ::calculate3;
// 4、参数、返回值和接口中定义的方法不完全一致不能引用
// ICalculate calc4 = CalculateTest ::calculate4;
// 5、引用Student类中的无参构造方法
GetStudent get = Student::new;
// 6、引用Student类中的有参构造方法
GetStudent2 get2 = Student::new;
// 7、接口方法参数是一个Person,返回值是String
GetterTest test = Person::getName;
}
}
@FunctionalInterface
interface ICalculate {
int calculate(int a, int b);
}
class CalculateTest {
public static int calculate1(int a, int b) {
if (a > b) {
return a;
}
return b;
}
public int calculate2(int x, int y) {
return x + y;
}
private static int calculate3(int a, int b) {
return a + b;
}
public void calculate4(int a) {
}
}
@FunctionalInterface
interface GetStudent {
Student get();
}
@FunctionalInterface
interface GetStudent2 {
Student get(String name, int age);
}
class Student {
public Student() { }
public Student(String name, int age) {
}
}
@FunctionalInterface
interface GetterTest {
String getName(Person person);
}
class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
四大核心函数式接口
消费型接口:Consumer
方法:void accept(T t);
无返回值,常用于打印等消费操作
/**
* 控制台打印 5
*/
public void testConsumer() {
handle(5, (x) -> System.out.println(x));
}
public void handle(int value, Consumer<Integer> consumer) {
consumer.accept(value);
}
供给型接口:Supplier
方法:T get();
常用于获取结果
/**
* 控制台打印 张三
*/
public void testSupplier() {
Person person = new Person ();
person.setName("张三")
System.out.println(getObject(() -> person.getName()));
}
public String getObject(Supplier<String> supplier) {
return supplier.get();
}
函数型接口:Function<T,R>
方法:R apply(T t);
传入一个参数T,返回一个结果R
public void testFunction() {
//删除单数
System.out.println(oneTwo(1, (x) -> {
if (x%2==0){
return "双数";
}
return "单数";
}));
//删除双数
System.out.println(oneTwo(2, (x) -> {
if (x%2==0){
return "双数";
}
return "单数";
}));
// 输出62
System.out.println(before(6, x -> x + 2, x -> x * 10));
// 输出80
System.out.println(after(6, x -> x + 2, x -> x * 10));
}
public Integer oneTwo(int origen, Function<Integer, String> function) {
return function.apply(origen);
}
public Integer before(int value, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
// value作为function2的参数,返回一个结果,该结果作为function1的参数,返回一个最终结果
return function1.compose(function2).apply(value);
}
public Integer after(int value, Function<Integer, Integer> function1, Function<Integer, Integer> function2) {
// value作为function1的参数,返回一个结果,该结果作为function2的参数,返回一个最终结果
return function1.andThen(function2).apply(value);
}
断言型接口:Predicate
方法:boolean test(T t);
接受一个输入参数T,返回一个布尔值结果,常用于条件判断
public void testPredicate() {
//输出false
System.out.println(judge(1, (x) -> x != 1));
//输出true
System.out.println(judge(1, (x) -> x = 1));
}
public boolean judge(Integer input, Predicate<Integer> predicate) {
return predicate.test(input);
}
流式编程Stream API
Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据
Stream(流)是一个来自数据源的元素队列,但是这个队列并不会存储元素,而是按需计算
数据源可以是集合,数组,I/O channel, 产生器generator 等
通常情况下,使用流式编程,需要经过以下三步。
1、创建流
获取数据源,将数据源中的数据读取到流中
List list = new ArrayList();
//为集合创建串行流
Stream stream = list.stream();
//为集合创建并行流 集成了多个线程对流中的数据进行操作,效率更高
Stream stream = list.parallelStream();
2、中间操作
对流中的数据进行各种各样的处理,每一个操作的返回值都是一个Stream对象,可以继续进行其他的操作,直到最终操作
//filter 条件过滤,仅保留流中满足指定条件的数据,其他不满足的数据都会被删除
list.stream().filter(e -> e.length() > 5).forEach(System.out::println);
//distinct 去重集合中重复的元素。这个方法没有参数。去重的规则与HashSet相同
list.stream().distinct().forEach(System.out::println);
//sorted 将流中的数据进行排序
// Comparable 接口方法实现排序
list.stream().sorted().forEach(System.out::println);
// 指定规则排序
list.stream().sorted((e1, e2) -> e1.length() - e2.length()).forEach(System.out::println);
//limit 截取流中指定数量的元素
list.stream().limit(2).forEach(System.out::println);
//skip 跳过流中的指定数量的元素
list.stream().skip(2).forEach(System.out::println);
//map 对流中的数据进行映射,用新的数据替换旧的数据
list.stream().map(e -> e + "添加").forEach(System.out::println);
//flatMap 扁平化映射
//方法返回一个Stream
public Stream<String> method(...){...}
//map
Stream<Stream<String>> list.stream().map(对象::method);
//flatMap
Stream<String> list.stream().map(对象::method);
3、最终操作
对流中的数据进行整合处理,并关闭流,因此最终操作只能存在一个
//collect 将流中的数据收集到一起进行处理
//将list转成set
Set<Integer> result = list.stream().collect(Collectors.toSet());
System.out.println(result);
//reduce 将流中的数据按照一定的规则聚合起来
int result = list.stream().reduce((e1, e2) -> e1 + e2).get();
System.out.println(result);
//count 统计流中的元素数量
int result = list.stream().count();
System.out.println(result);
//forEach 迭代流中的数据
list.stream().forEach(System.out::println);
//max 获取流中的最大元素
int result = list.stream().max(Integer::compareTo).get();
System.out.println(result);
//min 获取流中的最小元素
int result = list.stream().min(Integer::compareTo).get();
System.out.println(result);