Osmanthus

空想具現化


  • 首页
  • 归档
  • 分类
  • 标签
  • 关于
  •   

© 2024 Homurax

UV: | PV:

Theme Typography by Makito

Proudly published with Hexo

Java 17 新特性(9 ~ 17)

发布于 2024-05-09 Java  Feature 

Java 9

Stream.takeWhile

使用一个断言作为参数,返回给定 Stream 的子集直到断言语句第一次返回 false。
可以用于有序流中获取第一个不满足条件之前的元素。

// 1 2
Stream.of(1, 2, 3, 4, 5).takeWhile(x -> x < 3).forEach(System.out::println);

Stream.dropWhile

使用一个断言作为参数,直到断言语句第一次返回 false 才返回给定 Stream 的子集。
适用于有序流中获取从第一个不满足条件的元素开始的元素。

// 3 4 5
Stream.of(1, 2, 3, 4, 5).dropWhile(x -> x < 3).forEach(System.out::println);

IntStream.iterate

使用初始种子值创建顺序流。

// 3 6 9
IntStream.iterate(3, x -> x < 10, x -> x + 3).forEach(System.out::println);

Collectors.flatMapping

Set<Integer> set = Stream.of("a", "ab", "abc").collect(Collectors.flatMapping(v -> v.chars().boxed(), Collectors.toSet()));

Java 11

HttpClient

GET

public void get() throws ExecutionException, InterruptedException {  
    String url = "https://www.githubstatus.com/api/v2/status.json";  
    HttpRequest httpRequest = HttpRequest.newBuilder()  
            .uri(URI.create(url))  
            .header("Content-Type", "application/x-www-form-urlencoded")  
            .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36")  
            .GET()  
            .build();  
    // 异步  
    String responseBody = HttpClient.newHttpClient()  
            .sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())  
            .thenApply(HttpResponse::body)  
            .thenApply(Object::toString)  
            .get();  
    System.out.println(responseBody);  
}

GET 带有查询参数

public void getQuery() throws IOException, InterruptedException {  
    String url = "https://caniuse.com/process/query.php";  

    Map<String, String> queryMap = Maps.newHashMap();  
    queryMap.put("search", "encodeURIComponent");  
    // cn.hutool.core.util.URLUtil;
    String query = URLUtil.buildQuery(queryMap, StandardCharsets.UTF_8);  
    if (query != null) {  
        url += "?" + query;  
    }  

    String[] headers = {  
            "Content-Type",  
            "application/x-www-form-urlencoded",  
            "User-Agent",  
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"  
    };  

    HttpRequest httpRequest = HttpRequest.newBuilder()  
            .uri(URI.create(url))  
            .headers(headers)  
            .GET()  
            .build();  

    // 同步  
    HttpResponse<String> response = HttpClient.newHttpClient().send(httpRequest, HttpResponse.BodyHandlers.ofString());  
    System.out.println(response.statusCode());  
    System.out.println(response.body());  
}

POST

public void post() throws ExecutionException, InterruptedException {  
    String url = "https://example.com";  

    Map<String, String> queryMap = Maps.newHashMap();  
    queryMap.put("key", "value");  
    String query = URLUtil.buildQuery(queryMap, StandardCharsets.UTF_8);  

    HttpRequest httpRequest = HttpRequest.newBuilder()  
            .uri(URI.create(url))  
            .header("Content-Type", "application/x-www-form-urlencoded")  
            .POST(HttpRequest.BodyPublishers.ofString(query, StandardCharsets.UTF_8))  
            .build();  
    String response = HttpClient.newHttpClient()  
            .sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())  
            .thenApply(HttpResponse::body)  
            .thenApply(Object::toString)  
            .get();  
    System.out.println(response);  
}

POST JSON

public void postJson() throws ExecutionException, InterruptedException {  
    String url = "https://example.com";  

    String jsonStr = JSONUtil.toJsonStr(Maps.newHashMap());  

    HttpRequest httpRequest = HttpRequest.newBuilder()  
            .uri(URI.create(url))  
            .header("Content-Type", "application/json")  
            .POST(HttpRequest.BodyPublishers.ofString(jsonStr, StandardCharsets.UTF_8))  
            .build();  
    String response = HttpClient.newHttpClient()  
            .sendAsync(httpRequest, HttpResponse.BodyHandlers.ofString())  
            .thenApply(HttpResponse::body)  
            .thenApply(Object::toString)  
            .get();  
    System.out.println(response);  
}

Java 14

switch 表达式增强

引入了对 lambda 语法的支持,并且可以忽略每个 case 后的 break,同时提供了 yield 来在 block 中返回值。

for (int i = 0; i < 10; i++) {  
    int flag = RandomUtil.randomInt(1, 50);  
    switch (flag) {  
        case 1 -> System.out.println("case 1");  
        case 2 -> System.out.println("case 2");  
        case 3 -> System.out.println("case 3");  
        case 4 -> System.out.println("case 4");  
        default -> System.out.println("case default");  
    }  
}

