JAVA8生态
- Lambda 表达式
- 函数式接口
- 方法引用 / 构造器引用
- Stream API
- 接口中的默认方法 / 静态方法
- 新时间日期 API
- 其他新特性
新特性
- 速度更快
- 代码更少
- 强大的 Stream API
- 便于并行
- 最大化减少空指针异常 Optional (Kotlin ?)
1、Lambda
匿名内部类
@Test
public void test01(){
//匿名内部类
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1,o2);
}
};
//调用
TreeSet<Integer> set = new TreeSet<>(comparator);
}
Lambda
Lambda是一个匿名函数,可以理解为一段可以传递的代码(将代码像数据一样传递);可以写出更简洁、更灵活的代码;作为一种更紧凑的代码风格,是Java语言表达能力得到提升
@Test
public void test02(){
// Lambda 表达式
Comparator<Integer> comparator = (a, b) -> Integer.compare(a, b);
TreeSet<Integer> set = new TreeSet<>(comparator);
}
基础语法:
- 操作符:-> - 左侧:参数列表 - 右侧:执行代码块 / Lambda 体
例子:
例如Runnable接口:
public class Test02 {
int num = 10; //jdk 1.7以前 必须final修饰
@Test
public void test01(){
//匿名内部类
new Runnable() {
@Override
public void run() {
//在局部类中引用同级局部变量
//只读
System.out.println("Hello World" + num);
}
};
}
@Test
public void test02(){
//语法糖
Runnable runnable = () -> {
System.out.println("Hello Lambda");
};
}
}
@Test
public void test03(){
Consumer<String> consumer = (a) -> System.out.println(a);
consumer.accept("我觉得还行!");
}
@Test
public void test03(){
Consumer<String> consumer = a -> System.out.println(a);
consumer.accept("我觉得还行!");
}
- 有两个及以上的参数,有返回值,并且 Lambda 体中有多条语句
@Test
public void test04(){
Comparator<Integer> comparator = (a, b) -> {
System.out.println("比较接口");
return Integer.compare(a, b);
};
}
- 有两个及以上的参数,有返回值,并且 Lambda 体中只有1条语句 (大括号 与 return 都可以省略不写)
@Test
public void test04(){
Comparator<Integer> comparator = (a, b) -> Integer.compare(a, b);
}
Lambda 表达式 参数的数据类型可以省略不写 Jvm可以自动进行 “类型推断”
案例
调用 Collections.sort() 方法,通过定制排序 比较两个 Employee (先按照年龄比,年龄相同按照姓名比),使用 Lambda 表达式作为参数传递
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee {
private Integer id;
private String name;
private Integer age;
private Double salary;
}
List<Employee> emps = Arrays.asList(
new Employee(101, "Z3", 19, 9999.99),
new Employee(102, "L4", 20, 7777.77),
new Employee(103, "W5", 35, 6666.66),
new Employee(104, "Tom", 44, 1111.11),
new Employee(105, "Jerry", 60, 4444.44)
);
@Test
public void test01(){
Collections.sort(emps, (e1, e2) -> {
if (e1.getAge() == e2.getAge()){
return e1.getName().compareTo(e2.getName());
} else {
return Integer.compare(e1.getAge(), e2.getAge());
}
});
for (Employee emp : emps) {
System.out.println(emp);
}
}
2、函数式接口
定义:接口中只有一个抽象方法的接口 @FunctionalIterface
Java内置四大核心函数式接口:
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|
Consumer 消费型接口 | T | void | 对类型为T的对象应用操作:void accept(T t) | Supplier 提供型接口 | 无 | T | 返回类型为T的对象:T get() | Function<T, R> 函数型接口 | T | R | 对类型为T的对象应用操作,并返回结果为R类型的对象:R apply(T t) | Predicate 断言型接口 | T | boolean | 确定类型为T的对象是否满足某约束,并返回boolean值:boolean test(T t) |
消费型接口
@Test
public void test01(){
//Consumer
Consumer<Integer> consumer = (x) -> System.out.println("消费型接口" + x);
//test
consumer.accept(100);
}
提供型接口
@Test
public void test02(){
List<Integer> list = new ArrayList<>();
List<Integer> integers = Arrays.asList(1,2,3);
list.addAll(integers);
//Supplier<T>
Supplier<Integer> supplier = () -> (int)(Math.random() * 10);
list.add(supplier.get());
System.out.println(supplier);
for (Integer integer : list) {
System.out.println(integer);
}
}
函数型接口
@Test
public void test03(){
//Function<T, R>
String oldStr = "abc123456xyz";
Function<String, String> function = (s) -> s.substring(1, s.length()-1);
//test
System.out.println(function.apply(oldStr));
}
?断言型接口
@Test
public void test04(){
//Predicate<T>
Integer age = 35;
Predicate<Integer> predicate = (i) -> i >= 35;
if (predicate.test(age)){
System.out.println("你该退休了");
} else {
System.out.println("我觉得还OK啦");
}
}
3、引用
方法引用
定义:若 Lambda 表达式体中的内容已有方法实现,则我们可以使用“方法引用”
语法格式:
- 对象 :: 实例方法
- 类 :: 静态方法
- 类 :: 实例方法
//对象::实例方法
@Test
public void test(){
Consumer<String> con = x -> {
System.out.println(x);
};
PrintStream out = System.out;
Consumer<String> con1 = out::println;
Consumer<String> con2 = System.out::println;
con2.accept("qwe");
}
//类::静态方法名
@Test
public void test(){
int x;int y;
Comparator<Integer> com = (x,y)-> Integer.compare(x,y);
Comparator<Integer> com1 = Integer::compare;
}
// 类::实例方法名
@Test
public void test(){
BiPredicate<String,String> bp = (x,y) -> x.equals(y);
BiPredicate<String,String> bp2 = String::equals;
}
注意:
- Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!
- 若Lambda参数列表中的第一参数是实例方法的调用者,第二个参数是实例方法的参数时,可以使用
ClassName::method
构造器引用
格式:
@Test
public void test04(){
Supplier<List> sup1 = () -> new ArrayList();
Supplier<List> sup2 = ArrayList::new;
//如果有多个构造器,如何判断是调用的实体类的哪个构造器呢?看下面的注意,即Function(T,R)内部的函数 R apply(T t) 是1个参数,那么就会调用是1个参数的构造器。
Function<Integer,Employee> fun2 =Employee::new;
}
注意:需要调用的构造器的参数列表要与函数时接口中抽象方法的参数列表保持一致
数组引用
语法:
@Test
public void test(){
Function<Integer,String[]> fun = x -> new String[x];
Function<Integer,String[]> fun2 = String[]::new;
}
4、Stream?API
?创建流:(的几种方法如下)
/**
* 创建流
*/
@Test
public void test01(){
/**
* 集合流
* - Collection.stream() 穿行流
* - Collection.parallelStream() 并行流
*/
List<String> list = new ArrayList<>();
Stream<String> stream1 = list.stream();
//数组流
//Arrays.stream(array)
String[] strings = new String[10];
Stream<String> stream2 = Arrays.stream(strings);
//Stream 静态方法
//Stream.of(...)
Stream<Integer> stream3 = Stream.of(1, 2, 3);
//无限流
//迭代
Stream<Integer> stream4 = Stream.iterate(0, (i) -> ++i+i++);
stream4.forEach(System.out::println);
//生成
Stream.generate(() -> Math.random())
.limit(5)
.forEach(System.out::println);
}
筛选 / 切片
中间操作:
- filter:接收 Lambda ,从流中排除某些元素
- limit:截断流,使其元素不超过给定数量
- skip(n):跳过元素,返回一个舍弃了前n个元素的流;若流中元素不足n个,则返回一个空流;与 limit(n) 互补
- distinct:筛选,通过流所生成的 hashCode() 与 equals() 取除重复元素
List<Employee> emps = Arrays.asList(
new Employee(101, "Z3", 19, 9999.99),
new Employee(102, "L4", 20, 7777.77),
new Employee(103, "W5", 35, 6666.66),
new Employee(104, "Tom", 44, 1111.11),
new Employee(105, "Jerry", 60, 4444.44)
);
@Test
public void test01(){
emps.stream()
.filter((x) -> x.getAge() > 35)
.limit(3) //短路?达到满足不再内部迭代
.distinct()
.skip(1)
.forEach(System.out::println);
}
?映射?
- map:接收 Lambda ,将元素转换为其他形式或提取信息;接受一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
- flatMap:接收一个函数作为参数,将流中每一个值都换成另一个流,然后把所有流重新连接成一个流
@Test
public void test02(){
List<String> list = Arrays.asList("a", "b", "c");
list.stream()
.map((str) -> str.toUpperCase())
.forEach(System.out::println);
}
public Stream<Character> filterCharacter(String str){
List<Character> list = new ArrayList<>();
for (char c : str.toCharArray()) {
list.add(c);
}
return list.stream();
}
@Test
public void test03(){
List<String> list = Arrays.asList("a", "b", "c");
Test02 test02 = new Test02();
list.stream()
.flatMap(test02::filterCharacter)
.forEach(System.out::println);
}
排序
- sorted():自然排序
- sorted(Comparator c):定制排序
public class test {
@Test
public void test(){
//自然排序
List<String> list = Arrays.asList("aaa", "eee", "ddd", "bbb");
list.stream().sorted().forEach(System.out::println);
//定制排序
List<Person> list1 = Arrays.asList(
new Person("张三", 18, 2000.0),
new Person("李四", 18, 5000.0),
new Person("王五", 45, 8700.0),
new Person("赵六", 42, 4200.0),
new Person("陈七", 56, 13100.0)
);
list1.stream().sorted((p1,p2) -> {
if (p1.getAge().equals(p2.getAge())){
return p1.getSale().compareTo(p2.getSale());
}else {
return p1.getAge().compareTo(p2.getAge());
}
}).forEach(System.out::println);
}
}
|