Lambda 表达式
Lambda 表达式,也可称为闭包。Lambda 表达式是一个匿名函数,我们可以这样理解 Lambda 表达式:Lambda 是一段可以传递的代码(能够做到将代码像数据一样进行传递)。格式如下:
java(parameters) -> expression 或 (parameters) ->{ statements; }
实例
创建线程
java//不使用lambda new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()); } },"thread").start(); //使用lambda new 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 中,接口中允许添加静态方法,使用方式接口名.方法名。