Lambda 表达式
Lambda 表达式,也可称为闭包。Lambda 表达式是一个匿名函数,我们可以这样理解 Lambda 表达式:Lambda 是一段可以传递的代码(能够做到将代码像数据一样进行传递)。格式如下:
(parameters) -> expression 或 (parameters) ->{ statements; }
实例
创建线程
//不使用lambdanew Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName());}},"thread").start(); //使用lambdanew Thread(() -> {System.out.println(Thread.currentThread().getName());}, "thread").start();
语法
Lambda 表达式在 Java 语言中引入了 “->” 操作符, “->” 操作符被称为 Lambda 表达式的操作符或者箭头操作符,它将 Lambda 表达式分为两部分:
左侧部分指定了 Lambda 表达式需要的所有参
右侧部分指定了 Lambda 体,即 Lambda 表达式要执行的功能
Lambda 表达式本质上是对接口的实现,Lambda 表达式的参数列表本质上对应着接口中方法的参数列表。
语法格式一
无参,无返回值,Lambda 体只有一条语句
Runnable runnable=()-> System.out.println(Thread.currentThread().getName()); new Thread(runnable).start();
语法格式二
需要参数,并且无返回值。Lambda 表达式的参数列表的数据类型可以省略不写,因为 JVM编译器能够通过上下文推断出数据类型,这就是“类型推断”
public class LambdaDemo {interface Operate {void method(int x, int y);}public static void main(String[] args) {//实现Operate接口Operate operate = (x, y) -> System.out.printf("%d\t%d", x, y);operate.method(100,200);} } /* 100 200 */
语法格式三
只需要一个参数时,参数的小括号可以省略
public class LambdaDemo {interface Operate {void method(int x);}public static void main(String[] args) {Operate operate = x -> System.out.printf("%d", x);operate.method(100);} } /* 100 */
语法格式四
需要参数,并且有返回值
public class LambdaDemo {interface Operate {int method(int x, int y);}public static void main(String[] args) {Operate operate = (x, y) -> {System.out.println(x + y);return x + y;};operate.method(100, 200);} } /* 300 */
语法格式五
当 Lambda 体只有一条语句时,return 和大括号可以省
public class LambdaDemo {interface Operate {int method(int x, int y);}public static void main(String[] args) {Operate operate = (x, y) -> x + y;System.out.println(operate.method(100, 200));} }
函数式接口
Lambda 表达式需要函数式接口的支持,只包含一个抽象方法的接口,称为函数式接口。
可以通过 Lambda 表达式来创建该接口的对象。
可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
java提供了四大函数式接口:
Consumer 消费型接口
Consumer 接口是消费性接口,无返回值。
@FunctionalInterface public interface Consumer<T> {void accept(T t);default Consumer<T> andThen(Consumer<? super T> after) {Objects.requireNonNull(after);return (T t) -> { accept(t); after.accept(t); };} }
Supplier 供给型接口
Supplier 接口是供给型接口,有返回值。
@FunctionalInterface public interface Supplier<T> {T get(); }
Function<T,R> 函数式接口
Function 接口是函数型接口,有返回值。
@FunctionalInterface public interface Function<T, R> {R apply(T t);default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {Objects.requireNonNull(before);return (V v) -> apply(before.apply(v));}default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {Objects.requireNonNull(after);return (T t) -> after.apply(apply(t));}static <T> Function<T, T> identity() {return t -> t;} }
Predicate 断言型接口
Predicate 接口是断言型接口,返回值类型为 boolean。
@FunctionalInterface public interface Predicate<T> {boolean test(T t);default Predicate<T> and(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) && other.test(t);}default Predicate<T> negate() {return (t) -> !test(t);}default Predicate<T> or(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) || other.test(t);}static <T> Predicate<T> isEqual(Object targetRef) {return (null == targetRef)? Objects::isNull: object -> targetRef.equals(object);} }
方法引用与构造器引用
方法引用
当要传递给 Lambda 体的操作,已经有实现的方法了,可以使用方法引用!方法引用就是操作符“::”将方法名和对象或类的名字分隔开来。使用方法如下:
- 类::静态方法
- 类::实例方法
public static void main(String[] args) {List<Integer> list=new ArrayList<>();list.forEach(item->System.out.println(item));//等价list.forEach(System.out::println);}
构造器引用
格式如下所示: ClassName::new
与函数式接口相结合,自动与函数式接口中方法兼容。可以把构造器引用赋值给定义的方法, 与构造器参数列表要与接口中抽象方法的参数列表一致!
public static void main(String[] args) {Function<Integer, List<Integer>> function = ArrayList::new;List<Integer> list = function.apply(16);Supplier<List<Integer>> supplier = ArrayList::new;List<Integer> integers = supplier.get();}
数组引用
public static void main(String[] args) {Function<Integer, Integer[]> function = Integer[]::new;//创建大小为16的数组Integer[] list = function.apply(16);}
Optional类
Optional 类是一个容器类,代表一个值存在或不存在,可以避免空指针异常。类常用方法:
- Optional.of(T t) : 创建一个 Optional 实例。
- Optional.empty() : 创建一个空的 Optional 实例。
- Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例。
- isPresent() : 判断是否包含值。
- orElse(T t) : 如果调用对象包含值,返回该值,否则返回 t。
- orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值。
- map(Function f): 如果有值对其处理,并返回处理后的 Optional,否则返回 Optional.emp ty()。
- flatMap(Function mapper):与 map 类似,要求返回值必须是 Optional。
Stream API
Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执 行非常复杂的查找、过滤和映射数据等操作。Stream使用流程如下:
- 创建 Stream:一个数据源(如: 集合、数组), 获取一个流。
- 中间操作: 一个中间操作链,对数据源的数据进行处理。
- 终止操作(终端操作): 一个终止操作,执行中间操作链,并产生结果。
创建Stream
获取Stream
public static void main(String[] args) {List<Integer> list=new ArrayList<>();//获取流list.stream();//获取平行流list.parallelStream();}
由数组创建
public static void main(String[] args) {Stream<Integer> integerStream = Arrays.stream(new Integer[]{1, 2, -12, 0});IntStream intStream = Arrays.stream(new int[]{1, 2, 3, -1});LongStream longStream = Arrays.stream(new long[]{1L, 2L, 3L, -1L});DoubleStream doubleStream = Arrays.stream(new double[]{1.1, 2.1, 3.1, -1.1});}
由值创建
public static void main(String[] args) {Stream<Integer> integerStream = Stream.of(1, 2, 3, 4);}
由函数创建
由函数创建流可以创建无限流。
public static void main(String[] args) {Stream<Integer> stream = Stream.iterate(0, integer -> integer + 1);//创建的是无限流 使用limit方法获取10个List<Integer> collect = stream.limit(10).collect(Collectors.toList());System.out.println(collect);Stream<ArrayList<Object>> generate = Stream.generate(ArrayList::new);List<ArrayList<Object>> collect1 = generate.limit(5).collect(Collectors.toList());System.out.println(collect1);}
中间操作
筛选与切片
public static void main(String[] args) {List<Integer> list = Arrays.asList(2, 4, 5, 6, 7, 3, 6);//筛选被3整除的数List<Integer> collect = list.stream().filter(item -> Objects.equals(item % 3, 0)).collect(Collectors.toList());System.out.println(collect);//选取前5个List<Integer> collect1 = list.stream().limit(5).collect(Collectors.toList());System.out.println(collect1);//跳过前2个List<Integer> collect2 = list.stream().skip(2).collect(Collectors.toList());System.out.println(collect2);//去重List<Integer> collect3 = list.stream().distinct().collect(Collectors.toList());System.out.println(collect3);}
映射
public static void main(String[] args) {List<Integer> list = Arrays.asList(2, 4, 5, 6, 7, 3, 6);List<String> collect = list.stream().map(String::valueOf).collect(Collectors.toList());System.out.println(collect);}
排序
public static void main(String[] args) {List<Integer> list = Arrays.asList(2, 4, 5, 6, 7, 3, 6);List<Integer> collect = list.stream().sorted().collect(Collectors.toList());System.out.println(collect);}
终止操作
查找与匹配
public static void main(String[] args) {List<Integer> list = Arrays.asList(2, 4, 5, 6, 7, 3, 6);System.out.println(list.stream().allMatch(item -> item > 5));System.out.println(list.stream().anyMatch(item -> item > 5));System.out.println(list.stream().noneMatch(item -> item > 5));Optional<Integer> any = list.stream().findAny();System.out.println(any.orElse(0));Optional<Integer> first = list.stream().findFirst();System.out.println(first.orElse(0));}
统计
public static void main(String[] args) {List<Integer> list = Arrays.asList(2, 4, 5, 6, 7, 3, 6);System.out.println(list.stream().filter(Objects::isNull).count());Optional<Integer> max = list.stream().max(Integer::compareTo);System.out.println(max.orElse(0));Optional<Integer> min = list.stream().min(Integer::compareTo);System.out.println(min.orElse(0));list.stream().forEach(System.out::println);}
规约
public static void main(String[] args) {List<Integer> list = Arrays.asList(2, 4, 5, 6, 7, 3, 6);System.out.println(list.stream().reduce(0, Integer::sum));Optional<Integer> reduce = list.stream().reduce(Integer::sum);System.out.println(reduce.orElse(0));}
收集
public static void main(String[] args) {List<Integer> list = Arrays.asList(2, 4, 5, 6, 7, 3, 6);System.out.println(list.stream().filter(Objects::nonNull).collect(Collectors.toList()));}
接口的默认方法与静态方法
Java 8 中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用 default t关键字修饰。
- 选择父类中的方法。如果一个父类提供了具体的实现,那么接口中具有相同名称 和参数的默认方法会被忽略。
- 接口冲突。如果一个父接口提供一个默认方法,而另一个接口也提供了一个具有 相同名称和参数列表的方法(不管方法是否是默认方法), 那么必须覆盖该方法来解 决冲突。
在 Java8 中,接口中允许添加静态方法,使用方式接口名.方法名。