目录
JDK8新特性–接口–default关键字和静态方法
-
在jdk1.8以前接口里面是只能有抽象方法,不能有任何方法的实现的
-
jdk1.8里面打破了这个规定,引⼊了新的关键字default,使用default修饰⽅法,可以在接口里面定义具体的⽅法实现
-
默认方法:接口里面定义⼀个默认⽅法,这个接口的实现类实现了这个接口之后,不用管这个default修饰的方法就可以直接调用,即接口方法的默认实现
-
静态方法: 接口名.静态方法来访问接口中的静态方法
public interface Animal { void run(); void eat(); default void breath() { System.out.println("使⽤氧⽓呼吸"); } static void test() { System.out.println("这是静态⽅法"); } }
JDK8新特性–新增base64加解密API
-
Jdk1.8的java.util包中,新增了Base64的类
public static void main(String[] args) { Base64.Decoder decoder = Base64.getDecoder(); Base64.Encoder encoder = Base64.getEncoder(); String text = "1234567890"; byte[] textByte = text.getBytes("UTF-8"); //编码 String encodedText = encoder.encodeToString(textByte); System.out.println(encodedText); //解码 System.out.println(new String(decoder.decode(encodedText), "UTF-8")); }
JDK8新特性–时间日期处理类
-
时间处理再熟悉不过,SimpleDateFormat,Calendar等类旧版缺点:java.util.Date是非线程安全的API设计比较差,日期/时间对象⽐较,加减麻烦
-
Java 8通过发布新的Date-Time API (JSR 310)来进⼀步加强对日期与时间的处理
-
新增了很多常见的api,如⽇期/时间的比较,加减,格式化等
-
包所在位置 java.time
-
核心类
LocalDate:不包含具体时间的日期。 LocalTime:不含日期的时间。 LocalDateTime:包含了日期及时间。
-
LocalDate 常用API
LocalDate today = LocalDate.now(); System.out.println("今天⽇期:" + today); //获取年,⽉,⽇,周⼏ System.out.println("现在是哪年:" + today.getYear()); System.out.println("现在是哪⽉:" + today.getMonth()); System.out.println("现在是哪⽉(数字):" + today.getMonthValue()); System.out.println("现在是⼏号:" + today.getDayOfMonth()); System.out.println("现在是周⼏:" + today.getDayOfWeek()); //加减年份, 加后返回的对象才是修改后的,旧的依旧是旧的 LocalDate changeDate = today.plusYears(1); System.out.println("加后是哪年:" + changeDate.getYear()); System.out.println("旧的是哪年:" + today.getYear()); //⽇期⽐较 System.out.println("isAfter: " + changeDate.isAfter(today));
getYear() int 获取当前日期的年份 getMonth() Month 获取当前日期的⽉份对象 getMonthValue() int 获取当前日期是第⼏⽉ getDayOfWeek() DayOfWeek 表示该对象表示的日期是星期⼏ getDayOfMonth() int 表示该对象表示的日期是这个⽉第⼏天 getDayOfYear() int 表示该对象表示的日期是今年第⼏天 withYear(int year) LocalDate 修改当前对象的年份 withMonth(int month) LocalDate 修改当前对象的⽉份 withDayOfMonth(int dayOfMonth) LocalDate 修改当前对象在当⽉的日期 plusYears(long yearsToAdd) LocalDate 当前对象增加指定的年份数 plusMonths(long monthsToAdd) LocalDate 当前对象增加指定的⽉份数 plusWeeks(long weeksToAdd) LocalDate 当前对象增加指定的周数 plusDays(long daysToAdd) LocalDate 当前对象增加指定的天数 minusYears(long yearsToSubtract) LocalDate 当前对象减去指定的年数 minusMonths(long monthsToSubtract) LocalDate 当前对象减去注定的⽉数 minusWeeks(long weeksToSubtract) LocalDate 当前对象减去指定的周数 minusDays(long daysToSubtract) LocalDate 当前对象减去指定的天数 compareTo(ChronoLocalDate other) int ⽐较当前对象和other对象在时间上的⼤⼩,返回值如果为正,则当前对象时间较晚, isBefore(ChronoLocalDate other) boolean ⽐较当前对象日期是否在other对象日期之前 isAfter(ChronoLocalDate other) boolean ⽐较当前对象日期是否在other对象日期之后 isEqual(ChronoLocalDate other) boolean ⽐较两个日期对象是否相等
-
LocalTime 常用API
-
LocalDateTime 常用API
-
-
日期时间格式化
-
JDK8之前:SimpleDateFormat来进行格式化,但SimpleDateFormat并不是线程安全的
-
JDK8之后:引⼊线程安全的日期与时间DateTimeFormatter
LocalDateTime ldt = LocalDateTime.now(); System.out.println(ldt); DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm: ss "); String ldtStr = dtf.format(ldt); System.out.println(ldtStr);
-
获取指定的日期时间对象
LocalDateTime ldt = LocalDateTime.of(2023, 11, 11, 8, 20, 30); System.out.println(ldt);
-
计算日期时间差 java.time.Duration
LocalDateTime today = LocalDateTime.now(); System.out.println(today); LocalDateTime changeDate = LocalDateTime.of(2020,10,1,10,40,30); System.out.println(changeDate); Duration duration = Duration.between( today,changeDate);//第⼆个参数减第⼀个参数 System.out.println(duration.toDays());//两个时间差的天数 System.out.println(duration.toHours());//两个时间差的⼩时数 System.out.println(duration.toMinutes());//两个时间差的分钟数 System.out.println(duration.toMillis());//两个时间差的毫秒数 System.out.println(duration.toNanos());//两个时间差的纳秒数
-
JDK8新特性–Optional类
-
Optional 类有啥⽤
- 主要解决的问题是空指针异常(NullPointerException)
- 怎么解决?
- 本质是⼀个包含有可选值的包装类,这意味着 Optional 类既可以含有对象也可以为空
-
创建Optional类
- of()
- null 值作为参数传递进去,则会抛异常
Optional<Student> opt = Optional.of(user);
- null 值作为参数传递进去,则会抛异常
- ofNullable()
- 如果对象即可能是 null 也可能是非null,应该使用 ofNullable() ⽅法
Optional<Student> opt = Optional.ofNullable(user);
- 如果对象即可能是 null 也可能是非null,应该使用 ofNullable() ⽅法
- of()
-
访问 Optional 对象的值
- get() ⽅法
Optional<Student> opt = Optional.ofNullable(student); Student s = opt.get();
- 如果值存在则isPresent()⽅法会返回true,调用get()方法会返回该对象⼀般使用get之前需要 先验证是否有值,不然还会报错
public static void main(String[] args) { Student student = null; test(student); } public static void test(Student student) { Optional<Student> opt = Optional.ofNullable(student); System.out.println(opt.isPresent()); }
- get() ⽅法
-
兜底 orElse方法
- orElse()如果有值则返回该值,否则返回传递给它的参数值
Student student1 = null; Student student2 = new Student(2); Student result = Optional.ofNullable(student1).orElse(student2); System.out.println(result.getAge()); Student student = null; int result = Optional.ofNullable(student).map(obj->obj.getAge()).orElse(4); System.out.println(result);
- orElse()如果有值则返回该值,否则返回传递给它的参数值
JDK8新特性–lambda表达式
lambda表达式 使用场景(前提):⼀个接口中只包含⼀个方法,则可以使用Lambda表达式,这样的接口称之为“函数接口” 语法: (params) -> expression
- 第⼀部分为括号内用逗号分隔的形式参数,参数是函数式接口里面方法的参数;
- 第⼆部分为⼀个箭头符号:->;
- 第三部分为方法体,可以是表达式和代码块
参数列表 :
- 括号中参数列表的数据类型可以省略不写
- 括号中的参数只有⼀个,那么参数类型和()都可以省略不写
方法体:
- 如果{}中的代码只有一行,无论有返回值,可以省略{},return,分号,要⼀起省略,其他则需要加上
JDK8新特性–函数式接口
- Lambda表达式必须先定义接⼝,创建相关方法之后才可使用,这样做十分不便,其实java8已经内置了许多接口,
例如下面四个功能型接口,所以⼀般很少会由⽤户去定义新的函数式接口 - Java8的最⼤特性就是函数式接口,所有标注了@FunctionalInterface注解的接口都是函数式接口
Java8 内置的四⼤核⼼函数式接⼝ Consumer<T> : 消费型接⼝:有⼊参,⽆返回值 void accept(T t); Supplier<T> : 供给型接⼝:⽆⼊参,有返回值 T get(); Function<T, R> : 函数型接⼝:有⼊参,有返回值 R apply(T t); Predicate<T> : 断⾔型接⼝:有⼊参,有返回值,返回值类型确定是boolean boolean test(T t);
Function
- 传入⼀个值经过函数的计算返回另⼀个值
- T:入参类型,R:出参类型
- 调用方法:R apply(T t)
// 输出⼊参的10倍 Function<Integer, Integer> func = p -> p * 100; func.apply(100);
BiFunction
-
Function只能接收⼀个参数,如果要传递两个参数,则⽤ BiFunction
public static void main(String[] args) { System.out.println(operator(10, 21, (a, b) -> a + b)); System.out.println(operator(10, 2, (a, b) -> a - b)); System.out.println(operator(8, 4, (a, b) -> a * b)); System.out.println(operator(10, 2, (a, b) -> a / b)); } public static Integer operator(Integer a, Integer b, BiFunction<Integer, Integer, Integer> bf) { return bf.apply(a, b); }
Consumer
- Consumer 消费型接口:有入参,无返回值
- 将 T 作为输入,不返回任何内容
- 调用方法:void accept(T t);
public static void main(String[] args) throws Exception { Consumer<String> consumer = obj -> { System.out.println(obj); System.out.println("调⽤短信接⼝发送短信,或者打印⽇志"); }; // sendMsg("8888888", obj -> { // System.out.println(obj); // System.out.println("调⽤短信接⼝发送短信,或者打印⽇志"); // // }); sendMsg("8888888", consumer); } public static void sendMsg(String phone, Consumer<String> consumer) { consumer.accept(phone); }
Supplier
- Supplier: 供给型接口:无入参,有返回值
- T:出参类型;没有入参
- 调用方法:T get();
public static void main(String[] args) { //Student student = new Student(); Student student = newStudent(); System.out.println(student.getName()); } public static Student newStudent() { Supplier<Student> supplier = () -> { Student student = new Student(); student.setName("默认名称"); return student; }; return supplier.get(); } class Student{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
Predicate
- Predicate: 断⾔型接口:有⼊参,有返回值,返回值类型确定是boolean
- T:入参类型;出参类型是Boolean
- 调用方法:boolean test(T t);
public static void main(String[] args) { List<String> list = Arrays.asList("awewrwe", "vdssdsd", "aoooo", "psdddsd"); List<String> results = filter(list, obj -> obj.startsWith("a")); System.out.println(results); } public static List<String> filter(List<String> list, Predicate<String> predicate) { List<String> results = new ArrayList<>(); for (String str : list) { if (predicate.test(str)) { results.add(str); } } return results; }
JDK8新特性–方法与构造函数引用
- 以前方法调用
对象.方法名
或者类名.方法名
- jdk1.8提供了另外⼀种调用方式
::
说明:⽅法引⽤是⼀种更简洁易懂的lambda表达式,操作符是双冒号::,⽤来直接访问类或者实例 已经存在的⽅法或构造⽅法 通过⽅法引⽤,可以将⽅法的引⽤赋值给⼀个变量 语法:左边是容器(可以是类名,实例名),中间是" :: ",右边是相应的⽅法名 静态⽅法,则是ClassName::methodName。如 Object ::equals 实例⽅法,则是Instance::methodName 构造函数,则是 类名::new; 单个参数 Function<⼊参1, 返回类型> func = ⽅法引⽤ 应⽤ func.apply(⼊参); 2个参数 BiFunction<⼊参1,⼊参2, 返回类型> func = ⽅法引⽤ 应⽤ func.apply(⼊参1,⼊参2);
public static void main(String[] args) { // 使⽤双冒号::来构造静态函数引⽤ Function<String, Integer> fun = Integer::parseInt; Integer value = fun.apply("1024"); System.out.println(value); // 使⽤双冒号::来构造⾮静态函数引⽤ String content = "abcedfg"; Function<Integer, String> func = content::substring; String result = func.apply(1); System.out.println(result); // 构造函数引⽤,多个参数 BiFunction<String, Integer, User> biFunction = User::new; User user1 = biFunction.apply("小王", 28); System.out.println(user1.toString()); //构造函数引⽤,单个参数 Function<String, User> function = User::new; User user2 = function.apply("小王"); System.out.println(user2.toString()); // 函数引⽤也是⼀种函数式接⼝,可以将函数引⽤作为⽅法的参数 sayHello(String::toUpperCase, "www.baidu.com"); } /** * @param func 函数引⽤ * @param param 对应的参数 */ private static void sayHello(Function<String, String> func, String param) { String result = func.apply(param); System.out.println(result); } class User { private String username; private Integer age; public User() {} public User(String username) { this.username = username; } public User(String username, Integer age) { this.username = username; this.age = age; } }
JDK8新特性–Stream
- 什么是stream
- Stream 中文称为 “流”,通过将集合转换为这么⼀种叫做 “流”的元素队列,通过声明性方式,能够对集合中的每个元素进行⼀系列并行或串行的流水线操作
- 元素是特定类型的对象,所以元素集合看作⼀种流, 流在管道中传输, 且可以在管道的节点上进行处理, 比如 排序,聚合,过滤等操作
- 操作详情
- 数据元素便是原始集合,如List、Set、Map等
- 生成流,可以是串行流stream() 或者并行流 parallelStream()
- 中间操作,可以是 排序,聚合,过滤,转换等
- 终端操作,很多流操作本身就会返回⼀个流,所以多个操作可以直接连接起来,最后统⼀进行收集
map
-
将流中的每⼀个元素 T 映射为 R(类似类型转换)
// 案例一 List<String> list = Arrays.asList("springboot教程", "微服务教程", "并发编程", " 压⼒测试", " 架构课程"); List<String> resultList = list.stream().map(obj -> "0到100自学:" + obj).collect(Collectors.toList()); System.out.println(resultList); // 案例二 List<User> list = Arrays.asList(new User(1, "⼩东", "123"), new User(21, "jack", "rawer"), new User(155, "tom", "sadfsdfsdfsd"), new User(231, "marry", "234324"), new User(100, "⼩D", "122223")); List<UserDTO> userDTOList = list.stream().map(obj -> { UserDTO userDTO = new UserDTO(obj.getId(), obj.getName()); return userDTO; }).collect(Collectors.toList()); System.out.println(userDTOList);
filter
-
用于通过设置的条件过滤出元素,筛选过滤出符合条件的元素 需求:过滤出字符串长度大于5的字符串
List<String> list = Arrays.asList("springboot", "springcloud", "redis", "git", "netty", "java", "html", "docker"); List<String> resultList = list.stream().filter(obj -> obj.length() > 5).collect(Collectors.toList()); System.out.println(resultList);
sorted
- sorted() 对流进行自然排序, 其中的元素必须实现Comparable接口
List<String> list = Arrays.asList("springboot", "springcloud", "redis", "git", "netty", "java", "html", "docker"); List<String> resultList = list.stream().sorted().collect(Collectors.toList());
- sorted(Comparator<? super T> comparator) 用来自定义升降序
List<String> list = Arrays.asList("springboot", "springcloud", "redis", "git", "netty", "java", "html", "docker"); //根据⻓度进⾏排序 //方式一 List<String> resultList = list.stream().sorted(Comparator.comparing(obj -> obj.length())).collect(Collectors.toList()); //方式二 List<String> resultList = list.stream().sorted(Comparator.comparing(obj -> obj.length(), Comparator.reverseOrder())).collect(Collectors.toList()); //方式三 List<String> resultList = list.stream().sorted(Comparator.comparing(String::length).reversed()).collect(Collectors.toList()); System.out.println(resultList);
limit
- 截断流使其最多只包含指定数量的元素
List<String> list = Arrays.asList("springboot", "springcloud", "redis", "git", "netty", "java", "html", "docker"); //limit截取 List<String> resultList = list.stream().sorted(Comparator.comparing(String::length).reversed()) .limit(3).collect(Collectors.toList()); System.out.println(resultList);