一、Lambda表达式
Lambda表达式(->):Lambda允许把函数作为一个方法的参数(函数作为参数传递到方法中)。
->
将Lambda拆分为两部分。
- 左侧:参数列表。
- 右侧:执行功能。
语法规则:
- 无参数,无返回值
()-> System.out.println(“Hello Lambda!”)
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"匿名内实现多线程!!!");
}
}).start();
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"Lambad内实现多线程!!!");
}).start();
- 有一个参数,并且无返回值
(x)-> System.out.println(x)
Consumer<String> consumer =(x)->System.out.println(x);
consumer.accept("你好");
- 若只有一个参数,小括号可以省略不写
x-> System.out.println(x)
Consumer<String> consumer =x->System.out.println(x);
consumer.accept("你好");
- 有两个以上的参数,有返回值,并且 Lambda体中有多条语句
Comparator<Integer> cm =(x,y)->{
System.out.println("函数式接口");
return Integer.compare(x,y);
};
- 若 Lambda体中只有一条语句, return和大括号都可以省略不写
Comparator<Integer> com =(x,y) -> Integer. compare (x,y)
Lambda表达式的参数列表的数据类型可以省略不写,编译器通过上下文推断出,数据类型,即“类型推断”
(Integer x, Integer y)-> Integer. compare(x, y)
练习
1.声明函数式接口处理字符串
package com.zhou;
//代表这是一个函数式接口,只能有一个抽象方法
@FunctionalInterface
public interface MyFunction {
String getValue (String str);
}
//字符串处理
public String test3(String str,MyFunction my) {
return my.getValue(str);
}
@Test
public void test4() {
//转大写
String ss = test3("abcdefg", (str) -> str.toUpperCase());
//截取
String ss1 = test3("abcdefg", (str) -> str.substring(1,4));
System.out.println(ss);
System.out.println(ss1);
}
2.声明一个带两个泛型的函数式接口,泛型类型为<T, R> T为参数,R为返回值,并计算相加
package com.zhou;
public interface MyFunctionTwo <T,R>{
R getValue(T t1,T t2);
}
public void test5(Long l1,Long l2,MyFunctionTwo<Long,Long> my) {
System.out.println(my.getValue(l1,l2));
}
@Test
public void test6() {
test5(100L,200L,(x,y)->x+y);
}
二、Java8内置四大函数式接口
- 消费型接口
Consumer<T>
void accept(T t)
//消费型接口
@Test
public void test1 () {
shop(200,x->System.out.println("消费"+x+"元"));
}
public void shop (double money, Consumer<Double> t){
t.accept(money);
}
- 供给型接口
Supplier<Integer>
T get();
//供给型接口
//产生整数放入到集合
public List<Integer> getNumList (Integer num, Supplier<Integer> sp){
List<Integer> list = new ArrayList<>();
for (int i = 0; i <num ; i++) {
Integer ss = sp.get();
list.add(ss);
}
return list;
}
- 函数型接口
Function<T,R>
R apply(T t);
//函数型接口
//处理字符串
public String strHandler(String str, Function<String,String> fun){
return fun.apply(str);
}
@Test
public void test3 () {
String str = strHandler("ABCDEFG", String::toLowerCase);
String s = strHandler("\t\t\t hello ", String::trim);
System.out.println(str);
System.out.println(s);
}
- 断言型接口
Predicate<T t>
Boolean test(T t);
//断言型接口
//将满足条件的字符串放入集合
public List<String> getStr(List<String> str, Predicate<String> prc) {
ArrayList<String> list = new ArrayList<>();
for (String s : str) {
if(prc.test(s)){
list.add(s);
}
}
return list;
}
@Test
public void test4 () {
List<String> strs = Arrays.asList("张三","王麻子","李四","王五");
List<String> str = getStr(strs, x -> x.length()>2);
str.forEach(System.out::println);
}
三、方法引用与构造器引用
3.1、方法引用
方法引用:方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
注意:
Lambda 体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保持一致!
若Lambda 参数列表中的第一参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName : method!
主要有三种格式
-
对象 ::实例方法名
-
类 ::静态方法名
-
类::实力方法名
//对象::实例方法
@Test
public void test1 () {
Object obj = new Object();
Supplier<Object> sp =obj::getClass;
Object o = sp.get();
System.out.println(o);
}
//静态方法::实例方法
@Test
public void test2 () {
Comparator<Integer> compare = Integer::compare;
int compare1 = compare.compare(100, 20);
System.out.println(compare1);
}
//类::实例方法名
@Test
public void test3 () {
BiPredicate<String,String> ss = String::equals;
boolean test = ss.test("ss", "ss");
System.out.println(test);
}
3.2、构造器引用
注意:需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致!│
//构造器引用
@Test
public void test4 () {
Function<Integer,User> fun =User::new;
User us = fun.apply(111111);
System.out.println(us);
Function<Integer,String[]> fc = String[]::new;
String[] str = fc.apply(22);
System.out.println(str.length);
}
四、Stream API
Stream API:新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
Stream操作主要有以下三个步骤:
- 创建Stream
从一个数据源,如集合、数组中获取流。
- 中间操作
一个操作的中间链,对数据源的数据进行操作。
- 终止操作
一个终止操作,执行中间操作链,并产生结果。
4.1、创建流
-
创建Stream流的四种方式
-
通过Collection集合提供的stream()方法、和paralleStram()
-
通过ArrayList中的stream()方法。
-
通过Stream的静态of方法()。
-
创建无限流
@Test
public void test1(){
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
System.out.println(stream);
}
@Test
public void test2(){
int [] arr={1,2,3,4};
IntStream stream = Arrays.stream(arr);
}
@Test
public void test3(){
Stream<String> zs = Stream.of("zs", "ls", "ww");
zs.forEach(System.out::println);
}
@Test
public void test4(){
Stream<Integer> num = Stream.iterate(1, (x) -> x+2);
num.limit(5).forEach(System.out::println);
}
4.2、中间操作
4.2.1、过滤与切片
filter:接受Lambda从流中排除某些元素。
limit:截断流,使其元素不超过指定数量。
skip:跳过元素,返回一个人掉了前n个的流。
distinct:过滤,通过流的equals和hashcode去重元素。
@Test
public void test5 () {
List<Integer> list = Arrays.asList(21,20,50,28,60,60,50);
//得到流,判断集合里面值不超过50的人
list.stream().filter((x)->x>=50)
//跳过前面一个数据取后面一个数据
.skip(1)
//只显示1条满足条件的数据
.limit(2)
//去除
.distinct()
//终止操作
.forEach(System.out::println);
}
4.2.2、映射
map:接收Lambda表达式,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
flatMap接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
@Test
public void test6 () {
List<String> list = Arrays.asList("aaa","bbb","ccc");
//map接收到Stream的时候会把Stream放入到一个新的Stream最后返回一个包含多个Stream的Stream
list.stream().map(String::toUpperCase).forEach(System.out::println);
//flatMap会将接受到的Stream的元素放入到一个新的Stream最后返回一个包含多个Value的Stream
list.stream().flatMap(Streams::getStr).forEach(System.out::println);
}
public static Stream<Character> getStr(String str){
List<Character> list = new ArrayList<>();
for (Character s : str.toCharArray()) {
list.add(s);
}
return list.stream();
}
4.2.3、排序
排序分为自然排序和定制排序。
sorted()–自然排序(Comparable)。
sorted(Comparator com)–定制排序(Comparator)。
package com.zhou;
public class User {
private Integer id;
private String name;
private Integer age;
public User() {
}
public User(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
@Test
public void test7 () {
List<User> userList = Arrays.asList(
new User(1,"李四",20),
new User(2,"王麻子",18),
new User(3,"张三",20)
);
//sorted()--自然排序(Comparable)
// num.stream().sorted().forEach(System.out::println);
//sorted(Comparator com)--定制排序(Comparator)
userList.stream().sorted((e1,e2)->{
//年龄相等按照姓名排序,否则按照年龄进行升序排序
if(e1.getAge()==e2.getAge()){
return e1.getName().compareTo(e2.getName());
}else{
return e1.getAge().compareTo(e2.getAge());
}
}).forEach(System.out::println);
}
4.3、终止操作
Stream的终止操作有查找和匹配、归约和收集。
4.3.1、查询和匹配
- allMatch–检查是否匹配所有元素
- anyMatch–检查是否至少匹配一个元素
- noneMatch–检查是否没有匹配所有元素
- findFirst–返回第一个元素
- findAny–返回当前流中的任意元素
- count–返回流中元素的总个数
- max–返回流中最大值
- min–返回流中最小值
package com.zhou;
public class User {
private Integer id;
private String name;
private Integer age;
public User() {
}
public User(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
/**
* 查找或匹配
*/
@Test
public void test8 () {
List<User> userList = Arrays.asList(
new User(1,"李四",20),
new User(2,"王麻子",18),
new User(3,"张三",21)
);
//查询是否都是成年人
boolean b = userList.stream().allMatch(x -> x.getAge()>=18);
System.out.println(b);
//查询至少有叫张三的这个人
boolean name = userList.stream().anyMatch(x -> x.getName().equals("张三"));
System.out.println(name);
//检查没有叫张三的这个人
boolean names = userList.stream().noneMatch(x -> x.getName().equals("迪迦奥特曼"));
System.out.println(names);
//返回第一条数据
Optional<User> first = userList.stream().findFirst();
System.out.println(first);
//统计元素的个数
long count = userList.stream().count();
System.out.println("元素的个数:"+count);
//年龄最大值人的信息
Optional<User> max = userList.stream().max((x,y)->x.getAge().compareTo(y.getAge()));
System.out.println("最大值:"+max);
//年龄最小值人的信息
Optional<User> min = userList.stream().min((x, y) -> x.getAge().compareTo(y.getAge()));
System.out.println("最小值:"+min);
}
4.3.2、归约
- 规约就是将流中的元素反复结合起来得到一个值。
Optional<T> reduce(BinaryOperator<T> accumulator);
T reduce(T identity, BinaryOperator<T> accumulator);
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
@Test
public void test9() {
List<Integer> list = Arrays.asList(10, 20, 30, 40, 50);
//0为起始值代表集合中的第一个元素,每次取出一个值都会把值放y里面进行相加
//第一种写法
Integer reduce = list.stream().reduce(0, (x, y) -> x + y);
System.out.println(reduce);
//第二种写法
Optional<Integer> reduce1 = list.stream().reduce(Integer::sum);
System.out.println(reduce1.get());
}
4.3.3、收集
将流转换为其他形式,接收一个Collector接口实现 ,用于给Stream中汇总的方法。
Optional<T> reduce(BinaryOperator<T> accumulator);
T reduce(T identity, BinaryOperator<T> accumulator);
<U> U reduce(U identity,
BiFunction<U, ? super T, U> accumulator,
BinaryOperator<U> combiner);
List<User> userList = Arrays.asList(
new User(1,"李四",20),
new User(2,"王麻子",18),
new User(3,"张三",21),
new User(3,"张三",21)
);
//将姓名收集到list集合中
List<String> collect = userList.stream().map(User::getName).collect(Collectors.toList());
collect.forEach(System.out::println);
System.out.println("-----------");
//将姓名收集到set集合中
Set<String> collects = userList.stream().map(User::getName).collect(Collectors.toSet());
collects.forEach(System.out::println);
//将姓名保收集到其他集合中
System.out.println("-----------");
LinkedHashSet<String> collect1 = userList.stream().map(User::getName)
.collect(Collectors.toCollection(LinkedHashSet::new));
collect1.forEach(System.out::println);
//使用收集进行规约操作
Double collect2 = userList.stream().collect(Collectors.averagingDouble(x -> (int) x.getAge()));
System.out.println("平均年龄:"+collect2);
//使用收集进行分组
Map<Integer, List<User>> collect3 = userList.stream().collect(Collectors.groupingBy(User::getAge));
System.out.println(collect3);
//多级分组
Map<Integer, Map<Object, List<User>>> collect4 = userList.stream()
//如果年龄大于18就是成年人否则就是未成年
.collect(Collectors.groupingBy(User::getAge, Collectors.groupingBy((x) -> {
if (((User) x).getAge() >= 18) {
return "成年人";
}else {
return "未成年";
}
})));
System.out.println(collect4);
//连接字符串
String collect5 = userList.stream().map(User::getName).collect(Collectors.joining(","));
System.out.println(collect5);
五、并行流和串行流
-
并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流。
-
Stream API可以声明性地通过
parallel()
与sequential()
在并行流与顺序流之间进行切换。 -
Fork/Join框架:就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行join汇总。
Fork/Join框架与传统线程池的区别
采用工作窃取模式(work-stealing)
当执行新的任务时,它可以将其拆分成更小的任务执行,并将小任务加到线程队列中,然后再从一个随机线程的队列中偷一个并把它放在自己的队列中。
相对于一般的线程池实现,fork/join框架的优势体现在对其中包含的任务的处理方式上。在一般线程池中,如果一个线程正在执行的任务由于某些原因无法继续运行,那么该线程会处于等待状态。
而在fork/join框架实现中,如果某个子问题由于等待另外一个子问题的完成而无法继续运行,那么处理该子问题的线程会主动寻找其他尚未运行的子问题来执行,这种方式减少了线程的等待时间,提高了性能。
package com.zhou;
import java.util.concurrent.RecursiveTask;
public class ForkJoinCalculate extends RecursiveTask<Long> {
private long start;
private long end;
//临界值
private static final long THRESHOLD=10000L;
public ForkJoinCalculate(long start, long end) {
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length = end-start;
if(length<THRESHOLD){
long sum =0;
for (long i = start; i <end ; i++) {
sum +=i;
}
return sum;
}else {
long middle = (start+end)/2;
ForkJoinCalculate left = new ForkJoinCalculate(start,middle);
left.fork();//拆分子任务,同时压入线程队列
ForkJoinCalculate right = new ForkJoinCalculate(middle+1,end);
right.fork();
return left.join() + right.join();
}
}
}
@Test
public void test11(){
Instant start = Instant.now();
ForkJoinPool fo = new ForkJoinPool();
ForkJoinCalculate ff = new ForkJoinCalculate(0,10000000000L);
Long invoke = fo.invoke(ff);
System.out.println(invoke);
Instant end = Instant.now();
System.out.println("耗时:"+Duration.between(start,end).getSeconds()+"秒");
}
结果:-5345475101129947011
耗时:2秒
/**
* 使用普通for循环方式来计算,比较二者时间
*/
@Test
public void test13(){
long startTime = System.currentTimeMillis();
long sum = 0L;
for (long i = 0 ; i <= 10000000000L ; i ++ ){
sum += i;
}
System.out.println(sum);
long endTime = System.currentTimeMillis();
System.out.println("消耗时间:" + (endTime - startTime)/1000+"秒");
}
结果:-5340232216128654848
消耗时间:3秒
//计算1000亿数据累加
@Test
public void test12 () {
Instant start = Instant.now();
long reduce = LongStream.rangeClosed(0, 100000000000L).parallel().reduce(0, Long::sum);
System.out.println(reduce);
Instant end = Instant.now();
System.out.println("耗时:"+Duration.between(start,end).getSeconds()+"秒");
}
结果:932356074711512064
耗时:15秒
六、Otional类
Optional类:Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
package com.zhou;
public class User {
private Integer id;
private String name;
private Integer age;
public User() {
}
public User(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
@Test
public void test () {
//创建一个Optional实例,参数为null会报空指针异常
Optional<User> user = Optional.of(new User());
User user1 = user.get();
System.out.println(user1);
}
@Test
public void test1 () {
//允许传递为 null 参数
Optional<Object> o = Optional.ofNullable(null);
//判断参数是否存在
// if(o.isPresent()){
// System.out.println(o.get());
// }
//如果调用对象包含值返回值,否则返回获取的值
User user= (User) o.orElseGet(()->new User());
System.out.println(user);
//值存在返回,否则返回默认值
User user1= (User) o.orElse(new User(1,"李四",22));
System.out.println(user1);
}
//如果有值进行处理,并返回处理后的OPtional否则返回Optional.empty()
@Test
public void test2 () {
Optional<User> o = Optional.ofNullable(new User(1,"zs",22));
Optional<String> s = o.map(x -> x.getName());
System.out.println(s.get());
Optional<Integer> s1 = o.flatMap(x -> Optional.of(x.getAge()));
System.out.println(s1.get());
}
七、默认方法和静态方法
默认方法:默认方法就是一个在接口里面有了一个实现的方法。
package com.zhou;
public interface MyInterface {
//默认方法被default修饰
default String getStr () {
return "你好啊";
}
//静态方法
static void show () {
System.out.println("接口中的静态方法..........");
}
}
package com.zhou;
public class TestMyInterface implements MyInterface{
public static void main(String[] args) {
//通过接口实例化子类
//接口方法默认类优先原则:
//如果接口定义了默认方法.另一个父类或者接口定义了同名方法时,选择父类中的方法(父类方法被实现,接口中相同名称和参数的方法会被忽略)
//接口冲突。如果一个父接口和其他的接口具有相同的方法名称和参数必须使用覆盖来解决冲突.
MyInterface my = new TestMyInterface();
String str = my.getStr();
System.out.println(str);
MyInterface.show();
}
}
八、新的时间API
Date Time API:加强对日期与时间的处理,java.time包下的所有类都是不可变类型而且线程安全。
LocalDate
:不包含时间的日期,比如2019-10-14
。可以用来存储生日,周年纪念日,入职日期等。
@Test
public void localDate() {
//获取当前年月日
LocalDate today = LocalDate.now();
System.out.println("当前年月日:" + today);
// 获取年的两种方式
int thisYear = today.getYear();
int thisYearAnother = today.get(ChronoField.YEAR);
System.out.println("今年是" + thisYear + "年");
System.out.println("今年是" + thisYearAnother + "年");
// 获取月
Month thisMonth = today.getMonth();
System.out.println(thisMonth.toString());
// 这是今年的第几个月(两种写法)
int monthOfYear = today.getMonthValue();
// int monthOfYear = today.get(ChronoField.MONTH_OF_YEAR);
System.out.println("这个月是今年的第" + monthOfYear + "个月");
// 月份的天数
int length = today.lengthOfMonth();
System.out.println("这个月有" + length + "天");
// 获取日的两种方式
int thisDay = today.getDayOfMonth();
int thisDayAnother = today.get(ChronoField.DAY_OF_MONTH);
System.out.println("今天是这个月的第" + thisDay + "天");
System.out.println("今天是这个月的第" + thisDayAnother + "天");
// 获取星期
DayOfWeek thisDayOfWeek = today.getDayOfWeek();
System.out.println(thisDayOfWeek.toString());
// 今天是这周的第几天
int dayOfWeek = today.get(ChronoField.DAY_OF_WEEK);
System.out.println("今天是这周的第" + dayOfWeek + "天");
// 是否为闰年
boolean leapYear = today.isLeapYear();
System.out.println("今年是闰年:" + leapYear);
//构造指定的年月日
LocalDate anotherDay = LocalDate.of(2008, 8, 8);
System.out.println("指定年月日:" + anotherDay);
}
LocalTime
:与LocalDate
想对照,它是不包含日期的时间。
@Test
public void localTime() {
// 获取当前时间
LocalTime nowTime = LocalTime.now();
System.out.println("当前时间:" + nowTime);
//获取小时的两种方式
int hour = nowTime.getHour();
int thisHour = nowTime.get(ChronoField.HOUR_OF_DAY);
System.out.println("当前时:" + hour);
System.out.println("当前时:" + thisHour);
//获取分的两种方式
int minute = nowTime.getMinute();
int thisMinute = nowTime.get(ChronoField.MINUTE_OF_HOUR);
System.out.println("当前分:" + minute);
System.out.println("当前分:" + thisMinute);
//获取秒的两种方式
int second = nowTime.getSecond();
int thisSecond = nowTime.get(ChronoField.SECOND_OF_MINUTE);
System.out.println("当前秒:" + second);
System.out.println("当前秒:" + thisSecond);
// 构造指定时间(最多可到纳秒)
LocalTime anotherTime = LocalTime.of(20, 8, 8);
System.out.println("构造指定时间:" + anotherTime);
}
LocalDateTime
:包含了日期及时间,没有偏移信息(时区)。
// 当前日期和时间
LocalDateTime today = LocalDateTime.now();
System.out.println("现在是:" + today);
// 创建指定日期和时间
LocalDateTime anotherDay = LocalDateTime.of(2008, Month.AUGUST, 8, 8, 8, 8);
System.out.println("创建的指定时间是:" + anotherDay);
// 拼接日期和时间
// 使用当前日期,指定时间生成的 LocalDateTime
LocalDateTime thisTime = LocalTime.now().atDate(LocalDate.of(2008, 8, 8));
System.out.println("拼接的日期是:" + thisTime);
// 使用当前日期,指定时间生成的 LocalDateTime
LocalDateTime thisDay = LocalDate.now().atTime(LocalTime.of(12, 24, 12));
System.out.println("拼接的日期是:" + thisDay);
// 指定日期和时间生成 LocalDateTime
LocalDateTime thisDayAndTime = LocalDateTime.of(LocalDate.of(2008, 8, 8), LocalTime.of(12, 24, 12));
System.out.println("拼接的日期是:" + thisDayAndTime);
// 获取LocalDate
LocalDate todayDate = today.toLocalDate();
System.out.println("今天日期是:" + todayDate);
// 获取LocalTime
LocalTime todayTime = today.toLocalTime();
System.out.println("现在时间是:" + todayTime);
ZonedDateTime
:包含时区的完整的日期时间,偏移量是以UTC
/格林威治时间为基准的。
public class InstantDemo {
public static void main(String[] args) {
// 创建Instant对象
Instant instant = Instant.now();
// 通过ofEpochSecond方法创建(第一个参数表示秒,第二个参数表示纳秒)
Instant another = Instant.ofEpochSecond(365 * 24 * 60, 100);
// 获取到秒数
long currentSecond = instant.getEpochSecond();
System.out.println("获取到秒数:" + currentSecond);
// 获取到毫秒数
long currentMilli = instant.toEpochMilli();
System.out.println("获取到毫秒数:" + currentMilli);
}
}
Instant
:时间戳,与System.currentTimeMillis()
类似。
@Test
public void Instant() {
// 创建Instant对象
Instant instant = Instant.now();
// 通过ofEpochSecond方法创建(第一个参数表示秒,第二个参数表示纳秒)
Instant another = Instant.ofEpochSecond(365 * 24 * 60, 100);
// 获取到秒数
long currentSecond = instant.getEpochSecond();
System.out.println("获取到秒数:" + currentSecond);
// 获取到毫秒数
long currentMilli = instant.toEpochMilli();
System.out.println("获取到毫秒数:" + currentMilli);
}
Duration
:表示一个时间段。
@Test
public void duration() {
LocalDateTime from = LocalDateTime.now();
LocalDateTime to = LocalDateTime.now().plusDays(1);
// 通过between()方法创建
Duration duration = Duration.between(from, to);
// 通过of()方法创建,该方法参数为时间段长度和时间单位。
// 7天
Duration duration1 = Duration.of(7, ChronoUnit.DAYS);
// 60秒
Duration duration2 = Duration.of(60, ChronoUnit.SECONDS);
}
Period
:用来表示以年月日来衡量一个时间段。
@Test
public static void period() {
// 通过of方法
Period period = Period.of(2012, 12, 24);
// 通过between方法
Period period1 = Period.between(LocalDate.now(), LocalDate.of(2020,12,31));
}
DateTimeFormatter
:新的日期解析格式化类。
@Test
public void format() {
LocalDate today = LocalDate.now();
// 两种默认格式化时间方式
String todayStr1 = today.format(DateTimeFormatter.BASIC_ISO_DATE);
String todayStr2 = today.format(DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println("格式化时间:" + todayStr1);
System.out.println("格式化时间:" + todayStr2);
//自定义格式化
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
String todayStr3 = today.format(dateTimeFormatter);
System.out.println("自定义格式化时间:" + todayStr3);
}