四、方法引用
1、概念
方法引用是用来直接访问类或者实例的已经存在的方法或者构造方法。方法引用提供了一种引用而不执行方法的方式,它需要由兼容的函数式接口构成的目标类型上下文。计算时,方法引用会创建函数式接口的一个实例。
注意方法引用是一个Lambda表达式,其中方法引用的操作符是双冒号"::"。
2、语法:
(1)类名::静态方法名
public static int comparePersonByAge(Person person1, Person person2) {
return person1.getAge() - person2.getAge();
}
//方法引用(类名::静态方法名)
Data.getData().stream().sorted(Person::comparePersonByAge).forEach(System.out:: println);
(2)引用名(对象名)::实例方法名
public class PersonCompare {
public int compareAge(Person person1, Person person2) {
return person1.getAge() - person2.getAge();
}
}
方法引用(引用名/对象名::实例方法名)
PersonCompare personCompare = new PersonCompare();
s.sorted(personCompare::compareAge).forEach(System.out::println);
(3)类名::实例方法名
public class Person {
public int compareScore(Person person) {
return this.getScore() - person.getScore();
}
}
s.sorted(Person::compareScore).forEach(System.out::println);
(4)构造方法引用:类名::new
注:如果函数式接口的实现恰好可以通过调用一个类的构造方法来实现,那么就可以使用构造方法引用
Supplier<Person> sp = () -> new Person();
System.out.println(sp.get());
Supplier<Person> sp1 = Person::new;
System.out.println(sp1.get());
五、默认方法
简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现其方法。我们只需在方法名前面加个 default 关键字即可实现默认方法。
问:为什么要有这个特性呢?
首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8 之前的集合框架没有 foreach 方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题。
/**
定义接口
**/
interface ILike {
void like(int a);
default void like2() {
System.out.println("sssssss");
}
//重写Object类下的toString()
@Override
String toString();
}
六、Date Time API
Java 8通过发布新的Date-Time API (JSR 310)来进一步加强对日期与时间的处理。
在旧版的 Java 中,日期时间 API 存在诸多问题,其中有:
- 非线程安全− java.util.Date 是非线程安全的,所有的日期类都是可变的,这是Java日期类最大的问题之一。
- 设计很差 − Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
- 时区处理麻烦 − 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
Java 8 在 java.time包下提供了很多新的 API。以下为两个比较重要的 API:
- Local(本地) − 简化了日期时间的处理,没有时区的问题。
- Zoned(时区) − 通过制定的时区处理日期时间。
新的java.time包涵盖了所有处理日期,时间,日期/时间,时区,时刻(instants),过程(during)与时钟(clock)的操作。
//LocalDateTime --> String
//获取当前时间
LocalDateTime localDateTime = LocalDateTime.now();
//格式化
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String startTime = dateTimeFormatter.format(localDateTime);
System.out.println(startTime);
//String --> LocalDateTime
String ss = "2020-11-25 00:00:12";
//格式化
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(LocalDateTime.parse(ss,dateTimeFormatter));
七、Optional 类
Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
Optional 类的引入很好的解决空指针异常。
public static void main(String[] args) {
//如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。不推荐该方法
/*if (optional.isPresent()) {
System.out.println(optional.get());
}
*/
//为空
Optional<String> optional1 = Optional.empty();
//value一定不为空
Optional<String> optional2 = Optional.of("hello");
//value可为空可不为空
Optional<String> optional3 = Optional.ofNullable("hello");
//推荐写法:
optional.ifPresent(ele -> System.out.println(ele));
System.out.println(optional3.orElse("world");
}
//例子:
Employee employee1 = new Employee();
employee1.setName("zhangsan");
Employee employee2 = new Employee();
employee2.setName("lisi");
List<Employee> list = Arrays.asList(employee1,employee2);
Company company = new Company();
company.setName("company1");
company.setEmployees(list);
System.out.println(company.getEmployees());
Optional<Company> optional = Optional.ofNullable(company);
//list类型的对象不是null返回本身,是null则创建空list返回
System.out.println(optional.map(ele -> ele.getEmployees()).orElse(Collections.emptyList()));