Java——JDK1.8新特性
短信预约 -IT技能 免费直播动态提醒
目录
(一)使用LocalDate、LocalTime、LocalDateTime
一、Lambda 表达式
Lambda 是一个 匿名函数 ,我们可以把 Lambda表达式理解为是 一段可以传递的代码 (将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。 案例:从匿名内部类---》Lambda表达式 // 原来的匿名内部类 @Test public void test1() { Comparator com = new Comparator() { @Override public int compare(Integer o1, Integer o2) { return Integer.compare(o1, o2); } }; TreeSet ts = new TreeSet<>(com); } // Lambda表达式 @Test public void test2() { Comparator com = (o1, o2) -> Integer.compare(o1, o2); TreeSet ts = new TreeSet<>(com); }
(一)Lambda 表达式语法
Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为 “ -> ” , 该操作符被称为 Lambda 操作符或剪头操作符。它将 Lambda 分为两个部分:- 左侧:指定了 Lambda 表达式需要的所有参数
- 右侧:指定了 Lambda 体,即 Lambda 表达式要执行的功能。
语法格式一:无参,无返回值,Lambda体只需一条语句
语法格式二:Lambda需要一个参数
语法格式三:Lambda只需要一个参数时,参数的小括号可以省略
语法格式四:Lambda需要两个参数,并且有返回值
语法格式五:当 Lambda 体只有一条语句时,return 与大括号可以省略
(二)类型推断
上述 Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的 “类型推断“二、函数式接口
只包含一个抽象方法的接口,称为 函数式接口 。- 你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。
- 我们可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。
(一)自定义函数式接口
(二)作为参数传递Lambda 表达式
作为参数传递 Lambda 表达式:为了将 Lambda 表达式作为参数传递,接 收Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口 的类型。(三)Java 内置四大核心函数式接口
其他子接口(参数个数)
public class TestLambda02 { @Test public void test04() { List stringList = Arrays.asList("hello", "world","you"); List list = getStringList(stringList, (s) -> s.length() > 3); list.forEach(System.out::println); } public List getStringList(List stringList, Predicate pre) { List strings = new ArrayList<>(); for (String s : stringList) { if(pre.test(s)) { strings.add(s); } } return strings; } @Test public void test03() { String string = getString("\t\t\t 帅哥好帅", (str) -> str.trim()); System.out.println(string); } public String getString(String str, Function func) { return func.apply(str); } @Test public void test02() { int num = 10; generator(num, () -> (int)(Math.random() * 100) + 1); } public void generator(int x, Supplier sup) { List integerList = new ArrayList<>(); for(int i = 0; i < x; i ++) { Integer integer = sup.get(); integerList.add(integer); } integerList.forEach(System.out::println); } @Test public void test01() { int num = 100; consumer(num, x -> System.out.println("消费了" + num + "元")); } public void consumer(int num, Consumer com) { com.accept(num); }}
三、方法引用
当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用! ( 实现抽象方法的参数列表,必须与方法引用方法的参数列表保持一致! ) 方法引用:使用操作符 “ :: ” 将方法名和对象或类的名字分隔开来。 如下三种主要使用情况 :- 对象::实例方法
- 类::静态方法
- 类::实例方法
public class TestMethodRef { // 数组引用 @Test public void test05() { Function func = (x) -> new String[x]; String[] strings = func.apply(10); System.out.println(strings.length); Function func2 = String[]::new; String[] strs = func2.apply(20); System.out.println(strs.length); } // 构造器引用 @Test public void test04() { Supplier sup = () -> new Employee(); // 构造器引用的方式 Supplier sup2 = Employee::new; Employee employee = sup2.get(); System.out.println(employee); Function func = Employee::new; Employee employee1 = func.apply(20); System.out.println(employee1); } // 类::实例方法名 @Test public void tes03() { // 规则:若Lambda参数列表中的第一参数是实例方法的调用者,第二参数是实例方法的参数时,此时 // 可以通过 class::method BiPredicate bp = (x, y) -> x.equals(y); BiPredicate bp1 = String::equals; } // 对象::静态方法 @Test public void test02() { Comparator com = (x, y) -> Integer.compare(x, y); Comparator com1 = Integer::compare; } // 对象::实例方法 @Test public void test01() { PrintStream ps = System.out; Consumer con = (x) -> System.out.println(x); Consumer con2 = ps::println; }}
四、Stream API
Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API(java.util.stream.*) 。 Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。 使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。(一)什么是Stream?
流(Stream) 到底是什么呢? 是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。 “集合讲的是数据,流讲的是计算!” 注意: ①Stream 自己不会存储元素。 ②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。 ③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。(二)Stream 的操作三个步骤
- 创建 Stream
- 中间操作
- 终止操作(终端操作)
(三)创建流的四种方式
方式一:Collection接口
Java8 中的 Collection 接口被扩展,提供了 两个获取流的方法 : ⚫ default Stream方式二:数组创建流
Java8 中的 Arrays 的静态方法 stream() 可 以获取数组流: ⚫ staticpublic class testStream { // 创建stream @Test public void test1() { //1.可以通过Collection 系列集合提供的stream() or parallelStream() List list = new ArrayList<>(); Stream stream1 = list.stream(); //2. 通过Arrays的静态方法stream()获取数组流 Employee[] emps = new Employee[2]; Stream stream2 = Arrays.stream(emps); //3. 通过stream的静态方法of() Stream stream3 = Stream.of(1, 2, 3); //4. 创建无限流 // 迭代 Stream stream4 = Stream.iterate(0, (x) -> x + 2); stream4.limit(10).forEach(System.out::println); // 生成 Stream stream5 = Stream.generate(Math::random); stream5.limit(10).forEach(System.out::println); }}
(四)Stream的中间操作
多个 中间操作 可以连接起来形成一个 流水线 ,除非流水线上触发终止操作,否则 中间操作不会执行任何的处理 !而在 终止操作时一次性全部处理,称为“惰性求值” 。 筛选与切片映射
排序
public class testStreamApi { List 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)); // 中间操作 @Test public void test06() { List 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); } @Test public void test05() { List 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> streamStream = stringList.stream() .map(testStreamApi::filterCharacter); streamStream.forEach((sm) -> { sm.forEach(System.out::println); }); System.out.println("---------------------------------"); // flatMap实现将每个字符串转化为字符 简单 Stream stream = stringList.stream() .flatMap(testStreamApi::filterCharacter); stream.forEach(System.out::println); } public static Stream filterCharacter(String str) { List list = new ArrayList<>(); for(Character ch : str.toCharArray()) { list.add(ch); } return list.stream(); } @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 stream = empList.stream() .filter((e) -> e.getAge() > 30); // 终止操作:一次性执行全部内容,即“惰性求值” stream.forEach(System.out::println); } // 外部迭代 @Test public void test02() { Iterator iterator = empList.iterator(); while(iterator.hasNext()) { Employee employee = iterator.next(); if(employee.getAge() > 30) { System.out.println(employee); } } }}
(五)Stream的终止操作
Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到 List、Set、Map)。但是 Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:public class testStreamApi2 { List 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)); // 其他 @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> map = empList.stream() .collect(Collectors.partitioningBy((e) -> e.getSalary() > 5000)); System.out.println(map); } // 多级分组 @Test public void test07() { Map>> 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> 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 max = empList.stream() .map(Employee::getSalary) .collect(Collectors.maxBy(Double::compareTo)); System.out.println(max.get()); Optional min = empList.stream() .collect(Collectors.minBy((x, y) -> Double.compare(x.getSalary(), y.getSalary()))); System.out.println(min.get()); } @Test public void test04() { List list1 = empList.stream() .map(Employee::getName) .collect(Collectors.toList()); list1.forEach(System.out::println); System.out.println("------------------------"); Set set = empList.stream() .map(Employee::getName) .collect(Collectors.toSet()); set.forEach(System.out::println); System.out.println("------------------------"); LinkedHashSet hashSet = empList.stream() .map(Employee::getName) .collect(Collectors.toCollection(LinkedHashSet::new)); hashSet.forEach(System.out::println); } @Test public void test03() { List list = Arrays.asList(1, 2, 3); Integer sum1 = list.stream() .reduce(1, (x, y) -> x + y); System.out.println(sum1); Optional sum2 = empList.stream() .map(Employee::getSalary) .reduce(Double::sum); System.out.println(sum2.get()); } @Test public void test02() { // 数量 long count = empList.stream() .count(); System.out.println(count); // 最大值 Optional max = empList.stream() .max((x, y) -> Double.compare(x.getSalary(), y.getSalary())); System.out.println(max.get().getSalary()); // 最小值 Optional 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 op1 = empList.stream() .sorted((x, y) -> Double.compare(x.getSalary(), y.getSalary())) .findFirst(); System.out.println(op1.get()); Optional op2 = empList.stream() .sorted((x, y) -> Double.compare(x.getSalary(), y.getSalary())) .findAny(); System.out.println(op2.get()); }}
案例:
public class testStreamApi3 { @Test public void test() { Integer[] num = new Integer[]{1, 2, 3, 4, 5}; Stream stream = Arrays.stream(num); stream.map(x -> x*x).forEach(System.out::println); } List 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)); @Test public void test2() { Optional sum = empList.stream() .map(e -> 1) .reduce(Integer::sum); System.out.println(sum.get()); }}
五、综合案例
public interface MyPredicate { public boolean test(Employee employee);}==================================================================== List 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 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 filterList(List empList) { List emps = new ArrayList<>(); for (Employee emp : empList) { if(emp.getAge() > 35) { emps.add(emp); } } return emps; } // 需求:获取当前公司中员工工资大于4000的员工 public List filterListBySalary(List empList) { List emps = new ArrayList<>(); for (Employee emp : empList) { if(emp.getSalary() > 4000) { emps.add(emp); } } return emps; } // 优化方式一:策略设计模式 @Test public void test4() { List 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 filterList(List empList, MyPredicate pre) { List emps = new ArrayList<>(); for (Employee emp : empList) { if(pre.test(emp)) { emps.add(emp); } } return emps; } // 优化方式二:匿名内部类 @Test public void test5() { List emps = filterList(empList, new MyPredicate() { @Override public boolean test(Employee employee) { return employee.getSalary() > 4000; } }); emps.forEach(System.out::println); } // 优化方式三:Lambda表达式 @Test public void test6() { List 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 task = new Callable() { @Override public Date call() throws Exception { return sdf.parse("20230518"); } }; ExecutorService pool = Executors.newFixedThreadPool(10); List> results = new ArrayList<>(); for(int i = 0; i < 10; i ++) { results.add(pool.submit(task)); } for(Future future:results) { System.out.println(future.get()); } pool.shutdown(); }}
以前的方式,加锁,这里使用ThreadLocal
public class DateFormatThreadLocal { private static final ThreadLocal df = new ThreadLocal(){ 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 task = new Callable() { @Override public Date call() throws Exception {// return sdf.parse("20230518"); return DateFormatThreadLocal.convert("20230518"); } }; ExecutorService pool = Executors.newFixedThreadPool(10); List> results = new ArrayList<>(); for(int i = 0; i < 10; i ++) { results.add(pool.submit(task)); } for(Future 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 task = new Callable() { @Override public LocalDate call() throws Exception { return LocalDate.parse("20230518", dtf); } }; ExecutorService pool = Executors.newFixedThreadPool(10); List> results = new ArrayList<>(); for(int i = 0; i < 10; i ++) { results.add(pool.submit(task)); } for(Future future:results) { System.out.println(future.get()); } pool.shutdown(); }}
(一)使用LocalDate、LocalTime、LocalDateTime
LocalDate 、 LocalTime 、 LocalDateTime 类的实例是 不可变的对象 ,分别表示使用 ISO-8601 日 历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。(二)使用Instant时间戳
用于“时间戳”的运算。它是以 Unix 元年 ( 传统的设定为UTC 时区 1970 年 1 月 1 日午夜时分 ) 开始所经历的描述进行运算(三)Duration 和 Period
Duration: 用于计算两个“时间”间隔 Period: 用于计算两个“日期”间隔(四)日期的操纵
TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下个周日”等操作。 TemporalAdjuster s : 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现。(五)解析与格式化
java.time.format.DateTimeFormatter 类:该类提供了三种 格式化方法: ⚫ 预定义的标准格式 ⚫ 语言环境相关的格式 ⚫ 自定义的格式(六)时区的处理
Java8 中加入了对时区的支持,带时区的时间为分别为: ZonedDate 、 ZonedTime 、 ZonedDateTime 其中每个时区都对应着 ID ,地区 ID 都为 “{区域 }/{ 城市 } ”的格式 例如 : Asia/Shanghai 等 ZoneId :该类中包含了所有的时区信息 getAvailableZoneIds() : 可以获取所有时区时区信息 of(id) : 用指定的时区信息获取 ZoneId 对象(七)与传统日期处理的转换
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 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()); }}
七、接口中的默认方法与静态方法
Java 8中允许接口中包含具有具体实现的方法,该方法称为“默认方法” ,默认方法使用 default 关键字修饰。 接口默认方法的”类优先”原则 若一个接口中定义了一个默认方法,而另外一个父类或接口中 又定义了一个同名的方法时 ⚫ 选择父类中的方法。如果一个父类提供了具体的实现,那么 接口中具有相同名称和参数的默认方法会被忽略。 ⚫ 接口冲突。如果一个父接口提供一个默认方法,而另一个接 口也提供了一个具有相同名称和参数列表的方法(不管方法 是否是默认方法),那么必须覆盖该方法来解决冲突 Java8 中,接口中允许添加静态方法。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()); }}
public class SubClass extends MyClass implements MyFun, MyInterface { // 两个接口中都有同名函数时,需要实现方法指定执行哪一个接口中的函数// 当父类中也有同名函数而子类中没有时,默认调用父类函数,忽略接口中的默认函数 @Override public String getName() { return MyInterface.super.getName(); }}
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- 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 { // 为什么说它方便了空指针异常的调试,因为这里出现空值会报错NoSuchElementException @Test public void test6() { Optional optional = Optional.ofNullable(new Employee("张三", 18, 50000.0, Employee.Status.BUSY));// Optional name = optional.map((e) -> optional.get().getName());// System.out.println(name.get()); Optional name = optional.flatMap(e -> Optional.of(e.getName())); System.out.println(name.get()); } @Test public void test5() { Optional 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 optional = Optional.ofNullable(null);// System.out.println(optional.get()); // 报错NoSuchElementException // 安全的做法,判断是否包含值 if(optional.isPresent()) { System.out.println(optional.get()); } } @Test public void test3() { Optional optional = Optional.empty(); System.out.println(optional.get()); // 报错NoSuchElementException } @Test public void test2() { Optional optional = Optional.of(null); // 报错NullPointerException } @Test public void test1() { Optional optional = Optional.of(new Employee()); System.out.println(optional.get()); }}
(二)重复注解与类型注解
Java 8对注解处理提供了两点改进:可重复的注解及可用于类型的注解。@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 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) { }}
来源地址:https://blog.csdn.net/m0_62946761/article/details/130753016
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341