Java是一门面向对象的编程语言 ,不仅吸收了C++ 语言的各种优点,还摒弃了C++里难以理解的多继承 、指针 等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程。Java具有简单性、面向对象、分布式 、健壮性 、安全性 、平台独立与可移植性、多线程 、动态性等特点。 Java可以编写桌面应用程序 、Web应用程序、分布式系统 和嵌入式系统 应用程序等
JDK安装下载 下载jdk-17.0.12_windows-x64_bin.zip , 安装时可以选择安装地址,安装完成后配置JDK17的环境变量:
1 2 3 新增系统变量:JAVA_HOME,值为D:\IDEA\Java\jdk-17(安装路径) 新增系统变量:CLASSPATH,值为.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar,注意最前面的小黑点不能省. 在系统变量Path下新增两条配置:%JAVA_HOME%\bin和%JAVA_HOME%\jre\bin
其他版本安装差不多,下载地址Java downloads
Java8 新特性 原文链接:https://blog.csdn.net/qq_40991313/article/details/137256095
1.基本介绍
Lambda表达式 :Lambda表达式可以被视为一个对象,必须有上下文环境,作用是实现单方法的接口。该特性可以将功能视为方法参数,或者将代码视为数据。上下文环境意思是能证明它是对象,如让它处在方法或类的实参里,或者赋值给对象引用。
省略情况 :形参类型、返回类型可以省略,单参数能省略小括号,单语句能省略return、分号和大括号(全省略或全不省略)
**方法引用**:引用已存在的Lambda表达式,达到相同的效果。引用已有Java类或对象(实例)的静态方法、实例方法、对象方法(System.out::println;)、构造器方法。可与Lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
**接口默认方法**:允许在接口中定义默认方法,默认方法必须使用default修饰。默认方法是接口中有方法体的方法,用于向已有的接口添加新的功能,而无需破坏现有的实现。实现类可以直接调用默认方法,也可以重写默认方法。
**Stream API**:新添加的Stream API(java.util.stream)支持对元素流进行函数式操作。Stream API 集成在 Collections API 中,可以对集合进行批量操作(stream流的生成、操作、收集),例如filter()过滤、distinct()去重、map()加工、sorted()排序等操作。
Date Time API新增LocalDate、LocalTime、DateTimeFormatter等类 :加强对日期与时间的处理。LocalDate、LocalTime可以获取本地时间。线程安全的DateTimeFormatter代替线程不安全的SimpleDateFormat,用于将日期和字符串之间格式转换。
HashMap底层引入红黑树 :之前版本HashMap底层是“数组+链表”,当头插法的value链表长度大于等于8时,链表会转为红黑树,红黑树查询性能稳定O(logn),是近似平衡二叉树,层数最高2logn。
ConcurrentHashMap降低锁的粒度 :JDK1.8之前采用分段锁,锁粒度是分段segment,JDK1.8采用synchronized+CAS,锁粒度是槽(头节点)
CompletableFuture :是Future的实现类,JDK8引入,用于异步编排。
JVM方法区的实现方式由永久代改为元空间 :元空间属于本地内存,由操作系统直接管理,不再受JVM管理。同时内存空间可以自动扩容,避免内存溢出。默认情况下元空间可以无限使用本地内存,也可以通过-XX:MetaspaceSize限制内存大小。
2.Lambda表达式 Lambda 表达式是 Java 8 引入的一种新特性,主要用于实现单方法的接口,符合函数式思想。
函数式思想: 在数学中,函数是一套计算方案,包含输入量和输出量,即“拿数据做操作”。 面向对象思想强调通过对象的形式来完成任务,而函数式思想则尽量忽略面向对象的复杂语法,强调“做什么”,而不是“以什么形式去做”。 Lambda表达式正是函数式思想的体现。它用来实现单方法接口的方法逻辑,实现过程中的参数可省略类型(因为类型已经在接口里声明过了),单个表达式时可以省略分号和大括号(因为只有单个语句,不用分号分割也不会有歧义)。
Lambda表达式实际是一个对象,形式是一个方法的逻辑:():{}。
例如前面TreeSet那块有提到过:
1 2 3 4 5 6 7 8 9 10 TreeSet<Dog> dogs = new TreeSet <>(new Comparator <Dog>() { @Override public int compare (Dog a, Dog b) { return a.weight - b.weight; } }); TreeSet<Dog> dogs = new TreeSet <>((a, b) -> a.weight - b.weight);
Lambda和匿名内部类区别:
接口: Lambda只能是接口,匿名内部类可以是接口、抽象类、具体类。
方法: Lambda只能单方法,匿名内部类可以多方法。
原理: Lambda编译后字节码在运行时动态生成 ,匿名内部类编译后生成一个字节码文件 。
基本语法
1 2 3 (参数列表) -> 单个表达式 或 (参数列表) -> { 表达式1 ;表达式2 ; }
可省略内容:
形参类型、返回类型可以省略;
单参数能省略小括号;
单语句能省略return、分号和大括号(全省略或全不省略)
代码示例:
形参类型、返回类型可以省略 。毕竟接口里也声明了类型,类型必须要么都写要么都省略。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Demo { public static void main (String[] args) { fun((a,b)->a+b); } public static void fun (Dog d) { d.add(1 ,4 ); } } public interface Dog { public int add (int a,int b) ; }
3. Stream流 3.1 基本介绍 Stream 流是 Java 8 引入的一项新特性,用于对集合进行函数式编程风格的操作。它允许我们以声明性方式对数据进行过滤、加工、遍历、排序等操作,而不是以命令式方式逐个操作元素。
特点 :
声明式编程 :使用流操作表达数据处理的意图,而不是具体的实现。声明式编程强调“做什么”而不是“怎么做”。在声明式编程中,程序员专注于描述要完成的任务或问题,而不是描述具体的实现步骤。Stream流把复杂啰嗦的代码改成一串简洁的代码,符合声明式编程。
链式操作 :流操作可以链式调用,使代码更加简洁和易读。链式操作是利用运算符进行的连续运算(操作),如连续的赋值操作,而非拆成多条语句一个个加。例如stringBuilder.append(1).append(2);是链式操作,而stringBuilder.append(“a”);stringBuilder.append(“b”);不是链式操作。
惰性求值 :流操作是惰性求值的,即只有在终端操作才会执行实际计算,map等中间操作不会直接计算求值。
并行处理 :遍历的每一层之间是并发处理的,性能高。
代码示例 : 先获取List的stream流,给集合中每个元素+2,然后升序排序、过滤只保留大于20的元素,最后收集成List类型的集合:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Test { public static void main (String[] args) { List<Integer> arrayList = new ArrayList <>(); arrayList.add(10 ); arrayList.add(20 ); arrayList.add(30 ); arrayList.add(40 ); arrayList.add(50 ); System.out.println("使用 Stream API 遍历并修改元素:" ); List<Integer> modifiedList = arrayList.stream() .map(num -> num + 2 ).sorted().filter(num -> num > 20 ) .collect(Collectors.toList()); System.out.println(modifiedList); } }
3.2 常用方法 3.2.1 生成操作 生成一个流
Stream.of(T... values):通过提供的值创建一个流。
Stream.ofNullable(T t):通过单个值创建一个包含该值的流或一个空流。
Arrays.stream(T[] array):通过数组创建一个流。
Collection.stream():通过集合创建一个顺序流。
Collection.parallelStream():通过集合创建一个并行流。
Stream.generate(Supplier<T> s):生成一个无限流,元素由提供的 Supplier 生成。
Stream.iterate(T seed, UnaryOperator<T> f):生成一个无限流,初始元素为 seed,后续元素由一元运算符生成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class StreamGeneration { public static void main (String[] args) { List<String> list = new ArrayList <String>(); Stream<String> listStream = list.stream(); Set<String> set = new HashSet <String>(); Stream<String> setStream = set.stream(); Map<String, Integer> map = new HashMap <String, Integer>(); Stream<String> keyStream = map.keySet().stream(); Stream<Integer> valueStream = map.values().stream(); Stream<Map.Entry<String, Integer>> entryStream = map.entrySet().stream(); String[] strArray = {"hello" , "world" , "java" }; Stream<String> strArrayStream = Stream.of(strArray); Stream<String> strArrayStream2 = Stream.of("hello" , "world" , "java" ); Stream<Integer> intStream = Stream.of(10 , 20 , 30 ); } }
3.2.2 中间操作 中间操作返回一个新的流,可以链式调用多个中间操作。
filter(Predicate predicate):过滤元素
map(Function<T, R> mapper):加工,每个元素处理后返回一个新的元素。
map和filter区分:filter是满足条件的留下,是对原数组的过滤;map则是对原数组的加工,映射成一对一映射的新数组。
mapToInt(ToIntFunction<? super T> mapper):返回一个 IntStream,除常规流式操作外,还可以取和、平均数等Integer的操作;
concat():连接
skip(long n):跳过n个元素
distinct():去重
sorted(比较器):排序
limit(long maxSize):只截取前maxSize个元素
filter:过滤
filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤掉空字符串,打印非空字符串。filter 的参数是 Lambda,Lambda 参数是 list 的每个元素,返回值是 Boolean,为 true 时留下。
1 2 3 List<String> list = Arrays.asList("abc" , "" , "bc" , "efg" , "abcd" , "" , "jkl" ); list.stream().filter(item -> !item.isEmpty()).forEach(System.out::println);
skip & limit:跳过、限制
1 2 3 List<String> list = Arrays.asList("abc" , "" , "bc" , "efg" , "abcd" , "" , "jkl" ); list.stream().skip(2 ).limit(2 ).forEach(System.out::println);
concat 和 distinct:连接和去重
1 2 3 Stream<String> s1 = Stream.of("a" , "b" , "c" ); Stream<String> s2 = Stream.of("b" , "c" , "d" ); Stream.concat(s1, s2).distinct().forEach(System.out::println);
sorted 比较器:
sorted() 方法返回由此流的元素组成的流,根据自然顺序排序。如:按字母序排序(sorted()参数可省,因为默认就是按字母序排序)
1 2 3 4 5 6 7 List<String> list = Arrays.asList("abc" , "" , "bc" , "efg" , "abcd" , "" , "jkl" ); list = list.stream().sorted((item1, item2) -> { return item1.compareTo(item2); }).collect(Collectors.toList()); System.out.println(list);
map
中间操作 map() 用法和 filter 类似,map 的参数是 Lambda,Lambda 参数是 list 的每个元素,返回值是加工后的 list 元素。
1 2 3 4 List<String> list = Arrays.asList("abc" , "" , "bc" , "efg" , "abcd" , "" , "jkl" ); list = list.stream().map(item -> item.toUpperCase()).collect(Collectors.toList()); System.out.println(list);
mapToInt
mapToInt 返回一个 IntStream,其中包含将给定函数应用于此流的元素的结果。IntStream 是由 Integer 元素组成的流,可以取和、平均数、排序、skip、limit、count、forEach 等。
1 2 3 4 5 6 List<String> list = Arrays.asList("10" , "20" , "30" ); list.stream().mapToInt(Integer::parseInt).forEach(System.out::println); int sum = list.stream().mapToInt(Integer::parseInt).sum();System.out.println(sum);
3.2.3 终端操作 终端操作触发流的计算,并返回一个结果或副作用。
forEach(Consumer action):对每个元素执行操作
collect(Collector<T, A, R> collector):收集流的元素到一个集合或其他类型
count():计算流中的元素数量
count : count() 方法返回此流中的元素数量。
1 2 3 List<String> list = Arrays.asList("10" , "20" , "30" ); long count = list.stream().mapToInt(Integer::parseInt).count();System.out.println(count);
forEach : forEach(IntConsumer action) 方法对此流的每个元素执行操作。
1 2 List<String> list = Arrays.asList("10" , "20" , "30" ); list.stream().mapToInt(Integer::parseInt).forEach(value -> System.out.println(value));
collect :collect(Collector<T, A, R> collector):收集流的元素到一个集合或其他类型
public static Collector toList(): 把元素收集到 List 集合中
public static Collector toSet(): 把元素收集到 Set 集合中
public static Collector toMap(Function keyMapper, Function valueMapper): 把元素收集到 Map 集合中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 List<String> list = new ArrayList <>(); list.add("123" ); list.add("4567" ); List<String> ansList = list.stream().filter(item -> item.length() == 3 ).collect(Collectors.toList()); System.out.println(ansList); List<Integer> ansList1 = list.stream().map(Integer::parseInt).collect(Collectors.toList()); System.out.println(ansList1); Set<Integer> ansList2 = list.stream().map(Integer::parseInt).collect(Collectors.toSet()); System.out.println(ansList2); Map<String, Integer> stringSizeMap = list.stream().collect(Collectors.toMap(item -> item, item -> item.length())); System.out.println(stringSizeMap); String ansString = list.stream().collect(Collectors.joining("," ));System.out.println(ansString);
4. 函数式接口 4.1 基本介绍 函数式接口是指仅包含一个抽象方法的接口,可以使用 Lambda 表达式或方法引用来创建该接口的实例。Java 8 引入了函数式接口,并在java.util.function 包中提供了许多预定义的函数式接口,例如 Function、Supplier、Consumer、Predicate 等。
函数式接口 :有且仅有一个抽象方法的接口。 Java中函数式编程体现就是Lambda表达式。
函数式接口注解 :@FunctionalInterface
如果方法的返回值是函数式接口,可以使用Lambda表达式作为结果返回。
格式 : 函数式接口对象作为一个方法的形参,实参是Lambda表达式。
常见的函数式接口 :
JDK自带一些函数式接口 :函数式接口Supplier中get获取有返回值的数据,Predicate中test返回boolean型数据,Consumer中accept无返回值数据操作。
接口
方法
作用
示例
Supplier
get(),返回各类型的数据
获取
返回数组最大值
Function
apply(),返回各类型数据
转换
数字字符串转换
Predicate
test(),返回boolean型数据
判断
判断数字是否大于5
Consumer
accept(),无返回值
操作
翻转字符串
4.2 生产者接口Supplier 作用: 获取到生产出的数据
Supplier译作生产者,生产的数据类型由泛型参数T指定。
示例: 例如生产者接口,创建一个方法,获取数组的最大值,实际的获取逻辑由Lambda表达式确认:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class Test { public static void main (String[] args) { int [] arr = {19 , 50 , 28 , 37 , 46 }; int maxValue = getMax(() -> { int max = arr[0 ]; for (int i : arr) { if (i > max) { max = i; } } return max; }); System.out.println("数组中的最大值是: " + maxValue); } private static int getMax (Supplier<Integer> sup) { return sup.get(); } }
4.3 函数式接口Consumer 作用: 对数据进行操作,无返回值。
Consumer是消费型接口,消费的数据类型由泛型指定。
代码示例: 两种方式和一种方式消费字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class Test { public static void main (String[] args) { String name = "Hello World" ; operatorString(name, str -> System.out.println("转大写:" + str.toUpperCase()), str -> System.out.println("转小写:" +str.toLowerCase())); operatorString(name, str -> System.out.println("空格替换成下划线:" + str.replace(" " , "_" ))); } private static void operatorString (String name, Consumer<String> con1, Consumer<String> con2) { System.out.println("第一个消费者消费一次" ); con1.accept(name); System.out.println("第二个消费者消费一次" ); con2.accept(name); System.out.println("第一个消费者组合第二个消费者,再组合第一个消费者,按顺序各消费一次" ); con1.andThen(con2).andThen(con1).accept(name); } private static void operatorString (String name, Consumer<String> con) { con.accept(name); } }
4.4 函数式接口Predicate Predicate接口用于表示布尔值函数,判断参数是否满足条件。它接受一个参数,并返回一个布尔值。
译作谓词,谓语。
方法签名
说明
boolean test(T t)
对给定的参数进行判断(谓词操作)。返回布尔值。
default Predicate and(Predicate<? super T> other)
返回一个组合的 Predicate,表示逻辑与(AND)操作。
default Predicate negate()
返回一个表示逻辑非(NOT)操作的 Predicate。
default Predicate or(Predicate<? super T> other)
返回一个组合的 Predicate,表示逻辑或(OR)操作。
方法的形参Predicate,接受的实参是Lambda参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class Test { public static void main (String[] args) { boolean result = checkString("hello" , s -> s.length() > 5 , s -> s.length() < 100 ); System.out.println(result); System.out.println(negateCheck("hello" , s->s.length() == 5 )); } private static boolean checkString (String s, Predicate<String> p1, Predicate<String> p2) { return p1.and(p2).test(s); } private static boolean negateCheck (String s, Predicate<String> p) { return p.negate().test(s); } }
4.5 方法引用 4.5.1 概念 方法引用跟Lambda类似,都可以根据上下文推导。格式:
4.5.2 引用实例方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 public class Test { public static void main (String[] args) { TreeSet<Dog> dogsLambda = new TreeSet <>((a, b) -> a.weight - b.weight); TreeSet<Dog> dogsMethodRef = new TreeSet <>(Test::compareDogsByWeight); dogsLambda.add(new Dog (10 , "旺财" )); dogsLambda.add(new Dog (5 , "小黑" )); dogsLambda.add(new Dog (15 , "小白" )); dogsMethodRef.add(new Dog (10 , "旺财" )); dogsMethodRef.add(new Dog (5 , "小黑" )); dogsMethodRef.add(new Dog (15 , "小白" )); System.out.println("1.使用Lambda表达式打印结果:" ); dogsLambda.forEach(dog->{ System.out.println(dog); }); System.out.println("2.使用方法引用,引用PrintStream类的println方法:" ); dogsMethodRef.forEach(System.out::println); } public static int compareDogsByWeight (Dog a, Dog b) { return a.weight - b.weight; } } public class Dog { int weight; String name; public Dog (int weight, String name) { this .weight = weight; this .name = name; } @Override public String toString () { return "Dog{" + "weight=" + weight + ", name='" + name + '\'' + '}' ; } @Override public boolean equals (Object o) { if (this == o) { return true ; } if (o == null || getClass() != o.getClass()) { return false ; } Dog dog = (Dog) o; return weight == dog.weight && Objects.equals(name, dog.name); } @Override public int hashCode () { return Objects.hash(weight, name); } }
打印结果
1.使用Lambda表达式打印结果: Dog{weight=5, name=’小黑’} Dog{weight=10, name=’旺财’} Dog{weight=15, name=’小白’} 2.使用方法引用,引用PrintStream类的println方法: Dog{weight=5, name=’小黑’} Dog{weight=10, name=’旺财’} Dog{weight=15, name=’小白’}
4.6 引用构造器 某些场景下,需要在使用时才确定创建对象的逻辑,这时就可以引用构造器。格式:
代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class Test { public static void main (String[] args) { builderLinQinXia((name, age) -> new Student (name, age)); builderZhangXueYou((name, age) -> new Student (name, age)); builderLinQinXia(Student::new ); builderZhangXueYou(Student::new ); } private static void builderLinQinXia (StudentBuilder sb) { Student s = sb.build("林青霞" , 30 ); System.out.println(s.getName() + " " + s.getAge()); } private static void builderZhangXueYou (StudentBuilder sb) { Student s = sb.build("张学友" , 26 ); System.out.println(s.getName() + " " + s.getAge()); } } class Student { private String name; private int age; public Student (String name, int age) { this .name = name; this .age = age; } public String getName () { return name; } public int getAge () { return age; } } @FunctionalInterface interface StudentBuilder { Student build (String name, int age) ; }
4.7 接口组成更新 java8后加入了默认方法、静态方法。java9后加入了私有方法。
4.7.1 接口默认方法 接口中的方法会被隐式指定为 public abstract方法,抽象方法不能有实际内容。但某些业务场景需在接口中扩展一些有业务逻辑的方法,又不想直接改成抽象类(因为抽象类只能单继承),这时,JDK8扩展了接口的默认方法,需要用default关键字修饰方法。格式 :
default 返回值 方法名(参数) {
...
}
特点:
默认方法可以有方法体
默认方法可被接口的实现类对象调用。
默认方法不是抽象方法,实现类可以重写,也可以不重写,同名冲突时必须重写(某个类实现了多个包含默认方法fun()的接口,为了防止冲突,此时实现类必须重写这个类)。
示例:
1 2 3 4 5 6 7 8 9 public interface MyInterface { void abstractMethod () ; default void defaultMethod () { System.out.println("这是接口的默认方法" ); } }
4.7.2 接口静态方法 在 Java 8 中,引入了接口静态方法。接口静态方法与类静态方法类似,但它们属于接口本身,而不是接口的实现类。静态方法常用于在接口中提供静态工具方法,帮助操作或处理与接口相关的数据。格式 与类的静态方法一致:
static 返回类型 方法名(参数列表) {
// 方法体
}
特点 :
命名冲突时要重写:因为Java是单继承多实现的,所以存在一个类实现多个接口的情况。如果一个类同时实现了多个接口,并且这些接口都有相同签名的默认方法,则必须在实现类中重写该方法以解决冲突。例如类A实现了有同名静态方法的接口B、C,则A的对象分不清调用哪个接口的方法。
扩展接口功能:默认方法允许在不破坏现有实现的情况下扩展接口功能,对现有功能影响较小,符合设计模式中的开闭原则。
接口中静态方法跟类的静态方法,属于“类方法”,先于对象产生,所以只能被接口名调用,不能被实现类对象调用。
示例 :
1 2 3 4 5 6 public interface MyInterface { static void staticMethod () { System.out.println("这是接口的静态方法" ); } }
4.7.3 JDK9接口私有方法 接口中的方法会被隐式的指定为 public abstract方法。为了将接口中多个默认或静态方法中的共性方法抽离出来,JDK9引入了接口私有方法。接口私有方法只能在接口内部,被接口静态方法或者接口默认方法调用,不能在接口外部或实现类中调用。格式 :
1 2 3 4 5 6 7 private 返回类型 方法名(参数列表) { } private static 返回类型 方法名(参数列表) { }
特点 :
示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class Dog implements Animal { public static void main (String[] args) { Dog dog = new Dog (); dog.eat(); Animal.staticMethod(); } } public interface Animal { default void eat () { System.out.println("动物在吃东西" ); privateSoundMethod(); } private void privateSoundMethod () { System.out.println("这是私有实例方法,接口内私有、静态、默认方法都可以调用它:发出声音" ); } static void staticMethod () { System.out.println("静态方法调用私有静态方法" ); privateStaticMethod(); } private static void privateStaticMethod () { System.out.println("这是私有静态方法,它只能被接口中的静态方法调用" ); } }
运行结果:
静态方法调用私有静态方法 这是私有静态方法,它只能被接口中的静态方法调用 动物在吃东西 这是私有实例方法,接口内私有、静态、默认方法都可以调用它:发出声音
Java11 新特性 原文链接:https://blog.csdn.net/qq_43947876/article/details/148399400
一、标准化HTTP Client:告别HttpURLConnection 1.1 HttpURLConnection 的痛点 在 Java 11 之前,开发者主要使用 HttpURLConnection 处理 HTTP 请求,但存在严重缺陷:
设计陈旧 :
功能缺失 :
不支持 HTTP/2。
缺乏异步处理能力。
无内置的 WebSocket 支持。
难以处理 cookie 和重定向。
代码冗长 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 URL url = new URL ("https://api.example.com" );HttpURLConnection conn = (HttpURLConnection) url.openConnection();conn.setRequestMethod("GET" ); int status = conn.getResponseCode(); if (status == 200 ) { try (BufferedReader in = new BufferedReader ( new InputStreamReader (conn.getInputStream()))) { String line; StringBuilder content = new StringBuilder (); while ((line = in.readLine()) != null ) { content.append(line); } System.out.println(content); } } else { } conn.disconnect();
1.2 标准化 HTTP Client 的解决方案 核心设计原理:
Java 11 的标准化 HTTP Client 采用分层异步架构,核心通过 协议协商机制 自动选择最佳协议(优先尝试 HTTP/2,失败时降级到 HTTP/1.1),利用 多路复用技术 在单个 TCP 连接上并行处理多个请求,通过 响应式流处理模型 实现非阻塞 I/O 操作。其内部基于 CompletableFuture 实现异步处理引擎,配合智能 连接池管理 减少连接建立开销,同时通过 类型安全的 BodyHandler/BodyPublisher 抽象层实现请求/响应体的灵活转换,最终解决了传统 HttpURLConnection 的同步阻塞、协议支持不足和 API 臃肿三大痛点,为现代网络编程提供了高性能、可扩展的标准解决方案。
1.3 实战应用指南 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 HttpClient client = HttpClient.newBuilder() .version(HttpClient.Version.HTTP_2) .connectTimeout(Duration.ofSeconds(10 )) .followRedirects(HttpClient.Redirect.ALWAYS) .authenticator(Authenticator.getDefault()) .build(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com/users" )) .header("Content-Type" , "application/json" ) .header("Authorization" , "Bearer token" ) .timeout(Duration.ofSeconds(15 )) .GET() .build(); HttpResponse<String> response = client.send( request, HttpResponse.BodyHandlers.ofString() ); System.out.println("状态码: " + response.statusCode()); System.out.println("响应体: " + response.body()); client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(HttpResponse::body) .thenAccept(body -> { System.out.println("异步响应: " + body); }) .exceptionally(e -> { System.err.println("请求失败: " + e.getMessage()); return null ; }); String jsonBody = "{\"name\":\"John\", \"age\":30}" ;HttpRequest postRequest = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com/users" )) .header("Content-Type" , "application/json" ) .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) .build(); HttpRequest fileUpload = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com/upload" )) .header("Content-Type" , "multipart/form-data" ) .POST(HttpRequest.BodyPublishers.ofFile(Paths.get("data.txt" ))) .build(); WebSocket webSocket = HttpClient.newHttpClient() .newWebSocketBuilder() .buildAsync(URI.create("wss://echo.websocket.org" ), new WebSocket .Listener() { @Override public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) { System.out.println("收到消息: " + data); return null ; } @Override public void onOpen (WebSocket webSocket) { webSocket.sendText("Hello Server!" , true ); } }).join();
1.4 使用建议 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 .timeout(Duration.ofSeconds(10 )) .connectTimeout(Duration.ofSeconds(5 )) HttpResponse<Path> response = client.send( request, HttpResponse.BodyHandlers.ofFile(Paths.get("output.txt" )) ); HttpResponse<InputStream> streamResponse = client.send( request, HttpResponse.BodyHandlers.ofInputStream() ); try { HttpResponse<String> response = client.send(...); } catch (IOException | InterruptedException e) { } catch (HttpTimeoutException e) { }
1.5 完整 HTTP Client 使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class AdvancedHttpClientExample { private static final HttpClient CLIENT = HttpClient.newHttpClient(); public CompletableFuture<JsonObject> fetchUserData (String userId) { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.example.com/users/" + userId)) .header("Accept" , "application/json" ) .timeout(Duration.ofSeconds(8 )) .build(); return CLIENT.sendAsync(request, HttpResponse.BodyHandlers.ofString()) .thenApply(response -> { if (response.statusCode() == 200 ) { return parseJson(response.body()); } else { throw new RuntimeException ("HTTP Error: " + response.statusCode()); } }); } private JsonObject parseJson (String body) { return ...; } }
1.6 总结 Java 11 的标准化 HTTP Client 解决了传统网络编程的三大痛点:
协议落后 → 支持 HTTP/2 和 WebSocket
性能低下 → 异步非阻塞 + 连接复用
API 繁琐 → 链式调用 + 响应式处理
二、局部变量类型推断增强:Lambda中的var 先说一下什么是java中的var类型,Java 中的 var 是 JDK 10 引入的局部变量类型推断关键字,允许编译器根据赋值语句右侧的表达式自动推断变量类型,从而简化代码编写。
2.1 解决的问题:类型声明的一致性困境 在 Java 10 引入 var 后,开发者面临一个矛盾:
1 2 3 4 5 6 var list = new ArrayList <String>(); (var s) -> s.length() (s) -> s.length()
这种不一致性就导致了:
代码风格割裂 :普通变量和 Lambda 参数使用不同规则。
注解无法应用 :无法给隐式类型参数添加注解。
可读性降低 :复杂 Lambda 难以理解参数类型。
2.2 实现原理:编译器的类型推导增强 Java 11 通过 JEP 323 扩展了编译器的类型推导能力:
这种方式根据方法签名推导参数类型,通过函数式接口传递类型信息并且允许在 var 上添加注解。 编译过程 :
1 2 3 4 5 6 7 Function<String, Integer> len = (var s) -> s.length(); 1. 根据左侧 Function<String, Integer> 确定目标类型2. 解析 var s → 推导为 String 类型3. 验证 s.length() 返回 int (兼容 Integer)
编译器处理步骤 :
词法分析 :识别 var 关键字
语法树构建 :创建带 var 的 Lambda 节点
类型绑定 :
从赋值上下文获取目标类型
解析函数式接口的泛型参数
将 var 绑定到具体类型
注解附加 :将参数注解关联到具体类型
2.3 实战应用指南 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Function<String, Integer> lengthFunc = (@NonNull var str) -> str.length(); Function<String, Integer> oldFunc = str -> str.length(); BiFunction<Integer, Double, String> format = (var num, var dec) -> String.format("%d-%.2f" , num, dec); BiFunction<Integer, Double, String> explicit = (Integer num, Double dec) -> ...; List<Object> mixedList = Arrays.asList("Text" , 42 , 3.14 ); mixedList.forEach((var obj) -> { if (obj instanceof String) { System.out.println(((String) obj).toUpperCase()); } });
适用场景:
1 2 3 4 5 6 7 8 9 10 (var @Email email) -> validate(email) Map<String, List<Map<Integer, Set<String>>>> complex = ...; complex.forEach((var key, var value) -> ...); (var userId, var timestamp) -> process(userId, timestamp)
禁用场景:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var lambda = (var x) -> x * 2 ; (var x, y) -> x + y Function<Number, String> func = (var n) -> n.toString(); Consumer<String> consumer = (var n) -> System.out.println(n); Object ambiguous = (var n) -> n.toString();
2.4 终极示例:结合注解和复杂类型 Java 11 的这项改进并非鼓励在所有 Lambda 中使用 var,而是提供选择性显式类型声明的能力,在保持类型安全的同时增加灵活性。
1 2 3 4 5 6 7 8 9 10 11 12 13 public class UserProcessor { public void processUsers (List<@Valid User> users) { users.forEach((var user) -> { @NonEmpty String name = validateName(user.getName()); sendWelcomeEmail(user.getEmail()); }); } private String validateName (@NonEmpty String name) { if (name.isBlank()) throw new IllegalArgumentException (); return name.strip(); } }
三、文件读写简化 3.1 文件操作的”样板代码地狱” 在 Java 11 之前,读写文件需要大量重复代码,如下示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Path path = Paths.get("demo.txt" );String content; try (BufferedReader reader = Files.newBufferedReader(path)) { StringBuilder sb = new StringBuilder (); String line; while ((line = reader.readLine()) != null ) { sb.append(line).append("\n" ); } content = sb.toString(); } catch (IOException e) { } List<String> lines = Arrays.asList("Line1" , "Line2" ); try (BufferedWriter writer = Files.newBufferedWriter(path)) { for (String line : lines) { writer.write(line); writer.newLine(); } } catch (IOException e) { }
传统方式存在几大痛点:
代码冗长 :简单操作需要10+行代码
资源管理复杂 :必须显式关闭流(忘记关闭会导致资源泄漏)
异常处理繁琐 :必须处理 IOException
字符集问题 :默认使用平台编码,跨平台可能乱码
3.2 实现原理:智能封装与最佳实践 Java 11 通过 Files 类新增方法实现简化:
1 2 3 4 5 6 7 8 9 10 11 12 public static String readString (Path path) throws IOException { return readString(path, StandardCharsets.UTF_8); } public static Path writeString (Path path, CharSequence csq, OpenOption... options) throws IOException { try (BufferedWriter writer = newBufferedWriter(path, UTF_8, options)) { writer.write(csq.toString()); } return path; }
关键技术原理 :
自动资源管理 : 使用 try-with-resources 确保流自动关闭
智能缓冲 : 内部使用 BufferedWriter/BufferedReader 优化性能
字符集安全 : 默认 UTF-8 解决跨平台乱码问题
异常透明 : 保留必要的 IOException 传播
3.3 实战应用指南 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 Path file = Path.of("data.txt" );Files.writeString(file, "Hello Java 11!" ); Files.writeString(file, "\n追加内容" , StandardOpenOption.APPEND); String content = Files.readString(file);System.out.println(content); Files.writeString(file, "日本語テキスト" , StandardCharsets.UTF_8); String jpText = Files.readString(file, StandardCharsets.UTF_8);Files.writeString(file, "新内容" , StandardOpenOption.CREATE, StandardOpenOption.APPEND); Files.writeString(file, "独占内容" , StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW); try { String config = Files.readString(Path.of("config.cfg" )); } catch (NoSuchFileException e) { System.err.println("配置文件不存在: " + e.getFile()); } catch (AccessDeniedException e) { System.err.println("无访问权限: " + e.getFile()); } catch (IOException e) { System.err.println("系统IO错误: " + e.getMessage()); }
高级应用场景
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 WatchService watcher = FileSystems.getDefault().newWatchService();Path confDir = Path.of("config" );confDir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY); while (true ) { WatchKey key = watcher.take(); for (WatchEvent<?> event : key.pollEvents()) { if (event.context().toString().equals("app.conf" )) { reloadConfig(confDir.resolve("app.conf" )); } } key.reset(); } private void reloadConfig (Path configFile) throws IOException { String newConfig = Files.readString(configFile); } List<Path> textFiles = Files.list(Path.of("docs" )) .filter(p -> p.toString().endsWith(".txt" )) .toList(); textFiles.parallelStream() .map(p -> { try { return Files.readString(p); } catch (IOException e) { return "" ; } }) .filter(text -> text.contains("Java 11" )) .forEach(content -> processContent(content)); String template = Files.readString(Path.of("template.html" ));Map<String, String> variables = Map.of( "${name}" , "张三" , "${email}" , "zhangsan@example.com" ); for (Map.Entry<String, String> entry : variables.entrySet()) { template = template.replace(entry.getKey(), entry.getValue()); } Files.writeString(Path.of("output.html" ), template);
性能优化与注意事项
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 Path largeFile = Path.of("huge.log" );long size = Files.size(largeFile);if (size > 100 * 1024 * 1024 ) { try (Stream<String> lines = Files.lines(largeFile)) { lines.filter(line -> line.contains("ERROR" )) .forEach(System.err::println); } } else { String content = Files.readString(largeFile); } public Charset detectCharset (Path file) throws IOException { byte [] bom = new byte [4 ]; try (InputStream is = Files.newInputStream(file)) { is.read(bom); } if (bom[0 ] == (byte ) 0xEF && bom[1 ] == (byte ) 0xBB && bom[2 ] == (byte ) 0xBF ) { return StandardCharsets.UTF_8; } else if (bom[0 ] == (byte ) 0xFE && bom[1 ] == (byte ) 0xFF ) { return StandardCharsets.UTF_16BE; } else { return StandardCharsets.UTF_8; } }
3.4 终极示例:完整的配置加载器 Java 11的Files API通过readString()和writeString()方法,用单行代码彻底简化了文件读写操作,自动处理资源关闭、字符编码(默认UTF-8)和缓冲优化,解决了传统IO冗长的样板代码问题,使文本文件操作变得直观高效,适用于配置加载、日志处理等常见场景,虽对超大文件略有性能损耗,但显著提升了开发效率和代码可维护性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class ConfigLoader { private final Path configPath; private Map<String, String> settings = new HashMap <>(); public ConfigLoader (String filename) { this .configPath = Path.of("conf" , filename); } public void load () throws IOException { String content = Files.readString(configPath, StandardCharsets.UTF_8); content.lines() .filter(line -> !line.startsWith("#" ) && !line.isBlank()) .map(line -> line.split("=" , 2 )) .forEach(parts -> { if (parts.length == 2 ) { settings.put(parts[0 ].strip(), parts[1 ].strip()); } }); } public void save () throws IOException { StringBuilder sb = new StringBuilder ("# 自动生成的配置\n" ); settings.forEach((k, v) -> sb.append(k).append("=" ).append(v).append("\n" )); Files.writeString(configPath, sb.toString(), StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); } }
四、ZGC 与 Epsilon 4.1 痛点问题 传统 GC 的局限性:
STW 停顿时间过长 :
CMS/G1 在 TB 级堆内存下停顿可达秒级
无法满足金融交易、实时系统等低延迟需求
内存回收效率问题 :
特殊场景缺失 :
4.2 ZGC:亚毫秒级停顿的突破 核心原理 :
ZGC的核心原理是通过并发着色指针和读屏障技术实现亚毫秒级停顿:
着色指针在64位地址中嵌入元数据(标记/重映射状态),使GC线程能并发标记对象;
读屏障在应用线程访问对象时即时修复指针引用,实现堆压缩与标记的并发执行;
全阶段并发(标记/转移/重定位)仅需<1ms的STW根扫描,使停顿时间与堆大小无关。 其本质是以空间换时间(保留内存屏障开销)和以CPU换延迟(并发处理),适用于TB级堆内存的低延迟场景。
ZGC 发展路线 :
Java 15:正式生产可用
Java 17:分代 ZGC (减少内存开销)
Java 21:弹性元空间 (减少 native 内存)
4.3 Epsilon:无操作 GC Epsilon GC(无操作垃圾收集器)的核心原理是只分配内存,不回收内存,通过彻底消除GC开销来实现极致性能:
内存分配 :使用bump-the-pointer线性分配和TLAB(线程本地缓冲)快速分配对象
内存不回收 :完全跳过标记/清除/压缩等回收阶段,堆耗尽时直接OOM
零开销 :无GC线程、无写屏障、无内存扫描,CPU利用率接近100%
设计哲学 :用内存换性能,适合短期任务和性能基准测试,但需确保应用生命周期内堆不耗尽。
4.4 实战应用指南 ZGC 启用与调优:
1 2 3 4 5 6 7 8 9 10 java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -jar app.jar java -XX:+UseZGC \ -Xmx16g \ -XX:ConcGCThreads=4 \ -XX:ZAllocationSpikeTolerance=5 \ -Xlog:gc*:file=gc.log \ -jar trading-system.jar
Epsilon 使用场景:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 java -XX:+UnlockExperimentalVMOptions \ -XX:+UseEpsilonGC \ -Xmx1g \ -jar benchmark.jar java -XX:+UseEpsilonGC \ -Xmx128m \ -jar lambda-function.jar java -XX:+UseEpsilonGC \ -XX:+HeapDumpOnOutOfMemoryError \ -Xmx100m \ -jar memory-test.jar
4.5 总结 ZGC、Epsilon和G1的选型核心在于权衡延迟、内存与吞吐需求 : ZGC凭借并发着色指针实现亚毫秒级停顿,适合TB级堆内存的低延迟场景(如金融交易);Epsilon彻底放弃垃圾回收,以零GC开销服务于短期任务和性能测试;而G1作为Java默认收集器,通过分Region混合回收平衡吞吐与延迟(200ms内),是通用服务的最佳选择。三者分别覆盖了极致延迟、无GC干扰和通用稳定的三大技术象限,开发者需根据堆大小、任务生命周期和延迟要求精准匹配。
Java17 新特性 原文链接:https://cloud.tencent.com/developer/article/2475140
Java 17是Java编程语言的最新版本,于2021年9月14日发布。以下是Java 17的一些新特性:
Sealed类和接口 :Sealed类和接口限制了继承和实现的范围,在编译时提供更强的封装性。
Pattern匹配 :Pattern匹配简化了对实例进行类型检查和转换的流程,使代码更加简洁和易读。
垃圾收集器(G1)的改进 :Java 17对G1垃圾收集器进行了改进,包括改进了内存分配、暂停时间优化和垃圾回收性能等方面。
Oracle数据库 连接的改进 :Java 17引入了一个新的API,使开发人员可以更轻松地与Oracle数据库进行连接和交互。
嵌套的JVM标签 :Java 17支持在字节码层面上为代码添加标签,以便在运行时进行检查和验证。
私有嵌套接口 :Java 17允许在接口内部定义私有嵌套接口,以实现更好的封装性和模块化。
静态成员类型引用 :Java 17允许使用静态成员类型引用,以简化代码并提高可读性。
UNIX域套接字通道 :Java 17引入了对UNIX域套接字通道的支持,允许Java程序通过UNIX套接字与本地进程进行通信。
原文链接:https://blog.csdn.net/m0_53548081/article/details/147604067
1. 密封类(Sealed Classes) 密封类允许开发者精确控制哪些类可以继承或实现一个类或接口,增强了Java的封装性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 public sealed interface Shape permits Circle, Rectangle, Triangle { double area () ; } public final class Circle implements Shape { private final double radius; public Circle (double radius) { this .radius = radius; } @Override public double area () { return Math.PI * radius * radius; } } public final class Rectangle implements Shape { private final double width; private final double height; public Rectangle (double width, double height) { this .width = width; this .height = height; } @Override public double area () { return width * height; } } public final class Triangle implements Shape { private final double base; private final double height; public Triangle (double base, double height) { this .base = base; this .height = height; } @Override public double area () { return 0.5 * base * height; } } public static String getShapeDescription (Shape shape) { return switch (shape) { case Circle c -> "圆形,面积: " + c.area(); case Rectangle r -> "矩形,面积: " + r.area(); case Triangle t -> "三角形,面积: " + t.area(); }; }
2.记录类(Records) Records为创建不可变数据传输对象(DTO)提供了简洁的语法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 public class PersonTraditional { private final String name; private final int age; public PersonTraditional (String name, int age) { this .name = name; this .age = age; } public String getName () { return name; } public int getAge () { return age; } @Override public boolean equals (Object o) { if (this == o) return true ; if (o == null || getClass() != o.getClass()) return false ; PersonTraditional that = (PersonTraditional) o; return age == that.age && Objects.equals(name, that.name); } @Override public int hashCode () { return Objects.hash(name, age); } @Override public String toString () { return "PersonTraditional{name='" + name + "', age=" + age + '}' ; } } public record Person (String name, int age) { public boolean isAdult () { return age >= 18 ; } public Person { if (age < 0 ) { throw new IllegalArgumentException ("Age cannot be negative" ); } } } public class RecordsExample { public static void main (String[] args) { Person person = new Person ("张三" , 30 ); System.out.println("姓名: " + person.name()); System.out.println("年龄: " + person.age()); System.out.println("是否成年: " + person.isAdult()); var userInfo = getUserInfo(); processUserData(userInfo.username(), userInfo.email()); } private static UserInfo getUserInfo () { return new UserInfo ("admin" , "admin@example.com" ); } private static void processUserData (String username, String email) { System.out.println("处理用户: " + username + ", 邮箱: " + email); } } record UserInfo (String username, String email) {}
3. 模式匹配for instanceof Java 17改进了instanceof运算符,使其能够同时进行类型检查和类型转换。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public String getDescriptionTraditional (Object obj) { if (obj instanceof String) { String s = (String) obj; return "字符串,长度: " + s.length(); } else if (obj instanceof Integer) { Integer i = (Integer) obj; return "整数: " + i; } else { return "未知类型" ; } } public String getDescription (Object obj) { if (obj instanceof String s) { return "字符串,长度: " + s.length(); } else if (obj instanceof Integer i) { return "整数: " + i; } else { return "未知类型" ; } } public void processShape (Object obj) { if (obj instanceof Rectangle r) { System.out.println("矩形面积: " + r.area()); } else if (obj instanceof Circle c && c.area() > 100 ) { System.out.println("大型圆形,面积: " + c.area()); } }
4. Switch表达式增强 Java 17继承了Java 14引入的Switch表达式,与模式匹配结合使用更加强大。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public String getTypeDescription (Object obj) { return switch (obj) { case String s -> "字符串,内容: " + s; case Integer i -> "整数: " + i; case Long l -> "长整型: " + l; case Double d -> "双精度: " + d; case null -> "空值" ; default -> "其他类型" ; }; } public String analyzePerson (Person person) { return switch (person) { case Person p when p.age() < 18 -> p.name() + " 是未成年人" ; case Person p when p.age() >= 18 && p.age() < 65 -> p.name() + " 是成年人" ; case Person p -> p.name() + " 是老年人" ; }; }
5. 文本块(Text Blocks) 文本块提供了更好的多行字符串表示方式,特别适合SQL、HTML等内容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class TextBlocksExample { public static void main (String[] args) { String oldHtml = "<html>\n" + " <body>\n" + " <p>Hello, World!</p>\n" + " </body>\n" + "</html>" ; String html = """ <html> <body> <p>Hello, World!</p> </body> </html> """ ; String query = """ SELECT id, name, email FROM users WHERE status = 'active' AND last_login > DATE_SUB(NOW(), INTERVAL 30 DAY) ORDER BY name ASC """ ; String json = """ { "name": "张三", "age": 30, "address": { "city": "北京", "district": "海淀" }, "skills": ["Java", "Spring", "Kubernetes"] } """ ; } }
6. 新的随机数生成器API Java 17引入了强大的随机数生成器API,提供了更多算法选择和更好的性能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java.util.random.RandomGenerator;import java.util.random.RandomGeneratorFactory; public class RandomGeneratorExample { public static void main (String[] args) { RandomGenerator defaultRandom = RandomGenerator.getDefault(); System.out.println("随机整数: " + defaultRandom.nextInt(100 )); RandomGenerator xoroshiro = RandomGeneratorFactory.of("Xoroshiro128PlusPlus" ) .create(42 ); xoroshiro.ints(10 , 1 , 100 ) .forEach(n -> System.out.print(n + " " )); System.out.println("\n可用随机数生成器算法:" ); RandomGeneratorFactory.all() .map(factory -> factory.name()) .sorted() .forEach(System.out::println); } }
7. 强封装JDK内部API Java 17进一步强化了JDK内部API的封装,这需要开发者更加关注公共API的使用。
1 2 3 4 5 6 7 8 9 try { Class<?> sunClass = Class.forName("sun.misc.Unsafe" ); } catch (ClassNotFoundException | IllegalAccessException e) { System.out.println("无法访问内部API: " + e.getMessage()); }
8. 实际业务应用案例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 public sealed interface Product permits Electronics, Clothing, Book { String getId () ; String getName () ; double getPrice () ; } public record Electronics (String id, String name, double price, String brand, int warrantyMonths) implements Product {} public record Clothing (String id, String name, double price, String size, String material) implements Product {} public record Book (String id, String name, double price, String author, String isbn) implements Product {} public class ProductProcessor { public String generateProductDescription (Product product) { return switch (product) { case Electronics e -> String.format("%s - %s, 保修期: %d个月" , e.name(), e.brand(), e.warrantyMonths()); case Clothing c -> String.format("%s - 尺码: %s, 材质: %s" , c.name(), c.size(), c.material()); case Book b -> String.format("%s - 作者: %s, ISBN: %s" , b.name(), b.author(), b.isbn()); }; } public double calculateTax (Product product) { return switch (product) { case Electronics e when e.price() > 10000 -> e.price() * 0.2 ; case Electronics e -> e.price() * 0.15 ; case Clothing c -> c.price() * 0.1 ; case Book b -> b.price() * 0.05 ; }; } } public class ShoppingCart { private final List<Product> items = new ArrayList <>(); public void addItem (Product product) { items.add(product); } public double calculateTotal () { return items.stream().mapToDouble(Product::getPrice).sum(); } public double calculateTotalWithTax () { ProductProcessor processor = new ProductProcessor (); return items.stream().mapToDouble(p -> p.getPrice() + processor.calculateTax(p)).sum(); } public String getReceipt () { ProductProcessor processor = new ProductProcessor (); StringBuilder builder = new StringBuilder (); builder.append(""" ===== 购物小票 ===== 日期: %s 商品列表: """ .formatted(LocalDate.now())); items.forEach(item -> builder.append("- %s: %.2f 元 (税: %.2f 元)\n" .formatted(item.getName(), item.getPrice(), processor.calculateTax(item))) ); builder.append(""" ---------------- 总计: %.2f 元 含税总价: %.2f 元 ================ """ .formatted(calculateTotal(), calculateTotalWithTax())); return builder.toString(); } } public class ProductSystemDemo { public static void main (String[] args) { Product laptop = new Electronics ("E001" , "MacBook Pro" , 12999.0 , "Apple" , 24 ); Product tshirt = new Clothing ("C001" , "纯棉T恤" , 199.0 , "XL" , "棉" ); Product javaBook = new Book ("B001" , "Java编程思想" , 108.0 , "Bruce Eckel" , "978-7111213826" ); ShoppingCart cart = new ShoppingCart (); cart.addItem(laptop); cart.addItem(tshirt); cart.addItem(javaBook); System.out.println(cart.getReceipt()); Product randomProduct = getRandomProduct(laptop, tshirt, javaBook); String analysisResult = switch (randomProduct) { case Electronics e when e.price() > 10000 -> "高端电子产品" ; case Electronics e -> "普通电子产品" ; case Clothing c when "棉" .equals(c.material()) -> "纯棉服装" ; case Clothing c -> "其他材质服装" ; case Book b -> "图书类产品" ; }; System.out.println("随机商品分析: " + analysisResult); } private static Product getRandomProduct (Product... products) { return products[RandomGenerator.getDefault().nextInt(products.length)]; } }
9. 总结 Java 17的新特性为开发者提供了更多优雅高效的编程工具:
密封类 :增强了类型系统,提供了更好的封装性和编译时安全性
记录类 :极大简化了数据传输对象的编写
**模式匹配for instanceof**:简化了类型检查和转换操作
Switch表达式增强 :使分支逻辑更简洁清晰
文本块 :大幅改进了多行字符串的处理
新的随机数API :提供了更丰富的随机数生成工具
强封装JDK内部API :鼓励使用公共API,提高代码稳定性
这些新特性不仅提高了代码的简洁性和可读性,还增强了Java语言的表达能力和安全性。结合实际业务场景使用这些特性,可以编写出更优雅、更健壮的Java应用程序。