一、java8新特性
1、Lambda:表达式- - - - - Lambda允许把函数作为一个方法的参数
2、方法引用- - - - - 可以直接引用已有的java类或对象(实例)的方法或构造器
3、默认方法- - - - - 接口中一个实现的方法
4、Stream Api - - - - - 新添加的stream API(java.util.stream),把真正的函数式编程风格引入到Java中
5、Optional类 - - - - - 已经成为Java8类库的一部分,解决空指针异常
6、日期时间 API - - - - - 将日期时间的操作类集中到java.time类中
二、详细简介
1.Lambda:表达式
1、参数列表可以不写数据列表类型,因为JVM编译器通过上下文推断数据类型,即"类型推断"
(x, y) -> {Integer.compare(x,y)}
2、Java8中内置的四大核心接口
Comsumer<T> ----> 消费型接口、有去无回
void accept(T t)
Supplier<T> ----> 供给型接口、什么不给返回T类型
T get()
Function<T, R> -----> 函数型接口、给T返R(T、R也可以同一类型)
R apply(T t)
Predicate<T> -----> 断言型接口、if判断
boolean test(T t)
3、变量作用域: Lambda表达式只能引用标记了final的外部局部变量,这就是说不能在Lambda内部修改定义在域外的局部变量,可以不使用final修饰,但不可以修改
2.方法引用
若Lambda体中的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为方法引用是Lambda表达式的另一种表现形式)
主要有有三种语法格式:
- 对象 :: 实例方法名
- 类 :: 静态方法名
- 类 :: 实例方法名
注意: 1、Lambda体中调用方法的参数列表与返回值,要与函数式接口中抽象方法的函数列表和返回值类型保持一致
2、若Lambda 参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用 ClassName :: method
3.接口中的默认方法和静态方法
public interface Sized {
// 普通抽象方法,默认是public abstract修饰的,没有方法体
int size();
/*
* 默认方法,有方法体
*/
default boolean eat() {
System.out.println("这是默认方法");
}
/*
* 静态方法,有方法体
*/
public static void say() {
System.out.println("这是静态方法");
}
}
接口默认方法的“类优先”原则
----> 若一个接口中定义了一个默认方法,而另一个父类或接口中又定义了一个同名的方法时
- 选择父类中的方法,如果一个父类提供了具体的实现,那么接口中具有相同名称和参数列表的默认方式被忽略
- 接口冲突,如果一个接口提供一个默认方法,而另一个接口也提供了一个具有相同名称和参数列表的方法(不管方法是否默认方法),那么必须覆盖该方法来解决冲突
4.强大的Stream API
流(stream) 到底是什么呢?
---- 是数据渠道,用于操作数据源(集合、数组等) 所生成的元素序列
三步骤
1、创建Stream : 一个数据源(如集合、数组) 获取一个流
2、中间操作: 一个中间操作链,对数据源的数据进行处理
3、终止操作: 一个终止操作,执行中间操作链,并产生结果
1、创建Stream
// 1、可以通过Collection 系列接口提供的stream() 或parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
// 2、通过Arrays 中的静态方法stream() 获取数组流
Employee emp = new Employee[10];
Stream<Employee> stream = Arrays.stream(emp)
// 3、通过Stream类中的静态方法of()
Stream<String> stream = Stream.of("aa","bb","cc");
// 4、 创建无限流
// 迭代
Stream<String> stream = Stream.iterate(0,(x) -> x + 2);
stream.limit(4L).forEach(System.out::println)
// 生成
Stream.generate(() -> Math.random()).limit(5L).forEach(System.out::println)
2、中间操作
// 筛选与切片
filter(Predicate<? super T> predicate) ----> 接收Lambda,从流中排除某些元素
limit(long maxSize) ----> 截断流,使其元素不超过给定数量
skip(long n) ----> 跳过元素,返回一个扔掉前 n 个元素的流,若流中元素不足 n 个,则返回一个空流,与limit(n) 互补
distinct() ----> 筛选,通过流中所生成的hashcode() 和 equals() 去重,需要重写这两个方法
// 示例
list.stream().filter((e) -> e.getAge > 10).limit(2L).forEach(System.out::println)
// 映射
map(Function<? super T,? extends R> mapper) ----> 接收Lambda,将元素转换成其他形式提取信息,
接收一个函数作为参数,该函数会被应用到每个元素上,并将映射成一个新的元素
flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
----> 接收一个函数作为参数,将流中的每一个值都换成另一个流,然后把所有流连成一个流
//排序
sorted() -----> 自然排序
sorted(Comparator<? super T> comparator) ----> 定制排序
3、终止操作
// 查找与匹配
boolean allMatch(Predicate<? super T> predicate) ----> 检查是匹配所有元素
boolean anyMatch(Predicate<? super T> predicate) ----> 检查是否至少匹配一个元素
boolean noneMathch(Predicate<? super T> predicate) ----> 检查是否没有匹配所有元素
Optional<T> findFirst() ----> 返回描述此流的第一个元素的Optional如果流为空,则返回一个空的Optional
Optional<T> findAny() ----> 返回流中的任意元素的Optional如果流为空,则返回一个空的Optional
long count() ----> 返回流中的元素的总个数
Optional<T> max(Comparator<? super T> comparator) ----> 根据提供的 Comparator返回此流的最大元素。
Optional<T> min(Comparator<? super T> comparator) ----> 根据提供的 Comparator返回此流的最小元素。
// 归约
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator) ----> 可以将流中元素反复结合起来,得到一个值
//收集
<R,A> R collect(Collector<? super T,A,R> collector) ----> 将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中元素做汇总的方法
Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map),但是Collectors 实用类提供了很多静态方法,可以方便的创建常见收集器实例
// 示例
List<String> ll = list.stream().collect(Collectors.toList());
并行流与顺序流
- 并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流
- Java8 中将并行进行了优化,我们可以很容易的对数据进行并行操作,Stream API 可以声明性的通过parallel() 与 sequential() 在并行流与顺序流之间进行切换
5.Optional类
Optional 类(java.util.Optional) 是一个容器类,代表一个值存在或不存在,原来用null 表示一个值不存在,现在 Optional 可以更好的表达这个概念,并且可以避免空指针异常
static <T> Optional<T> Optional.of(T t) ----> 创建一个Optional实例
static <T> Optional<T> Optional.empty() ----> 创建一个空的Optional实例
static <T> Optional<T> Optional.ofNullable(T t) ----> 若t 不为null,创建Optional 实例,否则空实例
boolean isPresent() ----> 判断是否包含值
T orElseGet(Supplier<? extends T> s) ----> 如果调用对象包含值,返回该值,否则返回 s 获取的值
T osElse(T t) ----> 若果调用对象包含值,返回值,否则返回t
6.日期时间API
在旧版的 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(时区) − 通过制定的时区处理日期时间。
LocalDateTime currentTime = LocalDateTime.now();// 获取当前的日期时间
DateTimeFormatter dt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime.of(LocalDate.now(),LocalTime.MIN).format(dt); //2021-08-04 00:00:00
LocalDate date1 = currentTime.toLocalDate(); // LocalDate.now() 获取年月日
Month month = currentTime.getMonth(); // 月
int day = currentTime.getDayOfMonth(); // 天
int seconds = currentTime.getSecond(); // 秒
Date与LocalDateTime、LocalDate、LocalTime互相转换
// Date 转成 LocalDateTime、LocalDate、LocalTime
Date date = new Date();
// 系统默认时区 服务器时区不对会导致转换后的时间不对
ZoneId zoneId = ZoneId.systemDefault();
Instant instant = date.toInstant();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId);
LocalDate localDate = localDateTime.toLocalDate();
LocalTime localTime = localDateTime.toLocalTime();
// LocalDateTime 转成 Date
LocalDateTime localDateTime = LocalDateTime.now();
ZoneId zoneId = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zoneId).toInstant();
Date date = Date.from(instant);
// LocalDate 转成 Date
LocalDate localDate = LocalDate.now();
ZoneId zone = ZoneId.systemDefault();
Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
Date date = Date.from(instant);
// LocalTime 转成 Date
LocalTime localTime = LocalTime.now();
LocalDate localDate = LocalDate.now();
ZoneId zone = ZoneId.systemDefault();
Instant instant = LocalDateTime.of(localDate, localTime).atZone(zone).toInstant();
Date date = Date.from(instant);
总结
个人笔记,仅供参考