Java 最新 LTS 已经到 17 了,面试的时候如果 JAVA8 都不会的话,感觉很难接受
Lambda 表达式
一个匿名函数、可以理解为一段可以传递的代码。可以写出更简洁、更灵活的代码
本质:函数式接口的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Test{ @Test public void test2(){ Comparator<Integer> com = new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2); } }; int compare = com.compare(11,21); System.out.println(compare);
Comparator<Integer> com2 = (o1,o2) -> Integer.compare(o1, o2); int compare2 = com2.compare(21, 25); System.out.println(compare2);
Comparator<Integer> com3 = Integer :: compare; int compare3 = com3.compare(51,32); System.out.println(compare3); } }
|
1 2 3 4 5
| - 无参无返回值,参数为一个空的小括号 - 数据类型可以省略,由编译器推断,称为类型判断 - 若只需要一个参数,参数小括号可以省略 - 两个以上参数,多条语句,两个括号都不能省略 - 有且只有一条返回语句时,return 和打括号都可以一起省略
|
函数式接口
有且仅有一个抽象方法的接口
加一个 @FunctionalInterface
,JavaDoc 中会表明表示这是一个函数式接口,可以进行校验
四大内置函数式接口
接口 | 参数 | 返回类型 | 用途 | 方法 |
---|
Consumer | T | void | 对类型 T 对应用操作 | void accept() |
Supplier | 无 | T | 返回类型为 T 对对象 | T get() |
Function | T | R | 对类型为 T 对应用操作,并返回结果 | R apply(T t) |
Predicate | T | boolean | 确定 T 是否满足约束,并返回 boolean | boolean test(T t) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class TestLambda3 { @Test public void test2(){ List<String> list = Arrays.asList("北京", "南京", "西京", "北京", "普京","武汉","深圳");
List<String> filterStrs = filterString(list, new Predicate<String>() { @Override public boolean test(String s) { return s.contains("京"); } }); List<String> filterStrs2 = filterString(list, s -> s.contains("京"));
System.out.println(filterStrs); System.out.println(filterStrs2); } public List<String> filterString(List<String> list, Predicate<String> pre){ ArrayList<String> filter = new ArrayList<>(); for(String s : list) { if(pre.test(s)){ filter.add(s); } } return filter; } }
|
引用
方法引用
当要传递给 Lambda 体的操作已经有实现的时候,可以使用方法引用
要求:实现接口的抽象方法和方法引用的方法有相同的参数列表和返回值类型
格式:类(或对象)::方法名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class TestMethodRef {
@Test public void test1(){ Consumer<String> con1 = str -> System.out.println(str+"..."); con1.accept("北京");
PrintStream ps = System.out; Consumer<String> con2 = ps::println; con2.accept("beijing"); } @Test public void test2(){ Employee emp = new Employee("tom", 24, 5600); Supplier<String> sup1 = () -> emp.getName(); System.out.println(sup1.get());
Employee emp2 = new Employee("tom", 24, 5600); Supplier<String> sup2 = emp::getName; System.out.println(sup2.get()); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class TestStatic{ @Test public void test3(){ Comparator<Integer> com1 = (t1,t2) -> Integer.compare(t1,t2); System.out.println(com1.compare(12,21));
Comparator<Integer> com2 =Integer::compare; System.out.println(com2.compare(12,32)); }
@Test public void test4(){ Function<Double, Long> function = new Function<Double, Long>() { @Override public Long apply(Double d) { return Math.round(d); } }; Function<Double, Long> function1 = d ->Math.round(d); Function<Double, Long> function2 = Math::round; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| class Test{ @Test public void test5(){ Comparator<String> com1 = (s1,s2) -> s1.compareTo(s2); System.out.println(com1.compare("abc", "abd"));
System.out.println("***************");
Comparator<String> com2 = String :: compareTo; }
@Test public void test6(){ BiPredicate<String, String> pre1 = (s1,s2) -> s1.equals(s2); System.out.println(pre1.test("1","1"));
System.out.println("***************");
BiPredicate<String,String> pre2 = String :: equals;
System.out.println(pre2.test("ab","ab")); } @Test public void test7(){ Employee employee = new Employee("lqs", 24, 9600); Function<Employee, String> function = e -> e.getName(); System.out.println(function.apply(employee));
System.out.println("***************");
Function<Employee, String> function1 = Employee::getName; System.out.println(function1.apply(employee)); } }
|
构造器引用
类似方法引用,函数式接口的抽象方法和构造器有相同的形参列表,就可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class TestConstructorRef { @Test public void test(){ Supplier<Employee> sup = new Supplier<Employee>() { @Override public Employee get() { return new Employee(); } };
Supplier<Employee> sup1 = () -> new Employee(); Supplier<Employee> sup2 = Employee::new;
System.out.println(sup2.get()); }
@Test public void test2(){ Function<String ,Employee> func1 = name -> new Employee(name); Employee employee = func1.apply("lqs"); System.out.println(employee);
Function<String,Employee> func2 = Employee :: new; Employee employee1 = func2.apply("lcy"); System.out.println(employee1); }
@Test public void test3(){ BiFunction<String, Integer, Employee> func1 = (name, age) -> new Employee(name,age); System.out.println(func1.apply("lqs", 21));
BiFunction<String, Integer, Employee> func2 = Employee :: new; System.out.println(func2.apply("jj", 21)); } }
|
数组引用
把数组看做特殊的类,可以使用引用
1 2 3 4 5 6 7 8 9 10 11 12
| public class TestArrayRef { @Test public void test(){ Function<Integer,String[]> func1 = length -> new String[length]; String[] arr1 = func1.apply(5); System.out.println(Arrays.toString(arr1));
Function<Integer, String[]> func2 = String[]::new; String[] arr2 = func2.apply(10); System.out.println(Arrays.toString(arr2)); } }
|
Stream API
是数据渠道,用于操作数据源(集合、数组)所生成的元素序列
Stream 不会自己存储元素;不会改变源对象,而是返回一个持有结果的新 Stream;操作是延迟执行的,会等到需要新结果的时候才执行。
Stream && Collection:Collection 是一种静态的内存数据,Stream 有关计算,面向 CPU
三个步骤
创建 Stream
一个数据源(如数组,集合),获取一个流
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public class TestStreamCreate { @Test public void test(){ List<Employee> list = new ArrayList<>(); for(int i = 0; i < 10; i++){ list.add(new Employee("name"+i, i+20, i+2000)); } Stream<Employee> stream = list.stream(); Stream<Employee> parallelsStream = list.parallelStream(); }
@Test public void test2(){ int[] arr = new int[]{1,2,3,4,5,76}; IntStream stream = Arrays.stream(arr); int row = 10; Employee[] employees = new Employee[row]; for(int i = 0; i < row; i++){ employees[i] = new Employee("name"+i, i+20, i+2000); } Stream<Employee> stream1 = Arrays.stream(employees); }
@Test public void test3(){ Stream<Integer> stream = Stream.of(1,2,3,5,7,8,90); }
@Test public void test4(){ Stream.iterate(0, t -> t+2).limit(10).forEach(System.out::println); Stream.generate(Math::random).limit(10).forEach(System.out::println); } }
|
中间操作
对数据源进行处理
1、筛选与切片
方法 | 描述 |
---|
filter(Predicate p) | 接受 lambda,从流中排除某些元素 |
distinct() | 筛选,通过流锁生成对 hashCode()和 equals()去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素对流;不足 n 个是返回空流;与 limit 互补 |
方法 | 描述 |
- | - |
filter(Predicate p) | 接受 lambda,从流中排除某些元素 |
distinct() | 筛选,通过流锁生成对 hashCode()和 equals()去除重复元素 |
limit(long maxSize) | 截断流,使其元素不超过给定数量 |
skip(long n) | 跳过元素,返回一个扔掉了前 n 个元素对流;不足 n 个是返回空流;与 limit 互补 |
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public class TestStreamDeal { @Test public void test(){ List<Employee> list = new ArrayList<>(); for(int i = 0; i < 10; i++){ list.add(new Employee("name"+i, i+20, i+2000)); }
Stream<Employee> stream = list.stream(); stream.filter(employee -> employee.getSalary() > 2005).forEach(System.out::println);
System.out.println("***************");
Stream<Employee> stream2 = list.stream(); stream2.limit(5).forEach(System.out::println);
System.out.println("***************");
int k = 7; list.add(new Employee("name"+k, 20+k, 2000+k)); Stream<Employee> stream3 = list.stream(); stream3.distinct().forEach(System.out::println);
} }
|
2、映射
方法 | 描述 |
---|
map(Function f) | 接受一个函数为参数,该函数作用到每个元素,并将其映射为一个新的元素 |
mapToDouble(ToDoubleFunction f) | 接受一个函数为参数,该函数作用到每个元素,并产生一个新的 DoubleStream |
mapToInt(ToIntFunction f) | 接受一个函数为参数,该函数作用到每个元素,并产生一个新的 IntStream |
mapToLong(ToLongFunction f) | 接受一个函数为参数,该函数作用到每个元素,并产生一个新的 LongStream |
flatMap(Function f) | 接受一个函数为参数,将流中每个值转换成另一个流,然后所有流连接成一个流 |
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| public class TestStreamDeal { @Test public void test(){ List<Employee> list = EmployeeData.getEmp();
Stream<Employee> stream = list.stream(); stream.filter(employee -> employee.getSalary() > 2005).forEach(System.out::println);
System.out.println("***************");
Stream<Employee> stream2 = list.stream(); stream2.limit(5).forEach(System.out::println);
System.out.println("***************");
int k = 7; list.add(new Employee("name"+k, 20+k, 2000+k)); Stream<Employee> stream3 = list.stream(); stream3.distinct().forEach(System.out::println);
}
@Test public void test2(){ List<String> list = Arrays.asList("aa","bb","cc","dd"); list.stream().map(s -> s.toUpperCase()).forEach(System.out::println); list.stream().map(String::toUpperCase).forEach(System.out::println);
System.out.println("*********************");
List<Employee> emp = EmployeeData.getEmp();
emp.stream().map(Employee::getName).filter(name -> name.length() > 3).forEach(System.out::println);
System.out.println("*********************"); Stream<Stream<Character>> streamStream = list.stream().map(TestStreamDeal::stringToStream); Stream<Character> characterStream = list.stream().flatMap(TestStreamDeal::stringToStream); streamStream.forEach(s -> { s.forEach(System.out::println); });
characterStream.forEach(System.out::println); }
public static Stream<Character> stringToStream(String str){ ArrayList<Character> list = new ArrayList<>(); for(Character c : str.toCharArray()){ list.add(c); } return list.stream(); }
@Test public void test4(){ List<Integer> list = Arrays.asList(12,423,14,1,32,56,98,-1); list.stream().sorted().forEach(System.out::println);
List<Employee> employees = EmployeeData.getEmp(); employees.stream().sorted((a,b) ->{ int ageValue = Integer.compare(a.getAge(),b.getAge()); if(ageValue != 0){ return ageValue; }else { return -Double.compare(a.getSalary(), b.getSalary()); } }).forEach(System.out::println); } }
|
- 3、排序
方法 | 描述 |
---|
sorted() | 产生一个新流,按自然顺序排序 |
sorted(Comparator com) | 产生一个新流,按比较器顺序排序 |
终止操作
一旦执行终止操作,就执行中间操作链,并产生结果。之后不会再使用
- 1、匹配查找
方法 | 描述 |
---|
allMatch(Predicate p) | 检查是否匹配所有元素 |
anyMatch(Predicate p) | 检查是否至少匹配一个元素 |
nonematch(Predicate p) | 检查是否没有匹配所有元素 |
findFirst() | 返回第一个元素 |
findAny() | 返回当前流中任意元素 |
count() | 返回流中元素总数 |
max(Comparator c) | 返回流中最大值 |
min(Comparator c) | 返回流中最小值 |
forEach(Comparator c) | 内部迭代(使用 Collection 接口需要用户自己迭代,称为外部迭代) |
例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class TestStreamEnd { @Test public void test5(){ List<Employee> list = EmployeeData.getEmp();
System.out.println(list.stream().allMatch(e -> e.getAge() > 24));
System.out.println(list.stream().anyMatch(employee -> employee.getSalary() > 24000));
System.out.println(list.stream().noneMatch(e -> e.getName().startsWith("雷")));
System.out.println(list.stream().findFirst()); System.out.println(list.stream().findAny()); long count = list.stream().filter(employee -> employee.getSalary() > 24000).count(); System.out.println(count); Stream<Double> doubleStream = list.stream().map(Employee::getSalary); Optional<Double> max = doubleStream.max(Double::compare); System.out.println(max); Optional<Employee> employee = list.stream().min(Comparator.comparingDouble(Employee::getSalary));
} }
|
1 2 3 4 5 6 7 8 9 10 11
| class Test{ @Test public void test2(){ List<Integer> list = Arrays.asList(1,2,3,5,7,9,6,7); list.stream().reduce(0 ,Integer::sum); List<Employee> employees = EmployeeData.getEmp(); System.out.println(employees.stream().map(Employee::getSalary).reduce(Double::sum)); } }
|
- 3、收集
方法 | 描述 |
---|
collect(Collector c) | 将流转换为其他方式,接受一个 Collector 的实现,用于给 Stream 中元素做汇总的方法 |
1 2 3 4 5 6 7 8 9 10
| class Test{ @Test public void test4(){ List<Employee> employees = EmployeeData.getEmp(); List<Employee> employeeList = employees.stream().filter(e -> e.getSalary() > 24000).collect(Collectors.toList()); Set<Employee> collect = employees.stream().filter(e -> e.getSalary() > 24000).collect(Collectors.toSet()); } }
|
Optional 类
Optional 类是一个可以为 null 的容器对象。如果值存在则 isPresent()方法会返回 true,调用 get()方法会返回该对象。
Optional 是个容器:它可以保存类型 T 的值,或者仅仅保存 null。Optional 提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
类声明
以下是一个 java.util.Optional 类的声明:
public final class Optional
extends Object
类方法
序号 | 方法 & 描述 |
---|
1 | **static Optional empty()**返回空的 Optional 实例。 |
2 | **boolean equals(Object obj)**判断其他对象是否等于 Optional。 |
3 | **Optional filter(Predicate predicate)**如果值存在,并且这个值匹配给定的 predicate,返回一个 Optional 用以描述这个值,否则返回一个空的 Optional。 |
4 | ** Optional flatMap(Function> mapper)**如果值存在,返回基于 Optional 包含的映射方法的值,否则返回一个空的 Optional |
5 | **T get()**如果在这个 Optional 中包含这个值,返回值,否则抛出异常:NoSuchElementException |
6 | **int hashCode()**返回存在值的哈希码,如果值不存在 返回 0。 |
7 | **void ifPresent(Consumer consumer)**如果值存在则使用该值调用 consumer , 否则不做任何事情。 |
8 | **boolean isPresent()**如果值存在则方法会返回 true,否则返回 false。 |
9 | **Optional map(Function mapper)**如果有值,则对其执行调用映射函数得到返回值。如果返回值不为 null,则创建包含映射返回值的 Optional 作为 map 方法返回值,否则返回空 Optional。 |
10 | **static Optional of(T value)**返回一个指定非 null 值的 Optional。 |
11 | **static Optional ofNullable(T value)**如果为非空,返回 Optional 描述的指定值,否则返回空的 Optional。 |
12 | **T orElse(T other)**如果存在该值,返回值, 否则返回 other。 |
13 | **T orElseGet(Supplier other)**如果存在该值,返回值, 否则触发 other,并返回 other 调用的结果。 |
14 | ** T orElseThrow(Supplier exceptionSupplier)**如果存在该值,返回包含的值,否则抛出由 Supplier 继承的异常 |
15 | **String toString()**返回一个 Optional 的非空字符串,用来调试 |
注意: 这些方法是从 java.lang.Object 类继承来的。
Optional 实例
我们可以通过以下实例来更好的了解 Optional 类的使用:
Tester.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| public class Java8Tester { public static void main(String args[]){
Java8Tester java8Tester = new Java8Tester(); Integer value1 = null; Integer value2 = new Integer(10);
Optional<Integer> a = Optional.ofNullable(value1);
Optional<Integer> b = Optional.of(value2); System.out.println(java8Tester.sum(a,b)); }
public Integer sum(Optional<Integer> a, Optional<Integer> b){
System.out.println("第一个参数值存在: " + a.isPresent()); System.out.println("第二个参数值存在: " + b.isPresent());
Integer value1 = a.orElse(new Integer(0));
Integer value2 = b.get(); return value1 + value2; } }
|
接口默认方法和静态方法
新日期 API
其他新特性