1、lambda表达式
Lambda 是一个 匿名函数,我们可以把 Lambda 表达式理解为是 一段可以传递的代码(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。
(1)语法
Lambda 表达式:在Java 8 语言中引入的一种新的语法元素和操作符。这个操作符为 “->” , 该操作符被称为 Lambda操作符或 箭头操作符。它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的参数列表
右侧:指定了 Lambda 体,是抽象方法的实现逻辑,也即Lambda 表达式要执行的功能。
语法格式一 : 无参,无返回值
Rannable r1 = () -> {System.out.println("Hello Lanbda !");}
语法格式二: :Lambda 需要一个参数,但是没有返回值。
Cousumer<String> con = (String str) -> {System.out.println("str");}
语法格式三 : 数据类型可以省略 ,因为可由编译器推断得出,称为“类型推断”
Cousumer<String> con = (str) -> {System.out.println("str");}
语法格式四: :Lambda 若只需要一个参数时, 参数的小括号可以省略
Cousumer<String> con = str -> {System.out.println("str");}
语法格式五: :Lambda 需要两个或以上的参数,多条执行语句,并且可以有返回值
Comparator<Integer> com = (x,y) -> { System.out.println("实现函数式接口方法"); return Integer.compare(x,y); }
语法格式六 :当Lambda 体只有一条语句时,return与大括号若有,都可以省略
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
(2)类型推断
Lambda表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断”。
(3)应用示例
// 1.创建线程new Thread(() -> {// method run,do something}, "threadName").start();// 2.匿名类JButton show = new JButton("show");show.addActionListener(e -> {// method actionPerformed()});// 3.forEach迭代List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");features.forEach(System.out::println);// 4.map 和reduceList<Integer> costBeforeTax = Arrays.asList(100, 200, 300, 400, 500, 600);costBeforeTax.stream().map(e -> e + 0.12 * e).forEach(System.out::print);double bill = costBeforeTax.stream().map(e -> e + 0.12 * e).reduce((sum, cost) -> sum + cost).get();System.out.println(bill);// 5.过滤 filter 收集 collectList<String> strs = Arrays.asList("abc", "defg", "hi", "jkmln");List<String> filtered = strs.stream().filter(e -> e.length() > 2).collect(Collectors.toList());// 6.去重List<Integer> nums = Arrays.asList(1 ,2, 3, 1, 4, 5, 2, 6, 8, 7, 6);nums = nums.stream().distinct().collect(Collectors.toList());// 7.计算最大值、最小值、平均值、总和List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);IntSummaryStatistics stats = primes.stream().mapToInt(e -> e).summaryStatistics();System.out.println("最大值:" + stats.getMax());System.out.println("最小值:" + stats.getMin());System.out.println("平均值:" + stats.getAverage());System.out.println("总和:" + stats.getSum());System.out.println("计数:" + stats.getCount());
(4)限制
lambda表达式有个限制,只能引用final和final局部变量,也就是说不能再lambda表达式内部修改定义再域外的变量。否则编译报错:
2、函数式(Functional)接口
只包含一个抽象方法的接口,称为 函数式接口。
Lambda表达式就是一个函数式接口的实例。匿名实现类表示的现在都可以用Lambda表达式来写。
java内置四大核心函数式接口:
3、方法引用与构造器引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
格式:使用操作符 “::” 将类(或对象)与方法名分隔开来。如下三种主要使用情况:
对象::实例方法名
类::静态方法名
类::实例方法
// 方法引用 ClassName::methodName
如: Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
等同于: Comparator<Integer> com = Integer::compare; // 构造器引用 ClassName::new
如: Function<Integer, MyClass> fun = (n) -> new MyClass(n);
等同于: Function<Integer, MyClass> fun = MyClass::new; //数组引用 type[] :: new
如: Function<Integer, Integer[]) fun = (n) -> new Integer[n];
等同于: Function<Integer, Integer[]) fun = Integer::new;
4、Stream API
Stream 和 Collection 集合的区别:Collection 是一种静态的内存数据结构,而 Stream 是有关计算的。前者是主要面向内存,存储在内存中,后者主要是面向 CPU,通过 CPU 实现计算。
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
Stream操作的三个步骤:
创建Stream -> 中间操作 -> 终止操作(终端操作)
(1)创建Stream
// 方式1:通过集合
//Java8 中的 Collection 接口被扩展,提供了两个获取流的方法:
default Stream<E> stream() : 返回一个顺序流
default Stream<E> parallelStream() : 返回一个并行流
例:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Stream<Integer> integerStream = list.stream(); // 方式2:通过数组
// Java8 中的 Arrays 的静态方法 stream() 可以获取数组流:
static <T> Stream<T> stream(T[] array): 返回一个流
重载形式,能够处理对应基本类型的数组:
public static IntStream stream(int[] array)
public static LongStream stream(long[] array)
public static DoubleStream stream(double[] array)
例: IntStream stream = Arrays.stream(new int[]{1, 2, 3, 4, 5}); // 方式3:通过Stream的of()
public static<T> Stream<T> of(T... values) // 接收任意可变参数,返回一个流
例: Stream<String> stringStream = Stream.of("AA", "BB", "CC"); // 方式4: 创建无限流
>迭代 public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) >
生成 public static<T> Stream<T> generate(Supplier<T> s)
例:
// 迭代
Stream<Integer> stream = Stream.iterate(0, x -> x + 2); stream.limit(10).forEach(System.out::println);
// 生成
Stream<Double> stream1 = Stream.generate(Math::random); stream1.limit(10).forEach(System.out::println);
(2)Stream的中间操作
(2.1)筛选与切片
Person p1 = new Person("tom", 11);
Person p2 = new Person("jerry", 8);
Person p3 = new Person("marry", 5);
Person p4 = new Person("john", 14);
ArrayList<Person> list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
// 过滤
List<Person> collect = list.stream() .filter(p -> p.getAge() > 10).collect(Collectors.toList());
// 去重
Person p5 = new Person("john", 14);
collect = list.stream() .distinct() .collect(Collectors.toList());
// 截断
collect = list.stream() .limit(2) .collect(Collectors.toList());
// 跳过元素
collect = list.stream() .skip(2) .collect(Collectors.toList());
(2.2)映射
List<String> nameList = list.stream()
.map(Person::getName)
.collect(Collectors.toList()); // map()和flatMap类似于集合的add()和addAll(),后者会展开元素
(2.3)排序
// 自定义比较
List<Person> sortedList = list.stream() .sorted((e1, e2) -> e1.getAge()-e2.getAge()) .collect(Collectors.toList());
// 数值的比较方法
sortedList = list.stream() .sorted((e1, e2) -> Integer.compare(e1.getAge(), e2.getAge())) .collect(Collectors.toList());
// Comparator的静态比较方法
sortedList = list.stream() .sorted(Comparator.comparingInt(Person::getAge)) .collect(Collectors.toList());
(3)Stream的终止操作
(3.1)匹配与查找
boolean allMatch = list.stream().allMatch(e -> e.getAge() > 10);
Optional<Person> first = list.stream().findFirst();
list.stream().filter(e -> e.getAge() > 10).count();
Optional<Person> max = list.stream() .filter(e -> e.getAge() > 10) .max(Comparator.comparingInt(Person::getAge));
list.stream().filter(e -> e.getAge() > 10).forEach(System.out::println);
(3.2)归约
Optional<Integer> reduce = list.stream() .map(Person::getAge) .reduce((e1, e2) -> e1 + e2);
(3.3)收集
(4)Collectors
5、Optional类
Optional<T> 类(java.util.Optional) 是一个容器类,它可以保存类型T的值,代表这个值存在。或者仅仅保存null,表示这个值不存在。原来用 null 表示一个值不存在,现在 Optional 可以更好的表达这个概念。并且可以避免空指针异常。
Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
创建Optional 类对象的方法:
Optional.of(T t) : 创建一个 Optional 实例,t必须非空;
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t) :t可以为null
判断Optional 容器中是否包含对象:
boolean isPresent() : 判断是否包含对象
void ifPresent(Consumer<? super T> consumer) :如果有值,就执行Consumer接口的实现代码,并且该值会作为参数传给它。
获取Optional 容器的对象:
T get(): 如果调用对象包含值,返回该值,否则抛异常
T orElse(T other) :如果有值则将其返回,否则返回指定的other对象。
T orElseGet(Supplier<? extends T> other) : :如果有值则将其返回,否则返回由Supplier接口实现提供的对象。
T orElseThrow(Supplier<? extends X> exceptionSupplier) : :如果有值则将其返
回,否则抛出由Supplier接口实现提供的异常。
//使用Optional类的getGirlName():
public String getGirlName2(Boy boy){ Optional boyOptional = Optional.ofNullable(boy); //此时的boy1一定非空 Boy boy1 = boyOptional.orElse(new Boy(new Girl("迪丽热巴"))); Girl girl = boy1.getGirl(); Optional girlOptional = Optional.ofNullable(girl); //girl1一定非空 Girl girl1 = girlOptional.orElse(new Girl("古力娜扎"));return girl1.getName();
}