jdk8新特性之方法引用和日期

方法引用的三种表现形式

方法引用的基本思想是,如果一个Lambda代表的只是“直接调用这个方法”,那 最好还是用名称来调用它,而不是去描述如何调用它。事实上,方法引用就是让 你根据已有的方法实现来创建Lambda表达式。但是,显式地指明方法的名称, 你的代码的可读性会更好。所以方法引用只是在内容中只有一个表达式的简写。

当 你 需 要使用 方 法 引用时 , 目 标引用 放 在 分隔符::前 ,方法 的 名 称放在 后 面 ,即ClassName :: methodName 。例如 ,Apple::getWeight就是引用了Apple 类中定义的方法getWeight。请记住,不需要括号,因为你没有实际调用这个方 法。方法引用就是Lambda表达式(Apple a) ­> a.getWeight()的快捷写法。

这里有种情况需要特殊说明,就是类的构造函数情况,这个时候是通过 ClassName::new这种形式创建Class构造函数对应的引用,例如

若lambda体中的内容有方法已经实现了,那么可以使用”方法引用“

也可以理解为方法引用是lambda表达式的另外一种表现形式并且其语法比lambda表达式更加简单

三种表现形式
对象::实例方法名
类::静态方法名
类::实例方法名(lambda参数列表中第一个参数是实例方法的调用者,第二个是实例方法的参数时可用)		
// TODO: 2022/8/29 方法引用-对象::实例方法
Consumer<Integer> con2 = System.out::println;
con2.accept(200);

// TODO: 2022/8/29 方法引用-类::静态方法名
BiFunction<Integer,Integer,Integer> bigFun = (x, y)->Integer.compare(x,y);
BiFunction<Integer,Integer,Integer> bigFun2 = Integer::compareTo;
System.out.println(bigFun.apply(100, 200));
System.out.println(bigFun2.apply(800, 600));

// TODO: 2022/8/29 方法引用-类::实例方法名
BiFunction<String,String,Boolean> bigFun3 = (x,y)->x.equals(y);
BiFunction<String,String,Boolean> bigFun4 = String::equals;
System.out.println(bigFun3.apply("a", "a"));
System.out.println(bigFun4.apply("b", "c"));
注意:

1、lambda体中调用方法的参数列表返回值类型,要与函数式接口抽象方法函数列表返回值类型保持一致!

2、若lambda参数列表中的第一个参数是实例方法的调用者,而第二个参数是实例方法的参数时,可以使用ClassName::method

特殊例子
// TODO: 2022/8/29 构造方法引用 类名::new
Supplier<String> sup = () -> new String();
System.out.println(sup.get());
Supplier<String> sup2 = String::new;
System.out.println(sup2.get());

// TODO: 2022/8/29 类名::new(带一个参数)
Function<String, Integer> fun = x -> new Integer(x);
Function<String, Integer> fun2 = Integer::new;
System.out.println(fun.apply("1000"));
System.out.println(fun2.apply("2000"));

// TODO: 2022/8/29 数组引用 
Function<Integer, String[]> fun = x -> new String[x];
Function<Integer, String[]> fun2 = String[]::new;
String[] strArray = fun2.apply(10);
Arrays.stream(strArray).forEach(System.out::println);

日期/时间改进

1 * 之前使用的java.util.Date月份从0开始,我们一般会+1使用,很不方便, java.time.LocalDate月份和星期都改成了enum

2 * java.util.Date和SimpleDateFormat都不是线程安全的,而LocalDate和LocalTime 和最基本的String一样,是不变类型,不但线程安全,而且不能修改。

3 * java.util.Date是一个“万能接口”,它包含日期、时间,还有毫秒数,更加明确需求取 舍

4 * 新接口更好用的原因是考虑到了日期时间的操作,经常发生往前推或往后推几天的情 况。用java.util.Date配合Calendar要写好多代码,而且一般的开发人员还不一定能写对。

LocalDate/LocalTime/LocalDateTime

LocalDate为日期处理类、LocalTime为时间处理类、LocalDateTime为日期时间处理类

方法都类似,具体可以看API文档或源码,选取几个代表性的方法做下介绍。

now相关的方法可以获取当前日期或时间

of方法可以创建对应的日期或时间

parse方法 可以解析日期或时间