for (int i = 0; i < 10; i++) {  
    int day = RandomUtil.randomInt(1, 15);  
    String result = switch (day) {  
        case 1, 2, 3 -> "123";  
        case 4, 5, 6 -> "456";  
        default -> {  
            if (day > 7) {  
                yield "Please insert a valid day.";  
            } else {  
                yield "Looks like a Sunday.";  
            }  
        }  
    };  
    System.out.println(result);  
}

Java 15

隐藏类

引入隐藏类的主要目的是给框架来使用,使得框架可以在运行时生成类,并通过反射间接使用它们。

public class HiddenClass {  
    public static String hello() {  
        return "https://blog.homurax.com/";  
    }  
}

public void test() throws Throwable {
    String filePath = "target/classes/com/homurax/feature/HiddenClass.class";  
    byte[] bytes = Files.readAllBytes(Paths.get(filePath));  
    String CLASS_INFO = Base64.getEncoder().encodeToString(bytes);  
    System.out.println(CLASS_INFO);  
    // 通过反射加载上面生成的类,并调用隐藏类中的 hello
    byte[] classInBytes = Base64.getDecoder().decode(CLASS_INFO);  
    Class<?> proxy = MethodHandles.lookup()  
            // 创建普通类是用 ClassLoader::defineClass        
            // bytes:符合 Java 虚拟机规范的字节码  
            // initialize:是否要初始化类  
            // options:Java 类的类型,详见 java.lang.invoke.MethodHandles.Lookup.ClassOption        
            .defineHiddenClass(classInBytes, true, MethodHandles.Lookup.ClassOption.NESTMATE)  
            .lookupClass();  
    // 类名  
    System.out.println(proxy.getName());  
    // 方法  
    for (Method method : proxy.getDeclaredMethods()) {  
        System.out.println(method.getName());  
    }  
    // 调用  
    MethodHandle mh = MethodHandles.lookup().findStatic(proxy, "hello", MethodType.methodType(String.class));  
    String result = (String) mh.invokeExact();  
    System.out.println(result);
}

Java 16

Record 类

可以单独文件声明、在类内部声明、方法内声明。
Record 类是一个 final 类,其自动实现 equals、hashCode、toString 方法,成员变量均为 public。

record Rectangle(int length, int width) {  
    // 自定义成员方法  
    public int area() {  
        return Rectangle.this.length * Rectangle.this.width;  
    }  
}  

Rectangle rectangle = new Rectangle(700, 300);  
System.out.println(rectangle.length);  
System.out.println(rectangle.width);  
System.out.println(rectangle.area());  
System.out.println(rectangle);  
System.out.println(rectangle.equals(new Rectangle(700, 300)));

instanceof 增强

for (Object obj : new Object[]{"test", 10}) {  
    if (obj instanceof String s) {  
        System.out.println(s.toUpperCase());  
    } else if (obj instanceof Integer n) {  
        System.out.println(n * n);  
    }  
}

Stream.toList

List<Character> characters = Stream.of('a', 'b', 'c').toList();

注意创建的是一个 unmodifiableList。

// Stream.java
default List<T> toList() {  
    return (List<T>) Collections.unmodifiableList(new ArrayList<>(Arrays.asList(this.toArray())));  
}

Java 17

Sealed Classes

密封类可以对继承或者实现它们的类进行限制,这样这个类就只能被指定的类继承。

密封类必须有子类,密封类不支持匿名类与函数式接口。
permits 指定了 Animal 只允许 Cat 和 Dog 继承。
如果允许扩展的子类和封闭类在同一个源代码文件里,封闭类可以不使用 permits 语句,Java 编译器将检索源文件,在编译期为封闭类添加上许可的子类

public sealed class Animal permits Cat, Dog {  
}

任何扩展密封类的类本身都必须声明为 sealed、non-sealed 或 final。

public final class Cat extends Animal {  
}

使用 non-sealed 关键字对类进行显式的声明不进行密封,由下游调用方承担打破密封的风险。

public non-sealed class Dog extends Animal {  
}

sealed 子类传递了密封性,final 的子类确认密封性,non-sealed 显式放弃密封性。

增强的伪随机数生成器

JDK 17 之前,可以使用 Random、ThreadLocalRandom 和 SplittableRandom 来生成随机数。
不过这几个类实现代码质量和接口抽象不佳,且缺少常见的伪随机算法支持。

Java 17 为伪随机数生成器 PRNG(pseudorandom number generator,又称确定性随机位生成器)增加了新的接口类型和实现。
RandomGenerator 接口为所有的 PRNG 算法提供统一的 API,并且可以获取不同类型的 PRNG 对象流。
RandomGeneratorFactory 用于构造各种 RandomGenerator 实例。

RandomGeneratorFactory.all().forEach(factory -> System.out.println(factory.group() + ": " + factory.name()));  

RandomGeneratorFactory<RandomGenerator> random = RandomGeneratorFactory.of("L128X256MixRandom");  
RandomGenerator randomGenerator = random.create(System.currentTimeMillis());  
for (int i = 0; i < 5; i++) {  
    System.out.println(randomGenerator.nextInt(10));  
}

 上一篇: Java 21 虚拟线程(Virtual Threads) 下一篇: 中国业余无线电台 A 类操作技术能力验证 

© 2024 Homurax

UV: | PV:

Theme Typography by Makito

Proudly published with Hexo