目录
一、Lambda 表达式
(一)Lambda 表达式语法
(二)类型推断
二、函数式接口
(一)自定义函数式接口
(二)作为参数传递Lambda 表达式
(三)Java 内置四大核心函数式接口
三、方法引用
四、Stream API
(一)什么是Stream?
(二)Stream 的操作三个步骤
(三)创建流的四种方式
(四)Stream的中间操作
(五)Stream的终止操作
五、综合案例
六、新时间日期API
(一)使用LocalDate、LocalTime、LocalDateTime
(二)使用Instant时间戳
(三)Duration 和 Period
(四)日期的操纵
(五)解析与格式化
(六)时区的处理
(七)与传统日期处理的转换
七、接口中的默认方法与静态方法
八、其他新特性
(一)Optional 类
(二)重复注解与类型注解
一、Lambda 表达式
// 原来的匿名内部类
@Test
public void test1() {
Comparator<Integer> com = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return Integer.compare(o1, o2);
}
};
TreeSet<Integer> ts = new TreeSet<>(com);
}
// Lambda表达式
@Test
public void test2() {
Comparator<Integer> com = (o1, o2) -> Integer.compare(o1, o2);
TreeSet<Integer> ts = new TreeSet<>(com);
}
(一)Lambda 表达式语法
- 左侧:指定了 Lambda 表达式需要的所有参数
- 右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。
语法格式一:无参,无返回值,Lambda体只需一条语句
语法格式二:Lambda需要一个参数
语法格式三:Lambda只需要一个参数时,参数的小括号可以省略
语法格式四:Lambda需要两个参数,并且有返回值
语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略
(二)类型推断
二、函数式接口
- 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
- 我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
(一)自定义函数式接口
(二)作为参数传递Lambda 表达式
(三)Java 内置四大核心函数式接口
其他子接口(参数个数)
/*
* @Description Java8 内置四大核心函数式接口
* Consumer<T> : 消费型接口
* void accept(T t)
*
* Supplier<T> : 供给型接口
* T get();
*
* Function<T, R> : 函数型接口
* R apply(T t)
*
* Predicate<T> : 断言型接口
* boolean test(T t)
**/
public class TestLambda02 {
/*
* Predicate<T> : 断言型接口
* 将长度大于等于3的字符串输出
*/
@Test
public void test04() {
List<String> stringList = Arrays.asList("hello", "world","you");
List<String> list = getStringList(stringList, (s) -> s.length() > 3);
list.forEach(System.out::println);
}
public List<String> getStringList(List<String> stringList, Predicate<String> pre) {
List<String> strings = new ArrayList<>();
for (String s : stringList) {
if(pre.test(s)) {
strings.add(s);
}
}
return strings;
}
/*
* Function<T, R> : 函数型接口
*
*/
@Test
public void test03() {
String string = getString("\t\t\t 帅哥好帅", (str) -> str.trim());
System.out.println(string);
}
public String getString(String str, Function<String ,String> func) {
return func.apply(str);
}
/*
* Supplier<T> : 供给型接口
* 随机产生10个数字
*/
@Test
public void test02() {
int num = 10;
generator(num, () -> (int)(Math.random() * 100) + 1);
}
public void generator(int x, Supplier<Integer> sup) {
List<Integer> integerList = new ArrayList<>();
for(int i = 0; i < x; i ++) {
Integer integer = sup.get();
integerList.add(integer);
}
integerList.forEach(System.out::println);
}
/*
* Consumer<T> : 消费型接口
*/
@Test
public void test01() {
int num = 100;
consumer(num, x -> System.out.println("消费了" + num + "元"));
}
public void consumer(int num, Consumer<Integer> com) {
com.accept(num);
}
}
三、方法引用
- 对象::实例方法
- 类::静态方法
- 类::实例方法
/*
* 一、方法引用: 若Lambda体中的内容有方法已经实现了,我们可以通过方法引用
* (即方法引用是Lambda表达式的另外一种表现形式)
* 主要有三种语法格式:
*
* 对象::实例方法名
* 类::静态方法名
* 类::实例方法名
*
* 注意:Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的参数列表和返回值类型一致
*
* 二、构造器引用
* 格式: ClassName::New
*
* 注意:需要调用的构造器的参数列表要与函数式接口中的抽象方法的参数列表一致!
*
* 三、数组引用
* 格式:Type[]::new
*/
public class TestMethodRef {
// 数组引用
@Test
public void test05() {
Function<Integer, String[]> func = (x) -> new String[x];
String[] strings = func.apply(10);
System.out.println(strings.length);
Function<Integer, String[]> func2 = String[]::new;
String[] strs = func2.apply(20);
System.out.println(strs.length);
}
// 构造器引用
@Test
public void test04() {
Supplier<Employee> sup = () -> new Employee();
// 构造器引用的方式
Supplier<Employee> sup2 = Employee::new;
Employee employee = sup2.get();
System.out.println(employee);
/*
* 如何知道调用的是哪一个构造方法?
* 根据函数式接口传入的参数的个数决定调用的构造器方法
*/
Function<Integer, Employee> func = Employee::new;
Employee employee1 = func.apply(20);
System.out.println(employee1);
}
// 类::实例方法名
@Test
public void tes03() {
// 规则:若Lambda参数列表中的第一参数是实例方法的调用者,第二参数是实例方法的参数时,此时
// 可以通过 class::method
BiPredicate<String ,String> bp = (x, y) -> x.equals(y);
BiPredicate<String ,String> bp1 = String::equals;
}
// 对象::静态方法
@Test
public void test02() {
Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
Comparator<Integer> com1 = Integer::compare;
}
// 对象::实例方法
@Test
public void test01() {
PrintStream ps = System.out;
Consumer<String> con = (x) -> System.out.println(x);
Consumer<String> con2 = ps::println;
}
}
四、Stream API
(一)什么是Stream?
(二)Stream 的操作三个步骤
- 创建 Stream
- 中间操作
- 终止操作(终端操作)
(三)创建流的四种方式
方式一:Collection接口
方式二:数组创建流
/*
* 一、Stream的三个操作
* ① 创建Stream流对象
* ② 中间操作
* ③ 终止操作
*/
public class testStream {
// 创建stream
@Test
public void test1() {
//1.可以通过Collection 系列集合提供的stream() or parallelStream()
List<Integer> list = new ArrayList<>();
Stream<Integer> stream1 = list.stream();
//2. 通过Arrays的静态方法stream()获取数组流
Employee[] emps = new Employee[2];
Stream<Employee> stream2 = Arrays.stream(emps);
//3. 通过stream的静态方法of()
Stream<Integer> stream3 = Stream.of(1, 2, 3);
//4. 创建无限流
// 迭代
Stream<Integer> stream4 = Stream.iterate(0, (x) -> x + 2);
stream4.limit(10).forEach(System.out::println);
// 生成
Stream<Double> stream5 = Stream.generate(Math::random);
stream5.limit(10).forEach(System.out::println);
}
}
(四)Stream的中间操作
映射
排序
/*
* 一、Stream的三个操作
* ① 创建Stream流对象
* ② 中间操作
* ③ 终止操作
*/
public class testStreamApi {
List<Employee> empList = Arrays.asList(
new Employee("张三", 50, 7777.77),
new Employee("李四", 35, 8888.6),
new Employee("王五", 20, 999.55),
new Employee("赵六", 40, 1000.5),
new Employee("赵六", 40, 1000.5),
new Employee("赵六", 40, 1000.5));
// 中间操作
/*
排序
sorted()-自然排序(Comparable)
sorted(Comparator com)---定制排序(Comparator)
*/
@Test
public void test06() {
List<String> strs = Arrays.asList("aaa", "bbb", "ccc");
strs.stream()
.sorted() // 按已经实现的comparator接口的排序规则进行排序称为自然排序
.forEach(System.out::println);
// 先按年龄排序,然后按姓名排序
empList.stream()
.sorted((x, y) -> {
if(x.getAge().equals(y.getAge())) {
return x.getName().compareTo(y.getName());
}
return x.getAge().compareTo(y.getAge());
})
.forEach(System.out::println);
}
/*
映射
map一接收 Lambda ,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被用到每个元素上,并将其映射成一个新的元素
flatMap一接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流
*/
@Test
public void test05() {
List<String> stringList = Arrays.asList("aaa", "bbb", "ccc");
stringList.stream()
.map((str) -> str.toUpperCase())
.forEach(System.out::println);
System.out.println("---------------------------------");
// 获取员工的名字
empList.stream()
.distinct()
.map(Employee::getName)
.forEach(System.out::println);
System.out.println("---------------------------------");
// map实现将每个字符串转化为字符 复杂
Stream<Stream<Character>> streamStream = stringList.stream()
.map(testStreamApi::filterCharacter);
streamStream.forEach((sm) -> {
sm.forEach(System.out::println);
});
System.out.println("---------------------------------");
// flatMap实现将每个字符串转化为字符 简单
Stream<Character> stream = stringList.stream()
.flatMap(testStreamApi::filterCharacter);
stream.forEach(System.out::println);
}
public static Stream<Character> filterCharacter(String str) {
List<Character> list = new ArrayList<>();
for(Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
/*
筛选与切片
filter-接收 Lambda ,从流中排除某些元素。
limit-截断流,使其元素不超过给定数量。
skip(n) - 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流。与 limit(n) 互补
distinct-筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素
*
*/
@Test
public void test04() {
empList.stream()
.filter((e) -> e.getAge() > 30)
.skip(2)
.distinct() // 这里是根据hashCode和equals,所以employee需要重写hashCode和equals
.forEach(System.out::println);
}
@Test
public void test03() {
empList.stream()
.filter((e) -> e.getAge() > 30)
.limit(2)
.forEach(System.out::println);
}
// 内部迭代:即stream内部帮我们迭代
@Test
public void test01() {
// 中间操作
Stream<Employee> stream = empList.stream()
.filter((e) -> e.getAge() > 30);
// 终止操作:一次性执行全部内容,即“惰性求值”
stream.forEach(System.out::println);
}
// 外部迭代
@Test
public void test02() {
Iterator<Employee> iterator = empList.iterator();
while(iterator.hasNext()) {
Employee employee = iterator.next();
if(employee.getAge() > 30) {
System.out.println(employee);
}
}
}
}
(五)Stream的终止操作
public class testStreamApi2 {
List<Employee> empList = Arrays.asList(
new Employee("张三", 50, 7777.77, Employee.Status.FREE),
new Employee("李四", 35, 8888.6, Employee.Status.BUSY),
new Employee("王五", 20, 999.55, Employee.Status.VOCATION),
new Employee("赵六", 40, 1000.5, Employee.Status.BUSY),
new Employee("赵六", 40, 1000.5, Employee.Status.FREE),
new Employee("赵六", 40, 1000.5, Employee.Status.VOCATION));
/*
收集
collect一将流转换为其他形式。接收一个 Collector接口的实现,用于给Stream中元素做汇总的方法
*/
// 其他
@Test
public void test09() {
DoubleSummaryStatistics ssd = empList.stream()
.collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(ssd.getAverage());
System.out.println(ssd.getMax());
System.out.println(ssd.getMin());
String str = empList.stream()
.map(Employee::getName)
.collect(Collectors.joining(",", "===", "==="));
System.out.println(str);
}
// 分区
@Test
public void test08() {
// 分成true和false两个区
Map<Boolean, List<Employee>> map = empList.stream()
.collect(Collectors.partitioningBy((e) -> e.getSalary() > 5000));
System.out.println(map);
}
// 多级分组
@Test
public void test07() {
Map<Employee.Status, Map<String, List<Employee>>> map = empList.stream()
.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
if (e.getAge() < 30) {
return "青年";
} else if (e.getAge() < 50) {
return "中年";
} else {
return "老年";
}
})));
System.out.println(map);
}
// 分组
@Test
public void test06() {
Map<Employee.Status, List<Employee>> map = empList.stream()
.collect(Collectors.groupingBy(Employee::getStatus));
System.out.println(map);
}
@Test
public void test05() {
Long size = empList.stream()
.collect(Collectors.counting());
System.out.println(size);
Double avg = empList.stream()
.collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avg);
Double sum = empList.stream().collect(Collectors.summingDouble(Employee::getSalary));
System.out.println(sum);
Optional<Double> max = empList.stream()
.map(Employee::getSalary)
.collect(Collectors.maxBy(Double::compareTo));
System.out.println(max.get());
Optional<Employee> min = empList.stream()
.collect(Collectors.minBy((x, y) -> Double.compare(x.getSalary(), y.getSalary())));
System.out.println(min.get());
}
@Test
public void test04() {
List<String> list1 = empList.stream()
.map(Employee::getName)
.collect(Collectors.toList());
list1.forEach(System.out::println);
System.out.println("------------------------");
Set<String> set = empList.stream()
.map(Employee::getName)
.collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("------------------------");
LinkedHashSet<String> hashSet = empList.stream()
.map(Employee::getName)
.collect(Collectors.toCollection(LinkedHashSet::new));
hashSet.forEach(System.out::println);
}
/*
规约
reduce(T identity,BinaryOperator) / reduce(BinaryOperator)
——可以将流中元素反复结合起来,得到一个值。
*/
@Test
public void test03() {
List<Integer> list = Arrays.asList(1, 2, 3);
Integer sum1 = list.stream()
.reduce(1, (x, y) -> x + y);
System.out.println(sum1);
Optional<Double> sum2 = empList.stream()
.map(Employee::getSalary)
.reduce(Double::sum);
System.out.println(sum2.get());
}
/*
查找与匹配
allMatch-检查是否匹配所有元素
anyMatch-检查是否至少匹配一个元素
noneMatch-检查是否没有匹配所有元素
findFirst-返回第一个元素
findAny-返回当前流中的任意元素
count-返回流中元素的总个数
max一返回流中最大值
min-返回流中最小值
*/
@Test
public void test02() {
// 数量
long count = empList.stream()
.count();
System.out.println(count);
// 最大值
Optional<Employee> max = empList.stream()
.max((x, y) -> Double.compare(x.getSalary(), y.getSalary()));
System.out.println(max.get().getSalary());
// 最小值
Optional<Double> min = empList.stream()
.map(Employee::getSalary)
.min(Double::compareTo);
System.out.println(min.get());
}
@Test
public void test01() {
boolean b1 = empList.stream()
.allMatch((e) -> e.getStatus().equals(Employee.Status.FREE));
System.out.println(b1);
boolean b2 = empList.stream()
.anyMatch((e) -> e.getStatus().equals(Employee.Status.FREE));
System.out.println(b2);
boolean b3 = empList.stream()
.noneMatch((e) -> e.getStatus().equals(Employee.Status.FREE));
System.out.println(b3);
// 返回的值有可能为空所以封装到了Optional
Optional<Employee> op1 = empList.stream()
.sorted((x, y) -> Double.compare(x.getSalary(), y.getSalary()))
.findFirst();
System.out.println(op1.get());
Optional<Employee> op2 = empList.stream()
.sorted((x, y) -> Double.compare(x.getSalary(), y.getSalary()))
.findAny();
System.out.println(op2.get());
}
}
案例:
public class testStreamApi3 {
/*
* 1。给定一个数字列表,如何返回一个由每个数的平方构成的列表呢?
给定[1,2,3,4,5],应该返回[1,4,9,16,25]。
*/
@Test
public void test() {
Integer[] num = new Integer[]{1, 2, 3, 4, 5};
Stream<Integer> stream = Arrays.stream(num);
stream.map(x -> x*x).forEach(System.out::println);
}
List<Employee> empList = Arrays.asList(
new Employee("张三", 50, 7777.77),
new Employee("李四", 35, 8888.6),
new Employee("王五", 20, 999.55),
new Employee("赵六", 40, 1000.5),
new Employee("赵六", 40, 1000.5),
new Employee("赵六", 40, 1000.5));
/*
* 如何看流中有多少个employee
* 用map和reduce实现
*/
@Test
public void test2() {
Optional<Integer> sum = empList.stream()
.map(e -> 1)
.reduce(Integer::sum);
System.out.println(sum.get());
}
}
五、综合案例
public interface MyPredicate<T> {
public boolean test(Employee employee);
}
====================================================================
List<Employee> empList = Arrays.asList(
new Employee("张三", 50, 7777.77),
new Employee("李四", 35, 8888.6),
new Employee("王五", 20, 999.55),
new Employee("赵六", 40, 1000.5)
);
// 需求:获取当前公司中员工年龄大于35的员工
@Test
public void test3() {
List<Employee> employees = filterList(empList);
for (Employee employee : employees) {
System.out.println(employee);
}
System.out.println("---------------------------------");
employees = filterListBySalary(empList);
for (Employee employee : employees) {
System.out.println(employee);
}
}
public List<Employee> filterList(List<Employee> empList) {
List<Employee> emps = new ArrayList<>();
for (Employee emp : empList) {
if(emp.getAge() > 35) {
emps.add(emp);
}
}
return emps;
}
// 需求:获取当前公司中员工工资大于4000的员工
public List<Employee> filterListBySalary(List<Employee> empList) {
List<Employee> emps = new ArrayList<>();
for (Employee emp : empList) {
if(emp.getSalary() > 4000) {
emps.add(emp);
}
}
return emps;
}
// 优化方式一:策略设计模式
@Test
public void test4() {
List<Employee> employees
= filterList(empList, new filterEmployeeByAge());
for (Employee employee : employees) {
System.out.println(employee);
}
System.out.println("--------------------------------");
employees
= filterList(empList, new filterEmployeeBySalary());
for (Employee employee : employees) {
System.out.println(employee);
}
}
public List<Employee> filterList(List<Employee> empList, MyPredicate<Employee> pre) {
List<Employee> emps = new ArrayList<>();
for (Employee emp : empList) {
if(pre.test(emp)) {
emps.add(emp);
}
}
return emps;
}
// 优化方式二:匿名内部类
@Test
public void test5() {
List<Employee> emps = filterList(empList, new MyPredicate<Employee>() {
@Override
public boolean test(Employee employee) {
return employee.getSalary() > 4000;
}
});
emps.forEach(System.out::println);
}
// 优化方式三:Lambda表达式
@Test
public void test6() {
List<Employee> employees = filterList(empList, e -> e.getSalary() > 4000);
employees.forEach(System.out::println);
}
// 优化方式四:streamApi
@Test
public void test7() {
empList.stream()
.filter(e -> e.getSalary() > 4000)
.limit(1)
.forEach(System.out::println);
System.out.println("-----------------------");
empList.stream()
.map(Employee::getName)
.forEach(System.out::println);
}
六、新时间日期API
原本的时间相关的类存在线程安全问题
public class testSimpleDateFormat {
public static void main(String[] args) throws ExecutionException, InterruptedException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
return sdf.parse("20230518");
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> results = new ArrayList<>();
for(int i = 0; i < 10; i ++) {
results.add(pool.submit(task));
}
for(Future<Date> future:results) {
System.out.println(future.get());
}
pool.shutdown();
}
}
以前的方式,加锁,这里使用ThreadLocal
public class DateFormatThreadLocal {
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
};
public static Date convert(String source) throws ParseException {
return df.get().parse(source);
}
}
=========================================================================
public class testSimpleDateFormat {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
Callable<Date> task = new Callable<Date>() {
@Override
public Date call() throws Exception {
// return sdf.parse("20230518");
return DateFormatThreadLocal.convert("20230518");
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<Date>> results = new ArrayList<>();
for(int i = 0; i < 10; i ++) {
results.add(pool.submit(task));
}
for(Future<Date> future:results) {
System.out.println(future.get());
}
pool.shutdown();
}
}
jdk1.8的时间类
public class testSimpleDateFormat {
public static void main(String[] args) throws ExecutionException, InterruptedException {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyyMMdd");
Callable<LocalDate> task = new Callable<LocalDate>() {
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("20230518", dtf);
}
};
ExecutorService pool = Executors.newFixedThreadPool(10);
List<Future<LocalDate>> results = new ArrayList<>();
for(int i = 0; i < 10; i ++) {
results.add(pool.submit(task));
}
for(Future<LocalDate> future:results) {
System.out.println(future.get());
}
pool.shutdown();
}
}
(一)使用LocalDate、LocalTime、LocalDateTime
(二)使用Instant时间戳
(三)Duration 和 Period
(四)日期的操纵
(五)解析与格式化
(六)时区的处理
(七)与传统日期处理的转换
public class testLocalDateTime {
// ZonedDate/ZonedTime/ZonedDateTime 时区相关的
@Test
public void test8() {
// 获得的是指定时区的当前时间
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(ldt);
LocalDateTime ldt2 = LocalDateTime.now();
ZonedDateTime zdt = ldt2.atZone(ZoneId.of("Asia/Shanghai"));
// 输出2023-05-18T22:01:45.684+08:00[Asia/Shanghai]
// +08:00 是距离UTC的时间差
System.out.println(zdt);
}
@Test
public void test7() {
// 获取支持的时区
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
}
// DateTimeFormatter : 格式化时间/日期
@Test
public void test6() {
DateTimeFormatter dtf1 = DateTimeFormatter.ISO_DATE;
LocalDateTime ldt1 = LocalDateTime.now();
System.out.println(ldt1.format(dtf1));
System.out.println("-------------------------------");
// 格式化
DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
String time = ldt1.format(dtf2);
System.out.println(time);
// 再格式化回去
LocalDateTime ldt2 = ldt1.parse(time, dtf2);
System.out.println(ldt2);
}
// TemporalAdjuster: 时间矫正器
@Test
public void test5() {
LocalDateTime ldt1 = LocalDateTime.now();
System.out.println(ldt1);
// 直接设置日期为哪一天,不太方便求下一个周几等的操作
LocalDateTime ldt2 = ldt1.withDayOfMonth(10);
System.out.println(ldt2);
// 求下一个星期日
LocalDateTime ldt3 = ldt1.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ldt3);
//自定义:下一个工作日
LocalDateTime ldt5 = ldt1.with((l) -> {
LocalDateTime ldt4 = (LocalDateTime)l;
DayOfWeek dayOfWeek = ldt4.getDayOfWeek();
if(dayOfWeek.equals(DayOfWeek.FRIDAY)) {
return ldt4.plusDays(3);
} else if(dayOfWeek.equals(DayOfWeek.SATURDAY)) {
return ldt4.plusDays(2);
} else {
return ldt4.plusDays(1);
}
});
System.out.println(ldt5);
}
// 3、 Duration: 计算两个“时间”之间的间隔
// Period: 计算两个“日期”之间的间隔
@Test
public void test4() {
LocalDate l1 = LocalDate.of(2022, 5, 17);
LocalDate l2 = LocalDate.now();
Period period = Period.between(l1, l2);
System.out.println(period);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
}
@Test
public void test3() throws InterruptedException {
Instant i1 = Instant.now();
Thread.sleep(1000);
Instant i2 = Instant.now();
System.out.println(Duration.between(i1, i2));
System.out.println("----------------------------");
LocalTime l1 = LocalTime.now();
Thread.sleep(1000);
LocalTime l2 = LocalTime.now();
System.out.println(Duration.between(l1, l2));
}
// 2、Instant :时间戳(以Unix元年:1970年1月1日00:00:00到某个时间之间的毫秒数)
@Test
public void test2() {
Instant i1 = Instant.now(); // 默认获取UTC时区
System.out.println(i1);
// 与中国相差八个时区,可设置偏移
OffsetDateTime time = i1.atOffset(ZoneOffset.ofHours(8));
System.out.println(time);
// 从 1970-现在 的秒数
long second = i1.getEpochSecond();
System.out.println(second);
// 从元年开始计算,这里是+60s
Instant i2 = Instant.ofEpochSecond(60);
System.out.println(i2);
}
// 1、LocalDate LocalTime LocalDateTime(前两个的结合体)
// 一个会用另外两个也差不多了
@Test
public void test1() {
// 返回当前年月日时分秒毫秒
LocalDateTime ldt1 = LocalDateTime.now();
System.out.println(ldt1);
// 构造日期
LocalDateTime ldt2 = LocalDateTime.of(2023, 5, 18, 20, 2, 20);
System.out.println(ldt2);
// 加年数
LocalDateTime ldt3 = ldt1.plusYears(2);
System.out.println(ldt3);
// 减年数
LocalDateTime ldt4 = ldt1.minusYears(2);
System.out.println(ldt4);
// 取详细信息
System.out.println(ldt1.getYear());
System.out.println(ldt1.getMonthValue());
System.out.println(ldt1.getDayOfMonth());
System.out.println(ldt1.getHour());
System.out.println(ldt1.getMinute());
System.out.println(ldt1.getNano());
}
}
七、接口中的默认方法与静态方法
public class MyClass {
public String getName() {
return "father";
}
}
===========================================================================
public interface MyFun {
default String getName() {
return "hahaha";
}
}
===========================================================================
public interface MyInterface {
default String getName() {
return "heiheihei";
}
}
===========================================================================
public class SubClass extends MyClass implements MyFun, MyInterface {
// 两个接口中都有同名函数时,需要实现方法指定执行哪一个接口中的函数
// 当父类中也有同名函数而子类中没有时,默认调用父类函数,忽略接口中的默认函数
}
===========================================================================
public class testDefault {
public static void main(String[] args) {
SubClass subClass = new SubClass();
System.out.println(subClass.getName());
}
}
文章来源:https://www.toymoban.com/news/detail-732966.html
public class SubClass extends MyClass implements MyFun, MyInterface {
// 两个接口中都有同名函数时,需要实现方法指定执行哪一个接口中的函数
// 当父类中也有同名函数而子类中没有时,默认调用父类函数,忽略接口中的默认函数
@Override
public String getName() {
return MyInterface.super.getName();
}
}
文章来源地址https://www.toymoban.com/news/detail-732966.html
public interface MyInterface {
default String getName() {
return "heiheihei";
}
public static void show() {
System.out.println("展示");
}
}
==================================================
public class testDefault {
public static void main(String[] args) {
SubClass subClass = new SubClass();
System.out.println(subClass.getName());
// 调用接口中的静态方法
MyInterface.show();
}
}
八、其他新特性
(一)Optional 类
- Optional.of(T t) : 创建一个 Optional 实例
- Optional.empty() : 创建一个空的 Optional 实例
- Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
- isPresent() : 判断是否包含值
- orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
- orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
- map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional.empty()
- flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
public class testOptional {
/*
Optional 容器类的常用方法:
Optional.of(T t) : 创建一个 Optional 实例
Optional.empty() : 创建一个空的 Optional 实例
Optional.ofNullable(T t):若 t 不为 null,创建 Optional 实例,否则创建空实例
isPresent() : 判断是否包含值
orElse(T t) : 如果调用对象包含值,返回该值,否则返回t
orElseGet(Supplier s) :如果调用对象包含值,返回该值,否则返回 s 获取的值
map(Function f): 如果有值对其处理,并返回处理后的Optional,否则返回 Optional,empty()
flatMap(Function mapper):与 map 类似,要求返回值必须是Optional
*/
// 为什么说它方便了空指针异常的调试,因为这里出现空值会报错NoSuchElementException
@Test
public void test6() {
Optional<Employee> optional = Optional.ofNullable(new Employee("张三", 18, 50000.0, Employee.Status.BUSY));
// Optional<String> name = optional.map((e) -> optional.get().getName());
// System.out.println(name.get());
Optional<String> name = optional.flatMap(e -> Optional.of(e.getName()));
System.out.println(name.get());
}
@Test
public void test5() {
Optional<Employee> optional = Optional.ofNullable(null);
// 如果optional为空,那么返回传进去的默认参数,否则返回optional的参数
Employee employee1 = optional.orElse(new Employee());
System.out.println(employee1);
// 使用供给型函数式接口,如果optional为空,那么返回传进去的默认参数,否则返回optional的参数
Employee employee2 = optional.orElseGet(Employee::new);
System.out.println(employee2);
}
@Test
public void test4() {
Optional<Employee> optional = Optional.ofNullable(null);
// System.out.println(optional.get()); // 报错NoSuchElementException
// 安全的做法,判断是否包含值
if(optional.isPresent()) {
System.out.println(optional.get());
}
}
@Test
public void test3() {
Optional<Employee> optional = Optional.empty();
System.out.println(optional.get()); // 报错NoSuchElementException
}
@Test
public void test2() {
Optional<Employee> optional = Optional.of(null); // 报错NullPointerException
}
@Test
public void test1() {
Optional<Employee> optional = Optional.of(new Employee());
System.out.println(optional.get());
}
}
(二)重复注解与类型注解
@Repeatable(MyAnnotaions.class) // 指明容器类
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, TYPE_PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotaion {
String value() default "atguigu";
}
===============================================================================
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotaions {
MyAnnotaion[] value();
}
===============================================================================
/*
* 重复注解与类型注解
*/
public class TestAnnotaion {
@Test
public void test1() throws Exception {
Class<TestAnnotaion> aClass = TestAnnotaion.class;
Method method =
aClass.getMethod("show");
MyAnnotaion[] annotations = method.getAnnotationsByType(MyAnnotaion.class);
for(MyAnnotaion mya: annotations) {
System.out.println(mya);
}
}
@MyAnnotaion("world")
@MyAnnotaion("hello")
public void show(@MyAnnotaion("abc") String abs) {
}
}
到了这里,关于Java——JDK1.8新特性的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!