get方法可以获取日期或时间信息

with方法可以设置日期或时间信息

plus或minus方法可以增减日期或时间信息
TemporalAdjusters

这个类在日期调整时非常有用,比如得到当月的第一天、最后一天,当年的第一天、最后一

天,下一周或前一周的某天等。

// TODO: 2022/8/31 获取当前日期,只含年月日 固定格式 yyyy-MM-dd
LocalDate today = LocalDate.now();

// TODO: 2022/8/31 根据年月日去日期,5月就是5
LocalDate oldDate = LocalDate.of(2018, 5, 1);
System.out.println("oldDate = " + oldDate);

// TODO: 2022/8/31 根据字符串取:默认格式yyyy-MM-dd,02不能写成2
LocalDate yesteday = LocalDate.parse("2018-05-03");

// TODO: 2022/8/31 如果不是闰年 传入29号也会报错
//LocalDate localDate = LocalDate.parse("2018-02-29"); 会报错的

// TODO: 2022/8/31 ==========日期转换
// TODO: 2022/8/31
LocalDate today1 = LocalDate.now();
// TODO: 2022/8/31 取本月第一天: 2022-08-01
LocalDate firstDayOfMonth = today1.with(TemporalAdjusters.firstDayOfMonth());
// TODO: 2022/8/31 取本月第二天: 2022-08-02
LocalDate secondDayOfMonth = today1.withDayOfMonth(2);
// TODO: 2022/8/31 取本月最后一天,再也不用计算是28、29、30还是31: 2022-08-31
LocalDate lastDayOfMonth = today1.with(TemporalAdjusters.lastDayOfMonth());
// TODO: 2022/8/31 取本月最后一天的下一天: 2022-09-01
LocalDate nextDay = lastDayOfMonth.plusDays(1);
// TODO: 2022/8/31 取2018年10月第一个周三:2018-10-03
LocalDate firstWednesday = LocalDate.parse("2018-10-01").with(TemporalAdjusters.firstInMonth(DayOfWeek.WEDNESDAY));
DateTimeFormatter

以前日期格式化一般用SimpleDateFormat类,但是不怎么好用,现在1.8引入了 DateTimeFormatter类,默认定义了很多常量格式(ISO打头的),在使用的时候一般配合 LocalDate/LocalTime/LocalDateTime使用,比如想把当前日期格式化成yyyy-MM-dd hh:mm:ss的形式:

LocalDateTime dt = LocalDateTime.now(); 
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy‐MM‐dd hh:mm:ss");
System.out.println(dtf.format(dt));
时间戳转换
// TODO: 2022/8/31 获得时分秒.纳秒 22:26:11.800
LocalTime todayTimeWithMillisTime = LocalTime.now();
// TODO: 2022/8/31 不带纳秒值 22:26:11
LocalTime todayTimeWithNoMillisTime = LocalTime.now().withNano(0);
LocalTime time = LocalTime.parse("23:59:59");

// TODO: 2022/8/31 转化为时间戳 毫秒值
long time1 = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
long time2 = System.currentTimeMillis();

// TODO: 2022/8/31 时间戳转化为LocalDateTime 2022-08-31 22:43:29.645
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
String formatTime = dateTimeFormatter.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(time1), ZoneId.of("Asia/Shanghai")));
System.out.println("formatTime = " + formatTime);
LocalDateTime格式化转换
// TODO: 2022/8/31 DateTimeFormatter: 格式化时间/日期
// 自定义格式
LocalDateTime ldt = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
String strDate = ldt.format(formatter);
String strDate2 = formatter.format(ldt);
System.out.println("strDate = " + strDate);
System.out.println("strDate2 = " + strDate2);

// TODO: 2022/8/31 使用api提供的格式
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE;
LocalDateTime ldt2 = LocalDateTime.now();
String strDate3 = dtf.format(ldt2);
System.out.println("strDate3 = " + strDate3);

// TODO: 2022/8/31 解析字符串to时间
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime time = LocalDateTime.now();
String localTime = dateTimeFormatter.format(time);
LocalDateTime ldt4 = LocalDateTime.parse("2017-09-28 17:07:05", dateTimeFormatter);
System.out.println("LocalDateTime转成String类型的时间:"+localTime);
System.out.println("String类型的时间转成LocalDateTime:"+ldt4);
LocalDateTime基本操作
// TODO: 2022/8/31 从默认失去的系统始终获取当前的日期时间,不用考虑时区差
LocalDateTime dateTime = LocalDateTime.now();
// TODO: 2022/8/31  2022-08-31T23:05:02.831
System.out.println("dateTime = " + dateTime);

