一、 Lambda表达式
1、为什么使用Lambda表达式
- Lambda是–个匿名函数,我们可以把Lambda表达式理解为是–段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
2、Lambda表达式
- 举例:(o1,o2) -> Integer.compare(o1,o2)
- 格式:
- ->:lambda操作符或箭头操作符
- ->:左边 lambda形参列表(其实就是接口中的抽象方法的形参列表)
- ->:右边 lambda体(其实就是重写的抽象方法的方法体)
- lambda表达式的使用
- ->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略
- ->右边:lambda体应该使用一对{}包裹;如果Lambda体只有一条执行语句(可能是return语句),可以省略这一对{}和return关键字
/**
* 语法格式一:无参,无返回值
*/
class Demo1 {
public void Demo() {
Runnable runnable = () -> System.out.println("语法格式一:无参,无返回值");
runnable.run();
}
}
/**
* 语法格式二:需要一个参数,无返回值
*/
class Demo2 {
public void Demo() {
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
};
consumer.accept("语法格式二:需要一个参数,无返回值");
//lambda表达式修改
Consumer<String> consumer1 = (String s) -> System.out.println(s);
consumer1.accept("lambda two");
}
}
/**
* 语法格式三:数据类型可以省略,因为可以由编译器推断得出,称为"类型推断"
* ArrayList<String> arrayList=new ArrayList<>();
* int []arr1=new int[]{1,2,3};//--> int[]arr={1,2,3};
*/
class Demo3 {
public void Demo() {
Consumer<String> consumer1 = (s) -> System.out.println(s); //因为前边指定了泛型为String 所以参数肯定是String的 可以推断出来
consumer1.accept("lambda two");
}
}
/**
* 语法格式四:lambda若只需要一个参数时,参数的小括号可以省略
*/
class Demo4 {
public void Demo() {
Consumer<String> consumer1 = s -> System.out.println(s); //因为只有一个参数,所以小括号可以省略
consumer1.accept("lambda two");
}
}
/**
* 语法格式五:lambda需要两个或以上的参数,多条执行语句,并且可以有返回值
*/
class Demo5 {
public void Demo() {
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1.compareTo(o2);
}
};
//lambda表达式修改
Comparator<Integer> comparator1 = (o1, o2) -> {
return o1.compareTo(o2);
};
}
}
/**
* 语法格式六:lambda体只有一条语句时,return与大括号若有,都可以省略
*/
class Demo6 {
public void Demo() {
Comparator<Integer> comparator1 = (o1, o2) -> o1.compareTo(o2);
}
}
- lambda的本质:作为函数式接口的实例
3、函数式接口
- 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口 @FunctionalInterface
- 我们可以在一个报口.上使用@FunctionalInterface注解,这样做可以检查它是否是-一个函数式接口。同时javadoc也会包含一条声明,说明这个接口是-一个函数式接口。
- 在java.util.function包 下定义了Java 8的丰富的函数式接口
- 如何理解函数式接口
- Javal从诞生日起就是一直倡导“一切皆对象”,在Java里面面向对象(OOP)编程是一切。但是随着python、scala等 语言的兴起和新技术的挑战,Java不得不做出调整以便支持更加广泛的技术要求,也即java不但可以支持OOP还可以支持OOF(面向函数编程)
- 在函数式编程语言当中,函数被当做一- 等公民对待。在将函数作为一等公民的编程语言中,Lambda表达式的类型是函数。但是在Java8中,有所不同。在Java8中, Lambda表达式是对象,而不是函数,它们必须依附于一-类特别的对象类型–函数式接口。
- 简单的说,在Java8中, Lambda表达式就是一个函数式接口的实例。这就是Lambda表达式和函数式接口的关系。也就是说,只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。
- 所以以前用匿名实现类表示的现在都可以用L ambda表达式来写。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KbtdNrHZ-1604064472717)(C:\Users\王瑞文\AppData\Roaming\Typora\typora-user-images\image-20200804095524617.png)]
- 使用eg:
package java8;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
* 内置4大核心函数式接口
* 消费型 Consumer<T> void accept(T t)
* 供给型 Supplier<T> T get()
* 函数型Function<T,R> R apply(T t)
* 断定型 Predicate<T> boolean test(T t)
*
*/
public class LambdaTest {
public static void main(String[] args) {
//happyTime(200,money-> System.out.println("学习学累了,去天上人间买了瓶矿泉水价格为"+money));
List<String> list= Arrays.asList("北京","南京","天津","东京","西京","普京");
System.out.println(filterString(list,pre->pre.contains("京")));
}
public static void happyTime(double money, Consumer<Double> consumer){
consumer.accept(money);
}
//根据规定过滤集合中的字符串
public static List<String> filterString(List<String> list, Predicate<String> predicate){
ArrayList<String> filterList=new ArrayList<>();
for (String s : list) {
if (predicate.test(s)){
filterList.add(s);
}
}
return filterList;
}
}
4、方法引用与构造器引用
- 使用情景:当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
- 方法引用可以看做是L ambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一- 个语法糖。
- 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一- 致!
- 格式:使用操作符“::” 将类(或对象)与方法名分隔开来。
- 如下三种主要使用情况:
➢对象::实例方法名
➢类:静态方法名
➢类::实例方法名
二、强大的Stream API
1、Stream API说明
- Java8中有两大最为重要的改变。第一个是Lambda表达式;另外 一个则是Stream APl。
- **Stream API ( java.util.stream)**把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为StreamAPI可以极大提供Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。
- Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作**。使用Stream API对集合数据进行操作,就类似于使用SQL执行的数据库查询。**也可以使用StreamAPl来并行执行操作。简言之,StreamAPl提供了一种高效且易于使用的处理数据的方式。
2、为什么使用Stream API
- 实际开发中,项目中多数数据源都来自于Mysq|, Oracle等。 但现在数据源可以更多了,有MongDB,Radis等, 而这些NoSQL的数据就需要Java层面去处理。
- Stream和Collection集合的区别: Collection 是一种 静态的内存数据结构,而Stream是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向CPU,通过CPU实现计算。
- 注意:
- Stream自己不会存储元素。
- Stream不会改变源对象。相反,他们会返回一个持有结果的新Stream.
- Stream操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
3、Stream的操作三个步骤
-
创建Stream
- 一个数据源(如:集合、数组),获取一个流
-
中间操作
- 一个中间操作链,对数据源的数据进行处理
- 多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”
- 筛选与切片
-
终止操作
- 一旦终止操作,就执行中间操作链,并产生结果。之后,不会再被使用