登录
注册
开源
企业版
高校版
搜索
帮助中心
使用条款
关于我们
开源
企业版
高校版
私有云
模力方舟
AI 队友
登录
注册
代码拉取完成,页面将自动刷新
捐赠
捐赠前请先登录
取消
前往登录
扫描微信二维码支付
取消
支付完成
支付提示
将跳转至支付宝完成支付
确定
取消
Watch
不关注
关注所有动态
仅关注版本发行动态
关注但不提醒动态
24
Star
56
Fork
2
Java技术交流
/
Java技术提升库
代码
Issues
56
Pull Requests
0
Wiki
统计
流水线
服务
JavaDoc
PHPDoc
质量分析
Jenkins for Gitee
腾讯云托管
腾讯云 Serverless
悬镜安全
阿里云 SAE
Codeblitz
SBOM
我知道了,不再自动展开
更新失败,请稍后重试!
移除标识
内容风险标识
本任务被
标识为内容中包含有代码安全 Bug 、隐私泄露等敏感信息,仓库外成员不可访问
011、Java8、9新特性
待办的
#I1VX9P
高强
创建于
2020-09-19 22:09
### 考点分析! Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。 Java 9 发布于 2017 年 9 月 22 日,带来了很多新特性,其中最主要的变化是已经实现的模块化系统。接下来我们会详细介绍 Java 9 的新特性。 ### 典型回答! 1、Java8新特性: ① 引入了lambda表达式,可以简化匿名内部类的代码,允许将方法作为参数。 ② 方法引用,可以进一步简化lambda表达式的书写,可以引用类的构造方法,静态方法,特定类的方法和某个对象的方法。 ③ 可以在接口中使用default定义默认方法和静态方法,引入默认方法方便了接口升级的维护,之前如果在接口中新增一个方法必须修改所有实现类。 ④ 引入了stream类,支持链式编程,为集合类和数组提供了一些方便的操作方法,例如filter、skip、limit和map、concat等。 ⑤ 可以通过类型自动推测泛型参数。 ⑥ 允许重复使用注解,扩大了注解的使用范围,可以用在局部变量和泛型,方法异常上。 ⑦ 引入了Optional类解决空指针异常,更新了日期类的API等。 2、Java9新特性: ① Shell工具:相当于cmd工具,你可以和cmd一样,进入工具后可以做一些简单的java操作。 ② 模块化:某一个模块运行的时候,jvm只会启动和它有依赖的模块,并不会加载所有的模块到内存中,这样性能大大的提高了。 ③ 多版本兼容Jar包:可以兼容不同版本的jar包。 ④ 接口Interface的升级:支持私有方法 ⑤ 钻石操作符的升级 ⑥ 异常处理try升级 ⑦ 特殊标识符增加限制 ⑧ String底层存储结构更换 ⑨ Stream API 新方法的添加 Java9所有特性都是为了提高性能和内存。 ### 后续扩展! 1、Java8 新增了非常多的特性,我们主要讨论以下几个: Lambda 表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。 ``` public void test3(){ List<Student> list = Arrays.asList( new Student("九天","男",5000,18,"天秤座"), new Student("十夜","男",4000,16,"双鱼座"), new Student("十一郎","男",3000,24,"水瓶座") ); //Lambda表达式 List<Student> result = filterStudent(list,(e)->e.getStar().equals("天秤座")); System.out.println(result); } ``` 测试结果: ``` [Student(name=九天, sex=男, salary=5000, age=18, star=天秤座)] ``` 但是现在又会有人会问这个问题,我的那个方法中是这样子的: ``` filterStudent(List<Student> students, FilterProcess<Student> mp) ``` 为什么我的代码参数却是这样子的呢 ``` filterStudent(list,(e)->e.getStar().equals("天秤座") ``` 其实 -> 这个是一个连接符,左边代表参数,而右边代表函数体(也就是我们说的条件),这个e就是代表 FilterProcess<Student> mp 这个参数的,只不过我们得java8 中lambda可以给这个参数附加上了条件,这些条件筛选都是封装到jdk8中内部类中自己实现的,所以我们只要附加条件就可以了,那个(e)就代表传了参数。 总结:lambda主要是针对集合中条件的筛选,包括数组等等。接下来我们介绍Stream API ,这个和Lambda息息相关,论重要性,lambda只是基础,Stream API 才是真正的升级版。 方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。 默认方法 − 默认方法就是一个在接口里面有了一个实现的方法。 新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。 Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。 ● 父类:BasicStream ● 子类:Stream、IntStream、LongStream、DoubleStream 包含两个类型,中间操作(intermediate operations)和结束操作(terminal operations) 下面是所有方法的属于那一端操作的方法:  然后准备一个测试类,和一个静态变量,代码如下: ``` public class JdkTest { public static List<Student> list = Arrays.asList( new Student("九天", "男", 5000, 18, "天秤座"), new Student("十夜", "男", 4000, 16, "双鱼座"), new Student("十一郎", "男", 3000, 24, "水瓶座") ); } ``` 接下来我们一个一个方法解析他们的作用: ● stream: 将集合转换成流,一般会使用流继续后续操作。 ``` @Test public void test0() { list.stream(); } ``` ● forEach遍历: forEach遍历集合,System.out::println等同于System.out.println() ``` @Test public void test1() { list.forEach(System.out::println); } ``` 结果为:  ● filter过滤 该方法中是一个筛选条件,等同于sql查询的where后面的筛选。 ``` @Test public void test2() { list.stream().filter((e) -> e.getStar().equals("天秤座")) .forEach(System.out::println); } ```  ● map转换集合 将List<Student> 转换为List<String>, collect是将结果转换为List ``` @Test public void test3() { List<String> names = list.stream().map(Student::getName).collect(Collectors.toList()); names.stream().forEach(System.out::println); } ```  ● mapToInt转换数值流 转换数值流,等同mapToLong、mapToDouble,如下这个是取最大值 ``` @Test public void test4() { IntStream intStream = list.stream().mapToInt(Student::getAge); Stream<Integer> integerStream = intStream.boxed(); Optional<Integer> max = integerStream.max(Integer::compareTo); System.out.println(max.get()); } ``` 结果为:24 ● flatMap合并成一个流 将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流 ``` @Test public void test5() { List<String> list2 = new ArrayList<>(); list2.add("aaa bbb ccc"); list2.add("ddd eee fff"); list2.add("ggg hhh iii"); list2 = list2.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(Collectors.toList()); System.out.println(list2); } ``` 结果为: ``` [aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii] ``` ● distinct去重 ``` @Test public void test6() { List<String> list2 = new ArrayList<>(); list2.add("aaa bbb ccc"); list2.add("ddd eee fff"); list2.add("ggg hhh iii"); list2.add("ggg hhh iii"); list2.stream().distinct().forEach(System.out::println); } ``` 结果: ``` aaa bbb ccc ddd eee fff ggg hhh iii ``` ● sorted排序 ``` @Test public void test7() { //asc排序 list.stream().sorted(Comparator.comparingInt(Student::getAge)).forEach(System.out::println); System.out.println("------------------------------------------------------------------"); //desc排序 list.stream().sorted(Comparator.comparingInt(Student::getAge).reversed()).forEach(System.out::println); } ``` 结果: ``` Student(name=十夜, sex=男, salary=4000, age=16, star=双鱼座) Student(name=九天, sex=男, salary=5000, age=18, star=天秤座) Student(name=十一郎, sex=男, salary=3000, age=24, star=水瓶座) ------------------------------------------------------------------ Student(name=十一郎, sex=男, salary=3000, age=24, star=水瓶座) Student(name=九天, sex=男, salary=5000, age=18, star=天秤座) Student(name=十夜, sex=男, salary=4000, age=16, star=双鱼座) ``` ● skip跳过前n个 ``` @Test public void test8() { list.stream().skip(1).forEach(System.out::println); } ``` ● limit截取前n个 ``` @Test public void test10() { list.stream().limit(1).forEach(System.out::println); } ``` 结果为: ``` Student(name=九天, sex=男, salary=5000, age=18, star=天秤座) ``` ● anyMatch 只要有其中任意一个符合条件 ``` @Test public void test11() { boolean isHave = list.stream().anyMatch(student -> student.getAge() == 16); System.out.println(isHave); } ``` ● allMatch 全部符合 ``` @Test public void test12() { boolean isHave = list.stream().allMatch(student -> student.getAge() == 16); System.out.println(isHave); } ``` ● noneMatch 是否满足没有符合的 ``` @Test public void test13() { boolean isHave = list.stream().noneMatch(student -> student.getAge() == 16); System.out.println(isHave); } ``` ● findAny 找到其中一个元素 (使用 stream() 时找到的是第一个元素;使用 parallelStream() 并行时找到的是其中一个元素) ``` @Test public void test14() { Optional<Student> student = list.stream().findAny(); System.out.println(student.get()); } ``` ● findFirst 找到第一个元素 ``` @Test public void test15() { Optional<Student> student = list.stream().findFirst(); System.out.println(student.get()); } ``` ● count计数 ``` @Test public void test17() { long count = list.stream().count(); System.out.println(count); } ``` ● of 生成一个字符串流 ``` @Test public void test18() { Stream<String> stringStream = Stream.of("i","love","you"); } ``` ● empty 生成一个空流 ``` @Test public void test19() { Stream<String> stringStream = Stream.empty(); } ``` ● iterate ``` @Test public void test20() { List<String> list = Arrays.asList("a", "b", "c", "c", "d", "f", "a"); Stream.iterate(0, i -> i + 1).limit(list.size()).forEach(i -> { System.out.println(String.valueOf(i) + list.get(i)); }); } ``` ● collect:averagingLong 求平均值 ``` @Test public void test1(){ // 求年龄平均值 Double average = list.stream().collect(Collectors.averagingLong(Student::getAge)); } ``` ● collect:collectingAndThen 两步结束,先如何,在如何 ``` @Test public void test1(){ // 求年龄平均值 String average = list.stream().collect(Collectors.collectingAndThen(Collectors.averagingInt(Student::getAge), a->"哈哈,平均年龄"+a)); System.out.println(average); } ``` 结果: ``` 哈哈,平均年龄20.5 ``` ● collect:counting 求个数 ``` @Test public void test1(){ // 求数量 Long num = list.stream().collect(Collectors.counting()); System.out.println(num); } ``` ● collect: groupingBy(Function) 接下来所有的都是用下面的新List数据测试使用 ``` public static List<Student> list = Arrays.asList( new Student("九天", "男", 5000, 18, "天秤座"), new Student("十夜", "男", 4000, 16, "双鱼座"), new Student("十一郎", "男", 3000, 24, "水瓶座"), new Student("十二郎", "男", 3000, 24, "水瓶座") ); @Test public void test1(){ Map<Integer,List<Student>> result = list.stream().collect(Collectors.groupingBy(Student::getAge)); for (Integer age:result.keySet()){ System.out.println(result.get(age)); } } ``` 结果: ``` [Student(name=十夜, sex=男, salary=4000, age=16, star=双鱼座)] [Student(name=九天, sex=男, salary=5000, age=18, star=天秤座)] [Student(name=十一郎, sex=男, salary=3000, age=24, star=水瓶座), Student(name=十二郎, sex=男, salary=3000, age=24, star=水瓶座)] ``` ● collect:groupingBy(Function,Collector) ``` @Test public void test1(){ // 先分组,在计算每组的个数 Map<Integer,Long> num = list.stream().collect(Collectors.groupingBy(Student::getAge,Collectors.counting())); System.out.println(num); } ``` 结果: ``` {16=1, 18=1, 24=2} ``` ● collect:groupingBy(Function, Supplier, Collector) ``` @Test public void test1(){ // 先分组,在计算每组的个数,然后排序 Map<Integer,Long> num = list.stream().collect(Collectors.groupingBy(Student::getAge, TreeMap::new,Collectors.counting())); System.out.println(num); } ``` ● collect:groupingByConcurrent 同上,不过这个Concurrent是并发的,也有3个方法,和上面非并发一个效果 ``` groupingByConcurrent(Function) groupingByConcurrent(Function, Collector) groupingByConcurrent(Function, Supplier, Collector) ``` ● collect:joining() ``` @Test public void test1(){ // 名字拼接 String result = list.stream().map(Student::getName).collect(Collectors.joining()); System.out.println(result); } ``` 结果: ```九天十夜十一郎十二郎``` ● collect:joining(str) ``` @Test public void test1(){ // 名字拼接,用逗号隔开 String result = list.stream().map(Student::getName).collect(Collectors.joining(",")); System.out.println(result); } ``` 结果: ```九天,十夜,十一郎,十二郎``` ● collect:joining(str, prefix, suffix) @Test public void test1(){ // 名字拼接,包含前缀、后缀 String result = list.stream().map(Student::getName).collect(Collectors.joining(",","hello","world")); System.out.println(result); } 结果: hello九天,十夜,十一郎,十二郎world ● collect:summarizingDouble ``` @Test public void test1(){ // 求年龄的最大值、最小值、平均值、综合以及人数 DoubleSummaryStatistics result = list.stream().collect(Collectors.summarizingDouble(Student::getAge)); System.out.println(result); } ``` 结果: ``` DoubleSummaryStatistics{count=4, sum=82.000000, min=16.000000, average=20.500000, max=24.000000} ``` ● collect:toCollection  Date Time API − 加强对日期与时间的处理。 1、JDK7 Date缺点: ● 所有的日期类都是可变的,因此他们都不是线程安全的,这是Java日期类最大的问题之一 ● Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义 ● java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。对于时间、时间戳、格式化以及解析,并没有一些明确定义的类。对于格式化和解析的需求,我们有java.text.DateFormat抽象类,但通常情况下,SimpleDateFormat类被用于此类需求 ● 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题 2、JDK8 Date优势 ● 不变性:新的日期/时间API中,所有的类都是不可变的,这对多线程环境有好处。 ● 关注点分离:新的API将人可读的日期时间和机器时间(unix timestamp)明确分离,它为日期(Date)、时间(Time)、日期时间(DateTime)、时间戳(unix timestamp)以及时区定义了不同的类。 ● 清晰:在所有的类中,方法都被明确定义用以完成相同的行为。举个例子,要拿到当前实例我们可以使用now()方法,在所有的类中都定义了format()和parse()方法,而不是像以前那样专门有一个独立的类。为了更好的处理问题,所有的类都使用了工厂模式和策略模式,一旦你使用了其中某个类的方法,与其他类协同工作并不困难。 ● 实用操作:所有新的日期/时间API类都实现了一系列方法用以完成通用的任务,如:加、减、格式化、解析、从日期/时间中提取单独部分,等等。 ● 可扩展性:新的日期/时间API是工作在ISO-8601日历系统上的,但我们也可以将其应用在非IOS的日历上。 JDK8 Date新增字段: Java.time包中的是类是不可变且线程安全的。新的时间及日期API位于java.time中,java8 time包下关键字段解读。 | 属性 | 含义 | |---------------|----| | Instant | 代表的是时间戳 | | LocalDate | 代表日期,比如2020-01-14 | | LocalTime | 代表时刻,比如12:59:59 | | LocalDateTime | 代表具体时间 2020-01-12 12:22:26 | | ZonedDateTime | 代表一个包含时区的完整的日期时间,偏移量是以UTC/ 格林威治时间为基准的 | | Period | 代表时间段 | | ZoneOffset | 代表时区偏移量,比如:+8:00 | | Clock | 代表时钟,比如获取目前美国纽约的时间 | ● 获取当前时间 ``` Instant instant = Instant.now(); //获取当前时间戳 LocalDate localDate = LocalDate.now(); //获取当前日期 LocalTime localTime = LocalTime.now(); //获取当前时刻 LocalDateTime localDateTime = LocalDateTime.now(); //获取当前具体时间 ZonedDateTime zonedDateTime = ZonedDateTime.now(); //获取带有时区的时间 ``` ● 字符串转换 ``` jdk8: String str = "2019-01-11"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate localDate = LocalDate.parse(str, formatter); jdk7: SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); try { Date date = simpleDateFormat.parse(str); } catch (ParseException e){ e.printStackTrace(); } ``` ● Date转换LocalDate ``` import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.Date; public class Test { public static void main(String[] args) { Date date = new Date(); Instant instant = date.toInstant(); ZoneId zoneId = ZoneId.systemDefault(); // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。 LocalDate localDate = instant.atZone(zoneId).toLocalDate(); System.out.println("Date = " + date); System.out.println("LocalDate = " + localDate); } } ``` ● LocalDate转Date ``` import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Date; public class Test { public static void main(String[] args) { ZoneId zoneId = ZoneId.systemDefault(); LocalDate localDate = LocalDate.now(); ZonedDateTime zdt = localDate.atStartOfDay(zoneId); Date date = Date.from(zdt.toInstant()); System.out.println("LocalDate = " + localDate); System.out.println("Date = " + date); } } ``` ● 时间戳转LocalDateTime ``` long timestamp = System.currentTimeMillis(); Instant instant = Instant.ofEpochMilli(timestamp); LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); ``` ● LocalDateTime转时间戳 ``` LocalDateTime dateTime = LocalDateTime.now(); dateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); dateTime.toInstant(ZoneOffset.of("+08:00")).toEpochMilli(); dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); ``` ● LocalDate方法总结 ``` getYear() int 获取当前日期的年份 getMonth() Month 获取当前日期的月份对象 getMonthValue() int 获取当前日期是第几月 getDayOfWeek() DayOfWeek 表示该对象表示的日期是星期几 getDayOfMonth() int 表示该对象表示的日期是这个月第几天 getDayOfYear() int 表示该对象表示的日期是今年第几天 withYear(int year) LocalDate 修改当前对象的年份 withMonth(int month) LocalDate 修改当前对象的月份 withDayOfMonth(intdayOfMonth) LocalDate 修改当前对象在当月的日期 isLeapYear() boolean 是否是闰年 lengthOfMonth() int 这个月有多少天 lengthOfYear() int 该对象表示的年份有多少天(365或者366) plusYears(longyearsToAdd) LocalDate 当前对象增加指定的年份数 plusMonths(longmonthsToAdd) LocalDate 当前对象增加指定的月份数 plusWeeks(longweeksToAdd) LocalDate 当前对象增加指定的周数 plusDays(longdaysToAdd) LocalDate 当前对象增加指定的天数 minusYears(longyearsToSubtract) LocalDate 当前对象减去指定的年数 minusMonths(longmonthsToSubtract) LocalDate 当前对象减去注定的月数 minusWeeks(longweeksToSubtract) LocalDate 当前对象减去指定的周数 minusDays(longdaysToSubtract) LocalDate 当前对象减去指定的天数 compareTo(ChronoLocalDateother) int 比较当前对象和other对象在时间上的大小,返回值如果为正,则当前对象时间较晚, isBefore(ChronoLocalDateother) boolean 比较当前对象日期是否在other对象日期之前 isAfter(ChronoLocalDateother) boolean 比较当前对象日期是否在other对象日期之后 isEqual(ChronoLocalDateother) boolean 比较两个日期对象是否相等 ``` Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。 Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。 2、Java9的特性详解: ● Shell工具: 怎么理解,怎么用呢?这个只是针对于java9来说,相当于cmd工具,你可以和cmd一样,直接写方法等等,不过我认为只是适用于初学者做一些最简单的运算和写一些方法,在cmd中打开这个工具:  进入工具后可以做一些简单的java操作  ● 模块化 一个大型的项目,比如淘宝商城等,都会包含多个模块,比如订单模块,前台模块,后台管理模块,广告位模块,会员模块.....等等,各个模块之间会相互调用,不过这种情况下会很少,只针对特殊情况,如果一个项目有30个模块系统进行开发,但是只要某个单独模块运行时,都会带动所有的模块,这样对于jvm来说在内存和性能上会很低,所以,java9提供了这一个特性,某一个模块运行的时候,jvm只会启动和它有依赖的模块,并不会加载所有的模块到内存中,这样性能大大的提高了。写法上如下:  一个项目中的两个模块,模块之间通过module-info.java来关联,在IDEA编辑器右键创建package-info.java  在这个两个模块java9Demo和java9Test中,java9demo编写一个实体类Person,在java9Test调用这样一个过程 这个是java9Demo 将 java9Test 模块需要的文件导出 exports 把它所在的包导出 ``` module java9Demo{ exports com.mdxl.layer_cj.entity; } ``` 然后在java9Test模块中创建一个package-info.java,引入java9Demo模块导出包名 ``` module java9Test{ requires java9Demo; } ``` 这样就可以直接在java9Test中引入Person实体类了,exports 控制着那些包可以被模块访问,所以不被导出的包不能被其他模块访问。 ● 多版本兼容Jar包 好多公司用的JDK大部分还是老版本,JDK6、7都有,他们都不敢升级主要是因为兼容的问题,但是JDK9做到了这一点,就是不管公司的项目是用的JDK6、7、8甚至5,他都可以兼容不出错,打个比方,你之前用的是iphone5,现在出现了iPhone6,iphone7,iphon8和iphone9,但是你不敢买9,因为你自己已经适应了iphone5的所有手机的运行流程,6,7,8每个手机的运行流程不一样,但是这个9很强大,它能够识别你现在所用的版本iphone是5,所以当你升级到iphone9的时候,你的这个手机运行流程还是iphone5的流程,只是在原有基础上拥有了更多的iphone9的所有优势。 ● 接口Interface的升级 ``` public interface FilterProcess<T> { //java 7 及以前 特性 全局常量 和抽象方法 public static final String a ="22"; boolean process(T t); //java 8 特性 静态方法和默认方法 default void love(){ System.out.println("java8 特性默认方法"); } static void haha(){ System.out.println("java8 特性静态方法"); } //java 9 特性 支持私有方法 private void java9(){} } ``` ● 钻石操作符的升级 ``` //java6及以前 Map<String,String> map7 = new HashMap<String,String>(); //java7和8 <>没有了数据类型 Map<String,String> map8 = new HashMap<>(); //java9 添加了匿名内部类的功能 后面添加了大括号{} 可以做一些细节的操作 Map<String,String> map9 = new HashMap<>(){}; ``` ● 异常处理try升级 首先看下jdk6,7,8,9 的try catch的比较 Java6处理方式: ``` //java7及以前写法 每一个流打开的时候都要关闭 @Test public void test7(){ InputStreamReader reader = null; try{ reader = new InputStreamReader(System.in); reader.read(); }catch (IOException e){ e.printStackTrace(); }finally { if (reader != null){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } ``` JDK7,8 共同的处理方式: ``` @Test public void test7(){ try(InputStreamReader reader =new InputStreamReader(System.in)){ reader.read(); }catch (IOException e){ e.printStackTrace(); } } ``` java9的处理方式: ``` //java9及 每一个流打开的时候都要关闭,但是在try的括号中来进行关闭,在 //java8的基础上进一步升级 直接在try括号中直接写入 变量就好,如果有多个流,就用分号隔开 //try(reader;writer){} @Test public void test7(){ InputStreamReader reader =new InputStreamReader(System.in); try(reader){ reader.read(); }catch (IOException e){ e.printStackTrace(); } } ``` ● 特殊标识符增加限制 JDK8之前 String _ ="hello"; 这样的标识符可以用,JDK9就用不到。 ● String底层存储结构更换 JDK8之前 String的底层结构类型都是 char[] ,但是JDK9 就替换成 byte[] 这样来讲,更节省了空间和提高了性能。   之所以替换是因为 之前一直是最小单位是一个char,用到两个byte,但是JDK8是基于latin1的,而这个latin1编码可以用一个byte标识,所以当你数据明明可以用到一个byte的时候,我们用到了一个最小单位chat两个byte,就多出了一个byte的空间。所以JDK9在这一方面进行了更新,现在的JDK9 是基于ISO/latin1/Utf-16 ,latin1和ISO用一个byte标识,UTF-16用两个byte标识,JDK9会自动识别用哪个编码,当数据用到1byte,就会使用iSO或者latin1 ,当空间数据满足2byte的时候,自动使用utf-16,节省了很多空间。   ● Stream API 新方法的添加 在原有Stream API 新添加了4个方法,takeWhile dropWhile ofNullable iterate(新重载方法) 首先解释 takeWhile 当达到一定条件就结束:输出结果为45 43,如图  而 dropWhile 则和takeWhile 相反 ofNullable, 在java8中 Stream中的元素不能完全为null,否则空指针异常,而在java9的升级中,允许创建null iterate 不加条件无线循环  引进HttpClient 以往我们都是通过maven添加httpclient ,java9直接引入即可 ● Java9所有特性都是为了提高性能和内存。。。。
### 考点分析! Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 JavaScript 引擎,新的日期 API,新的Stream API 等。 Java 9 发布于 2017 年 9 月 22 日,带来了很多新特性,其中最主要的变化是已经实现的模块化系统。接下来我们会详细介绍 Java 9 的新特性。 ### 典型回答! 1、Java8新特性: ① 引入了lambda表达式,可以简化匿名内部类的代码,允许将方法作为参数。 ② 方法引用,可以进一步简化lambda表达式的书写,可以引用类的构造方法,静态方法,特定类的方法和某个对象的方法。 ③ 可以在接口中使用default定义默认方法和静态方法,引入默认方法方便了接口升级的维护,之前如果在接口中新增一个方法必须修改所有实现类。 ④ 引入了stream类,支持链式编程,为集合类和数组提供了一些方便的操作方法,例如filter、skip、limit和map、concat等。 ⑤ 可以通过类型自动推测泛型参数。 ⑥ 允许重复使用注解,扩大了注解的使用范围,可以用在局部变量和泛型,方法异常上。 ⑦ 引入了Optional类解决空指针异常,更新了日期类的API等。 2、Java9新特性: ① Shell工具:相当于cmd工具,你可以和cmd一样,进入工具后可以做一些简单的java操作。 ② 模块化:某一个模块运行的时候,jvm只会启动和它有依赖的模块,并不会加载所有的模块到内存中,这样性能大大的提高了。 ③ 多版本兼容Jar包:可以兼容不同版本的jar包。 ④ 接口Interface的升级:支持私有方法 ⑤ 钻石操作符的升级 ⑥ 异常处理try升级 ⑦ 特殊标识符增加限制 ⑧ String底层存储结构更换 ⑨ Stream API 新方法的添加 Java9所有特性都是为了提高性能和内存。 ### 后续扩展! 1、Java8 新增了非常多的特性,我们主要讨论以下几个: Lambda 表达式 − Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。 ``` public void test3(){ List<Student> list = Arrays.asList( new Student("九天","男",5000,18,"天秤座"), new Student("十夜","男",4000,16,"双鱼座"), new Student("十一郎","男",3000,24,"水瓶座") ); //Lambda表达式 List<Student> result = filterStudent(list,(e)->e.getStar().equals("天秤座")); System.out.println(result); } ``` 测试结果: ``` [Student(name=九天, sex=男, salary=5000, age=18, star=天秤座)] ``` 但是现在又会有人会问这个问题,我的那个方法中是这样子的: ``` filterStudent(List<Student> students, FilterProcess<Student> mp) ``` 为什么我的代码参数却是这样子的呢 ``` filterStudent(list,(e)->e.getStar().equals("天秤座") ``` 其实 -> 这个是一个连接符,左边代表参数,而右边代表函数体(也就是我们说的条件),这个e就是代表 FilterProcess<Student> mp 这个参数的,只不过我们得java8 中lambda可以给这个参数附加上了条件,这些条件筛选都是封装到jdk8中内部类中自己实现的,所以我们只要附加条件就可以了,那个(e)就代表传了参数。 总结:lambda主要是针对集合中条件的筛选,包括数组等等。接下来我们介绍Stream API ,这个和Lambda息息相关,论重要性,lambda只是基础,Stream API 才是真正的升级版。 方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。 默认方法 − 默认方法就是一个在接口里面有了一个实现的方法。 新工具 − 新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。 Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。 ● 父类:BasicStream ● 子类:Stream、IntStream、LongStream、DoubleStream 包含两个类型,中间操作(intermediate operations)和结束操作(terminal operations) 下面是所有方法的属于那一端操作的方法:  然后准备一个测试类,和一个静态变量,代码如下: ``` public class JdkTest { public static List<Student> list = Arrays.asList( new Student("九天", "男", 5000, 18, "天秤座"), new Student("十夜", "男", 4000, 16, "双鱼座"), new Student("十一郎", "男", 3000, 24, "水瓶座") ); } ``` 接下来我们一个一个方法解析他们的作用: ● stream: 将集合转换成流,一般会使用流继续后续操作。 ``` @Test public void test0() { list.stream(); } ``` ● forEach遍历: forEach遍历集合,System.out::println等同于System.out.println() ``` @Test public void test1() { list.forEach(System.out::println); } ``` 结果为:  ● filter过滤 该方法中是一个筛选条件,等同于sql查询的where后面的筛选。 ``` @Test public void test2() { list.stream().filter((e) -> e.getStar().equals("天秤座")) .forEach(System.out::println); } ```  ● map转换集合 将List<Student> 转换为List<String>, collect是将结果转换为List ``` @Test public void test3() { List<String> names = list.stream().map(Student::getName).collect(Collectors.toList()); names.stream().forEach(System.out::println); } ```  ● mapToInt转换数值流 转换数值流,等同mapToLong、mapToDouble,如下这个是取最大值 ``` @Test public void test4() { IntStream intStream = list.stream().mapToInt(Student::getAge); Stream<Integer> integerStream = intStream.boxed(); Optional<Integer> max = integerStream.max(Integer::compareTo); System.out.println(max.get()); } ``` 结果为:24 ● flatMap合并成一个流 将流中的每一个元素 T 映射为一个流,再把每一个流连接成为一个流 ``` @Test public void test5() { List<String> list2 = new ArrayList<>(); list2.add("aaa bbb ccc"); list2.add("ddd eee fff"); list2.add("ggg hhh iii"); list2 = list2.stream().map(s -> s.split(" ")).flatMap(Arrays::stream).collect(Collectors.toList()); System.out.println(list2); } ``` 结果为: ``` [aaa, bbb, ccc, ddd, eee, fff, ggg, hhh, iii] ``` ● distinct去重 ``` @Test public void test6() { List<String> list2 = new ArrayList<>(); list2.add("aaa bbb ccc"); list2.add("ddd eee fff"); list2.add("ggg hhh iii"); list2.add("ggg hhh iii"); list2.stream().distinct().forEach(System.out::println); } ``` 结果: ``` aaa bbb ccc ddd eee fff ggg hhh iii ``` ● sorted排序 ``` @Test public void test7() { //asc排序 list.stream().sorted(Comparator.comparingInt(Student::getAge)).forEach(System.out::println); System.out.println("------------------------------------------------------------------"); //desc排序 list.stream().sorted(Comparator.comparingInt(Student::getAge).reversed()).forEach(System.out::println); } ``` 结果: ``` Student(name=十夜, sex=男, salary=4000, age=16, star=双鱼座) Student(name=九天, sex=男, salary=5000, age=18, star=天秤座) Student(name=十一郎, sex=男, salary=3000, age=24, star=水瓶座) ------------------------------------------------------------------ Student(name=十一郎, sex=男, salary=3000, age=24, star=水瓶座) Student(name=九天, sex=男, salary=5000, age=18, star=天秤座) Student(name=十夜, sex=男, salary=4000, age=16, star=双鱼座) ``` ● skip跳过前n个 ``` @Test public void test8() { list.stream().skip(1).forEach(System.out::println); } ``` ● limit截取前n个 ``` @Test public void test10() { list.stream().limit(1).forEach(System.out::println); } ``` 结果为: ``` Student(name=九天, sex=男, salary=5000, age=18, star=天秤座) ``` ● anyMatch 只要有其中任意一个符合条件 ``` @Test public void test11() { boolean isHave = list.stream().anyMatch(student -> student.getAge() == 16); System.out.println(isHave); } ``` ● allMatch 全部符合 ``` @Test public void test12() { boolean isHave = list.stream().allMatch(student -> student.getAge() == 16); System.out.println(isHave); } ``` ● noneMatch 是否满足没有符合的 ``` @Test public void test13() { boolean isHave = list.stream().noneMatch(student -> student.getAge() == 16); System.out.println(isHave); } ``` ● findAny 找到其中一个元素 (使用 stream() 时找到的是第一个元素;使用 parallelStream() 并行时找到的是其中一个元素) ``` @Test public void test14() { Optional<Student> student = list.stream().findAny(); System.out.println(student.get()); } ``` ● findFirst 找到第一个元素 ``` @Test public void test15() { Optional<Student> student = list.stream().findFirst(); System.out.println(student.get()); } ``` ● count计数 ``` @Test public void test17() { long count = list.stream().count(); System.out.println(count); } ``` ● of 生成一个字符串流 ``` @Test public void test18() { Stream<String> stringStream = Stream.of("i","love","you"); } ``` ● empty 生成一个空流 ``` @Test public void test19() { Stream<String> stringStream = Stream.empty(); } ``` ● iterate ``` @Test public void test20() { List<String> list = Arrays.asList("a", "b", "c", "c", "d", "f", "a"); Stream.iterate(0, i -> i + 1).limit(list.size()).forEach(i -> { System.out.println(String.valueOf(i) + list.get(i)); }); } ``` ● collect:averagingLong 求平均值 ``` @Test public void test1(){ // 求年龄平均值 Double average = list.stream().collect(Collectors.averagingLong(Student::getAge)); } ``` ● collect:collectingAndThen 两步结束,先如何,在如何 ``` @Test public void test1(){ // 求年龄平均值 String average = list.stream().collect(Collectors.collectingAndThen(Collectors.averagingInt(Student::getAge), a->"哈哈,平均年龄"+a)); System.out.println(average); } ``` 结果: ``` 哈哈,平均年龄20.5 ``` ● collect:counting 求个数 ``` @Test public void test1(){ // 求数量 Long num = list.stream().collect(Collectors.counting()); System.out.println(num); } ``` ● collect: groupingBy(Function) 接下来所有的都是用下面的新List数据测试使用 ``` public static List<Student> list = Arrays.asList( new Student("九天", "男", 5000, 18, "天秤座"), new Student("十夜", "男", 4000, 16, "双鱼座"), new Student("十一郎", "男", 3000, 24, "水瓶座"), new Student("十二郎", "男", 3000, 24, "水瓶座") ); @Test public void test1(){ Map<Integer,List<Student>> result = list.stream().collect(Collectors.groupingBy(Student::getAge)); for (Integer age:result.keySet()){ System.out.println(result.get(age)); } } ``` 结果: ``` [Student(name=十夜, sex=男, salary=4000, age=16, star=双鱼座)] [Student(name=九天, sex=男, salary=5000, age=18, star=天秤座)] [Student(name=十一郎, sex=男, salary=3000, age=24, star=水瓶座), Student(name=十二郎, sex=男, salary=3000, age=24, star=水瓶座)] ``` ● collect:groupingBy(Function,Collector) ``` @Test public void test1(){ // 先分组,在计算每组的个数 Map<Integer,Long> num = list.stream().collect(Collectors.groupingBy(Student::getAge,Collectors.counting())); System.out.println(num); } ``` 结果: ``` {16=1, 18=1, 24=2} ``` ● collect:groupingBy(Function, Supplier, Collector) ``` @Test public void test1(){ // 先分组,在计算每组的个数,然后排序 Map<Integer,Long> num = list.stream().collect(Collectors.groupingBy(Student::getAge, TreeMap::new,Collectors.counting())); System.out.println(num); } ``` ● collect:groupingByConcurrent 同上,不过这个Concurrent是并发的,也有3个方法,和上面非并发一个效果 ``` groupingByConcurrent(Function) groupingByConcurrent(Function, Collector) groupingByConcurrent(Function, Supplier, Collector) ``` ● collect:joining() ``` @Test public void test1(){ // 名字拼接 String result = list.stream().map(Student::getName).collect(Collectors.joining()); System.out.println(result); } ``` 结果: ```九天十夜十一郎十二郎``` ● collect:joining(str) ``` @Test public void test1(){ // 名字拼接,用逗号隔开 String result = list.stream().map(Student::getName).collect(Collectors.joining(",")); System.out.println(result); } ``` 结果: ```九天,十夜,十一郎,十二郎``` ● collect:joining(str, prefix, suffix) @Test public void test1(){ // 名字拼接,包含前缀、后缀 String result = list.stream().map(Student::getName).collect(Collectors.joining(",","hello","world")); System.out.println(result); } 结果: hello九天,十夜,十一郎,十二郎world ● collect:summarizingDouble ``` @Test public void test1(){ // 求年龄的最大值、最小值、平均值、综合以及人数 DoubleSummaryStatistics result = list.stream().collect(Collectors.summarizingDouble(Student::getAge)); System.out.println(result); } ``` 结果: ``` DoubleSummaryStatistics{count=4, sum=82.000000, min=16.000000, average=20.500000, max=24.000000} ``` ● collect:toCollection  Date Time API − 加强对日期与时间的处理。 1、JDK7 Date缺点: ● 所有的日期类都是可变的,因此他们都不是线程安全的,这是Java日期类最大的问题之一 ● Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义 ● java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。对于时间、时间戳、格式化以及解析,并没有一些明确定义的类。对于格式化和解析的需求,我们有java.text.DateFormat抽象类,但通常情况下,SimpleDateFormat类被用于此类需求 ● 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题 2、JDK8 Date优势 ● 不变性:新的日期/时间API中,所有的类都是不可变的,这对多线程环境有好处。 ● 关注点分离:新的API将人可读的日期时间和机器时间(unix timestamp)明确分离,它为日期(Date)、时间(Time)、日期时间(DateTime)、时间戳(unix timestamp)以及时区定义了不同的类。 ● 清晰:在所有的类中,方法都被明确定义用以完成相同的行为。举个例子,要拿到当前实例我们可以使用now()方法,在所有的类中都定义了format()和parse()方法,而不是像以前那样专门有一个独立的类。为了更好的处理问题,所有的类都使用了工厂模式和策略模式,一旦你使用了其中某个类的方法,与其他类协同工作并不困难。 ● 实用操作:所有新的日期/时间API类都实现了一系列方法用以完成通用的任务,如:加、减、格式化、解析、从日期/时间中提取单独部分,等等。 ● 可扩展性:新的日期/时间API是工作在ISO-8601日历系统上的,但我们也可以将其应用在非IOS的日历上。 JDK8 Date新增字段: Java.time包中的是类是不可变且线程安全的。新的时间及日期API位于java.time中,java8 time包下关键字段解读。 | 属性 | 含义 | |---------------|----| | Instant | 代表的是时间戳 | | LocalDate | 代表日期,比如2020-01-14 | | LocalTime | 代表时刻,比如12:59:59 | | LocalDateTime | 代表具体时间 2020-01-12 12:22:26 | | ZonedDateTime | 代表一个包含时区的完整的日期时间,偏移量是以UTC/ 格林威治时间为基准的 | | Period | 代表时间段 | | ZoneOffset | 代表时区偏移量,比如:+8:00 | | Clock | 代表时钟,比如获取目前美国纽约的时间 | ● 获取当前时间 ``` Instant instant = Instant.now(); //获取当前时间戳 LocalDate localDate = LocalDate.now(); //获取当前日期 LocalTime localTime = LocalTime.now(); //获取当前时刻 LocalDateTime localDateTime = LocalDateTime.now(); //获取当前具体时间 ZonedDateTime zonedDateTime = ZonedDateTime.now(); //获取带有时区的时间 ``` ● 字符串转换 ``` jdk8: String str = "2019-01-11"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate localDate = LocalDate.parse(str, formatter); jdk7: SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); try { Date date = simpleDateFormat.parse(str); } catch (ParseException e){ e.printStackTrace(); } ``` ● Date转换LocalDate ``` import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; import java.util.Date; public class Test { public static void main(String[] args) { Date date = new Date(); Instant instant = date.toInstant(); ZoneId zoneId = ZoneId.systemDefault(); // atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。 LocalDate localDate = instant.atZone(zoneId).toLocalDate(); System.out.println("Date = " + date); System.out.println("LocalDate = " + localDate); } } ``` ● LocalDate转Date ``` import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Date; public class Test { public static void main(String[] args) { ZoneId zoneId = ZoneId.systemDefault(); LocalDate localDate = LocalDate.now(); ZonedDateTime zdt = localDate.atStartOfDay(zoneId); Date date = Date.from(zdt.toInstant()); System.out.println("LocalDate = " + localDate); System.out.println("Date = " + date); } } ``` ● 时间戳转LocalDateTime ``` long timestamp = System.currentTimeMillis(); Instant instant = Instant.ofEpochMilli(timestamp); LocalDateTime.ofInstant(instant, ZoneId.systemDefault()); ``` ● LocalDateTime转时间戳 ``` LocalDateTime dateTime = LocalDateTime.now(); dateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli(); dateTime.toInstant(ZoneOffset.of("+08:00")).toEpochMilli(); dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); ``` ● LocalDate方法总结 ``` getYear() int 获取当前日期的年份 getMonth() Month 获取当前日期的月份对象 getMonthValue() int 获取当前日期是第几月 getDayOfWeek() DayOfWeek 表示该对象表示的日期是星期几 getDayOfMonth() int 表示该对象表示的日期是这个月第几天 getDayOfYear() int 表示该对象表示的日期是今年第几天 withYear(int year) LocalDate 修改当前对象的年份 withMonth(int month) LocalDate 修改当前对象的月份 withDayOfMonth(intdayOfMonth) LocalDate 修改当前对象在当月的日期 isLeapYear() boolean 是否是闰年 lengthOfMonth() int 这个月有多少天 lengthOfYear() int 该对象表示的年份有多少天(365或者366) plusYears(longyearsToAdd) LocalDate 当前对象增加指定的年份数 plusMonths(longmonthsToAdd) LocalDate 当前对象增加指定的月份数 plusWeeks(longweeksToAdd) LocalDate 当前对象增加指定的周数 plusDays(longdaysToAdd) LocalDate 当前对象增加指定的天数 minusYears(longyearsToSubtract) LocalDate 当前对象减去指定的年数 minusMonths(longmonthsToSubtract) LocalDate 当前对象减去注定的月数 minusWeeks(longweeksToSubtract) LocalDate 当前对象减去指定的周数 minusDays(longdaysToSubtract) LocalDate 当前对象减去指定的天数 compareTo(ChronoLocalDateother) int 比较当前对象和other对象在时间上的大小,返回值如果为正,则当前对象时间较晚, isBefore(ChronoLocalDateother) boolean 比较当前对象日期是否在other对象日期之前 isAfter(ChronoLocalDateother) boolean 比较当前对象日期是否在other对象日期之后 isEqual(ChronoLocalDateother) boolean 比较两个日期对象是否相等 ``` Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。 Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。 2、Java9的特性详解: ● Shell工具: 怎么理解,怎么用呢?这个只是针对于java9来说,相当于cmd工具,你可以和cmd一样,直接写方法等等,不过我认为只是适用于初学者做一些最简单的运算和写一些方法,在cmd中打开这个工具:  进入工具后可以做一些简单的java操作  ● 模块化 一个大型的项目,比如淘宝商城等,都会包含多个模块,比如订单模块,前台模块,后台管理模块,广告位模块,会员模块.....等等,各个模块之间会相互调用,不过这种情况下会很少,只针对特殊情况,如果一个项目有30个模块系统进行开发,但是只要某个单独模块运行时,都会带动所有的模块,这样对于jvm来说在内存和性能上会很低,所以,java9提供了这一个特性,某一个模块运行的时候,jvm只会启动和它有依赖的模块,并不会加载所有的模块到内存中,这样性能大大的提高了。写法上如下:  一个项目中的两个模块,模块之间通过module-info.java来关联,在IDEA编辑器右键创建package-info.java  在这个两个模块java9Demo和java9Test中,java9demo编写一个实体类Person,在java9Test调用这样一个过程 这个是java9Demo 将 java9Test 模块需要的文件导出 exports 把它所在的包导出 ``` module java9Demo{ exports com.mdxl.layer_cj.entity; } ``` 然后在java9Test模块中创建一个package-info.java,引入java9Demo模块导出包名 ``` module java9Test{ requires java9Demo; } ``` 这样就可以直接在java9Test中引入Person实体类了,exports 控制着那些包可以被模块访问,所以不被导出的包不能被其他模块访问。 ● 多版本兼容Jar包 好多公司用的JDK大部分还是老版本,JDK6、7都有,他们都不敢升级主要是因为兼容的问题,但是JDK9做到了这一点,就是不管公司的项目是用的JDK6、7、8甚至5,他都可以兼容不出错,打个比方,你之前用的是iphone5,现在出现了iPhone6,iphone7,iphon8和iphone9,但是你不敢买9,因为你自己已经适应了iphone5的所有手机的运行流程,6,7,8每个手机的运行流程不一样,但是这个9很强大,它能够识别你现在所用的版本iphone是5,所以当你升级到iphone9的时候,你的这个手机运行流程还是iphone5的流程,只是在原有基础上拥有了更多的iphone9的所有优势。 ● 接口Interface的升级 ``` public interface FilterProcess<T> { //java 7 及以前 特性 全局常量 和抽象方法 public static final String a ="22"; boolean process(T t); //java 8 特性 静态方法和默认方法 default void love(){ System.out.println("java8 特性默认方法"); } static void haha(){ System.out.println("java8 特性静态方法"); } //java 9 特性 支持私有方法 private void java9(){} } ``` ● 钻石操作符的升级 ``` //java6及以前 Map<String,String> map7 = new HashMap<String,String>(); //java7和8 <>没有了数据类型 Map<String,String> map8 = new HashMap<>(); //java9 添加了匿名内部类的功能 后面添加了大括号{} 可以做一些细节的操作 Map<String,String> map9 = new HashMap<>(){}; ``` ● 异常处理try升级 首先看下jdk6,7,8,9 的try catch的比较 Java6处理方式: ``` //java7及以前写法 每一个流打开的时候都要关闭 @Test public void test7(){ InputStreamReader reader = null; try{ reader = new InputStreamReader(System.in); reader.read(); }catch (IOException e){ e.printStackTrace(); }finally { if (reader != null){ try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } } ``` JDK7,8 共同的处理方式: ``` @Test public void test7(){ try(InputStreamReader reader =new InputStreamReader(System.in)){ reader.read(); }catch (IOException e){ e.printStackTrace(); } } ``` java9的处理方式: ``` //java9及 每一个流打开的时候都要关闭,但是在try的括号中来进行关闭,在 //java8的基础上进一步升级 直接在try括号中直接写入 变量就好,如果有多个流,就用分号隔开 //try(reader;writer){} @Test public void test7(){ InputStreamReader reader =new InputStreamReader(System.in); try(reader){ reader.read(); }catch (IOException e){ e.printStackTrace(); } } ``` ● 特殊标识符增加限制 JDK8之前 String _ ="hello"; 这样的标识符可以用,JDK9就用不到。 ● String底层存储结构更换 JDK8之前 String的底层结构类型都是 char[] ,但是JDK9 就替换成 byte[] 这样来讲,更节省了空间和提高了性能。   之所以替换是因为 之前一直是最小单位是一个char,用到两个byte,但是JDK8是基于latin1的,而这个latin1编码可以用一个byte标识,所以当你数据明明可以用到一个byte的时候,我们用到了一个最小单位chat两个byte,就多出了一个byte的空间。所以JDK9在这一方面进行了更新,现在的JDK9 是基于ISO/latin1/Utf-16 ,latin1和ISO用一个byte标识,UTF-16用两个byte标识,JDK9会自动识别用哪个编码,当数据用到1byte,就会使用iSO或者latin1 ,当空间数据满足2byte的时候,自动使用utf-16,节省了很多空间。   ● Stream API 新方法的添加 在原有Stream API 新添加了4个方法,takeWhile dropWhile ofNullable iterate(新重载方法) 首先解释 takeWhile 当达到一定条件就结束:输出结果为45 43,如图  而 dropWhile 则和takeWhile 相反 ofNullable, 在java8中 Stream中的元素不能完全为null,否则空指针异常,而在java9的升级中,允许创建null iterate 不加条件无线循环  引进HttpClient 以往我们都是通过maven添加httpclient ,java9直接引入即可 ● Java9所有特性都是为了提高性能和内存。。。。
评论 (
0
)
登录
后才可以发表评论
状态
待办的
待办的
进行中
已完成
已关闭
负责人
未设置
标签
未设置
标签管理
里程碑
01.JavaSE阶段面试题
未关联里程碑
Pull Requests
未关联
未关联
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
未关联
未关联
master
开始日期   -   截止日期
-
置顶选项
不置顶
置顶等级:高
置顶等级:中
置顶等级:低
优先级
不指定
严重
主要
次要
不重要
参与者(1)
1
https://gitee.com/beike-java-interview-alliance/java-interview.git
git@gitee.com:beike-java-interview-alliance/java-interview.git
beike-java-interview-alliance
java-interview
Java技术提升库
点此查找更多帮助
搜索帮助
Git 命令在线学习
如何在 Gitee 导入 GitHub 仓库
Git 仓库基础操作
企业版和社区版功能对比
SSH 公钥设置
如何处理代码冲突
仓库体积过大,如何减小?
如何找回被删除的仓库数据
Gitee 产品配额说明
GitHub仓库快速导入Gitee及同步更新
什么是 Release(发行版)
将 PHP 项目自动发布到 packagist.org
评论
仓库举报
回到顶部
登录提示
该操作需登录 Gitee 帐号,请先登录后再操作。
立即登录
没有帐号,去注册