System.out.println("dateTime.getYear() = " + dateTime.getYear());
System.out.println("dateTime.getMonthValue() = " + dateTime.getMonthValue());
System.out.println("dateTime.getDayOfMonth() = " + dateTime.getDayOfMonth());
System.out.println("dateTime.getHour() = " + dateTime.getHour());
System.out.println("dateTime.getMinute() = " + dateTime.getMinute());
System.out.println("dateTime.getSecond() = " + dateTime.getSecond());
System.out.println("dateTime.getNano() = " + dateTime.getNano());

// TODO: 2022/8/31 手动创建一个LocalDateTime实例 
LocalDateTime date2 = LocalDateTime.of(2017, 12, 17, 9, 34, 31);
System.out.println("date2 = " + date2);
// TODO: 2022/8/31 进行加操作,得到新的日期实例
LocalDateTime date3 = date2.plusDays(12);
System.out.println("date3 = " + date3);
// TODO: 2022/8/31 进行减操作
LocalDateTime date4 = date3.minusYears(2);
System.out.println("date4 = " + date4);
获取时间戳
// TODO: 2022/8/31 获取毫秒值
// TODO: 2022/8/31 时间戳 1970年1月1日00:00:00 到某一个时间点的毫秒值
// TODO: 2022/8/31 默认获取UTC时区
Instant ins = Instant.now();
System.out.println("ins = " + ins);

System.out.println(LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
System.out.println(System.currentTimeMillis());

System.out.println(Instant.now().toEpochMilli());
System.out.println(Instant.now().atOffset(ZoneOffset.ofHours(8)).toInstant().toEpochMilli());
计算间隔时间
 // TODO: 2022/8/31 计算时间间隔
// TODO: 2022/8/31 Duration:计算两个时间之间的间隔
// TODO: 2022/8/31 Period:计算两个日期之间的间隔
Instant instant = Instant.now();
//LocalTime localTime = LocalTime.now();

try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
Instant instant2 = Instant.now();
//LocalTime localTime2 = LocalTime.now();
Duration duration = Duration.between(instant, instant2);
System.out.println("duration = " + duration);
System.out.println(duration.toMillis());

System.out.println("===================");

LocalDate localDate = LocalDate.now();
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
LocalDate localDate2 = LocalDate.of(2016, 12, 12);
Period period = Period.between(localDate, localDate2);
System.out.println("period = " + period);
时间操作
// TODO: 2022/8/31 temperalAdjust 时间校验器
LocalDateTime ldt1 = LocalDateTime.now();
System.out.println("ldt1 = " + ldt1);

// TODO: 2022/8/31 获取一年中的第一天
LocalDateTime ldt2 = ldt1.withDayOfYear(1);
System.out.println("ldt2 = " + ldt2);
// TODO: 2022/8/31 获取一个月中的第一天
LocalDateTime ldt3 = ldt1.withDayOfMonth(1);
System.out.println("ldt3 = " + ldt3);

// TODO: 2022/8/31 例如获取下周日
LocalDateTime ldt4 = ldt1.with(TemporalAdjusters.next(DayOfWeek.FRIDAY));
System.out.println("ldt4 = " + ldt4);

// TODO: 2022/8/31 获取下一个工作日
LocalDateTime ldt5 = ldt1.with((t) -> {
    LocalDateTime ldt6 = (LocalDateTime) t;
    DayOfWeek dayOfWeek = ldt6.getDayOfWeek();
    if (DayOfWeek.FRIDAY.equals(dayOfWeek)) {
        return ldt6.plusDays(3);
    } else if (DayOfWeek.SATURDAY.equals(dayOfWeek)) {
        return ldt6.plusDays(2);
    } else {
        return ldt6.plusDays(1);
    }
});
System.out.println("ldt5 = " + ldt5);
posted @ 2022-08-31 23:40  蔡地像徐坤  阅读(84)  评论(0编辑  收藏  举报