Skip to content

Java8

Lambda表达式

所作的一切操作都是以是函数式接口为前提

函数式接口

定义:一个接口里面只有一个抽象方法那么这个接口就是函数式接口

例:

java
public interface Runnable{
    public abstract void run();
}

发展历程

定义一个接口 interface ILike

  1. 一个实现类去实现接口 class Like implement ILike
  2. 静态内部类去实现接口 类: static class Like implement ILike
  3. 局部内部类去实现接口 方法:class Like implement ILike
  4. 匿名内部类去实现接口 对象名 = new ILike(){ ... }
  5. 使用 Lambda 对象名 = () -> { ... }

格式

java
对象名 = () -> { ... };

对象名 = (int i) -> { ... };

对象名 = (i) -> { ... };

对象名 = i -> { ... };

对象名 = i -> ...;

7行:前提是有且只有一个参数,才能省略小括号

9行:前提是有且只有一行内容;之前),才能省略大括号

Optional类

用途:更好的处理空指针异常

API

  1. of(T value):创建一个包含非空值的 Optional 对象。如果传入的值为 null,则会抛出 NullPointerException。
  2. ofNullable(T value):创建一个 Optional 对象,可以包含空值。如果传入的值为 null,则返回一个空的 Optional 对象。
  3. empty():创建一个空的 Optional 对象,不包含任何值。
  4. isPresent():如果 Optional 对象包含非空值,则返回 true;否则返回 false。
  5. ifPresent(Consumer<? super T> consumer):如果 Optional 对象包含非空值,则执行传入的操作。
  6. get():如果 Optional 对象包含非空值,则返回该值;否则抛出 NoSuchElementException 异常。
  7. orElse(T other):如果 Optional 对象包含非空值,则返回该值;否则返回传入的默认值。
  8. orElseGet(Supplier<? extends T> supplier):如果 Optional 对象包含非空值,则返回该值;否则返回由 Supplier 提供的值。
  9. orElseThrow(Supplier<? extends X> exceptionSupplier):如果 Optional 对象包含非空值,则返回该值;否则抛出由 Supplier 提供的异常。
  10. map(Function<? super T,? extends U> mapper):对 Optional 对象中的值进行转换,并返回一个新的 Optional 对象。
  11. flatMap(Function<? super T,Optional<U>> mapper):对 Optional 对象中的值进行转换,并返回一个新的 Optional 对象,可以避免嵌套的 Optional。

Java9

模块机制

模块机制提供了另一个级别的Java代码的可见性、可访问性的控制

它做了包与包之间的隔离,按需导入

java
module com.example.myapp {
    requires java.base;
    requires com.example.mylibrary;
    exports com.example.myapp;
}

在上面的代码中,我们定义了一个名为com.example.myapp的模块。它声明了对java.base模块的依赖,以及对com.example.mylibrary模块的依赖。还通过exports语句将com.example.myapp包导出,以使其他模块可以访问该包中的类

......

JShell

让其使用命令行的交互式编程,支持一条一条命令进行操作,配置好环境变量之后输入jshell即可开始

接口中private

在Java8中接口支持添加default关键字来添加默认实现,在Java9中接口可以存在私有方法

java
public interface Main {
    default void fun1() {
        // 默认实现
        System.out.println(3.1415926);
    }

    private void fun2() {
        // 私有方法
        System.out.println(3.1415926);
    }
}

在接口中定义私有方法,一般是默认实现和静态方法使用

私有方法必须提供方法体

集合类工厂方法

java
// 普通创建的map
Map<String, String> map = new HashMap<>();
map.put("k1", "v1");
map.put("k2", "v2");

// 快速创建
Map<String, String> map2 = Map.of("k1", "v1", "k2", "v2");
List.of(...);
Set.of(...);

相应的其他的集合方法也有相对应的 of

注意:使用快速添加的内容不可更改

Java10

局部变量推断

java
// 老版正常写法
String s = "hello";
// 新版写法
var a = "hello";
var b = 1;
var c = true;

这个 var 关键字会根据后面跟得值来推断这是一个什么样的类型,在编译完成之后会编译成正常的类型,关键字后面必须跟值

java
// 这是编译后的内容
String s = "hello";
String a = "hello";
int b = true;
boolean c = true;

Java11

Lambda表达式的形参局部变量语法

java
Consumer<String> consumer = (var s) -> {
    var split = s.split("-");

    System.out.println(split[0]);
    System.out.println(split[1]);
};

consumer.accept("hello-world");

Spring类方法增强

java
String s = "";
System.out.printf("是否是空字符串:%s", s.isEmpty());
s = "   ";
System.out.printf("是否全部是空格:%s", s.isBlank());

isBlank() 判断其内容中是都全是空格是的话为true,什么也没有的一个空串也是true

java
String s = "ABC";
String repeat = s.repeat(3);
System.out.println(repeat);

repeat() 循环字符串,如:“ABC”循环三次后为“ABCABCABC”

java
String s = "AB\nCD";
Stream<String> lines = s.lines();
lines.forEach(System.out::println);

lines() 根据\n换行符进行分割字符串

java
String s = " A B C D ";
// 去除首尾空格
String strip = s.strip();
// 去除首空格
String stripLeading = s.stripLeading();
// 去除尾空格
String stripTrailing = s.stripTrailing();

strip()stripLeading()stripTrailing() 这三个API快速去除空格

新HttpClien API

此HttpClien不是apache的是JDK自带的

java
// 创建一个客户端
HttpClient client = HttpClient.newHttpClient();
// 创建一个请求
HttpRequest request = HttpRequest.newBuilder(new URI("https://nav.ximuliunian.top/json/image.json")).GET().build();
// 发送请求并接收响应
HttpResponse<String> send = client.send(request, HttpResponse.BodyHandlers.ofString());
// 打印响应体
System.out.println(send.body());

Java12 ~ 16

switch

原版

java
Scanner scanner = new Scanner(System.in);
switch (scanner.nextInt()) {
    case 1:
        System.out.println("1");
        break;
    case 2:
        System.out.println("2");
        break;
    default:
        System.out.println("default");
}

箭头表达式

java
Scanner scanner = new Scanner(System.in);
switch (scanner.nextInt()) {
    // 多行使用以下写法
    case 1 -> {
        System.out.println("1");
    }
    // 只有单行可以使用下面的写法
    case 2 -> System.out.println("2");
        
    default -> {
        System.out.println("default");
    }
}

yield返回值

yield能让switch作为表达式,能够返回值

java
Scanner scanner = new Scanner(System.in);
String s = switch (scanner.nextInt()) {
    case 1 -> {
        System.out.println("1");
        yield "1";
    }
    // 只有单行直接返回
    case 2 -> "2";
        
    default -> {
        System.out.println("default");
        yield "default";
    }
};

在switch中 case X:case X-> 只能使用两种其中的一种格式,不能混用

文本块

java
String data = """
             hello world
             这是一个文本块
             我可以这样编写使用           
        """;

新 instanceof 语法

java
public class Student {
    private String name;
    private int age;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof Student) {
            Student student = (Student) o;
            return student.name.equals(name) && student.age == age;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

以上为老版本的 instanceof 内容,语法优化是不需要强转类型直接使用

java
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o instanceof Student student) {
        return student.name.equals(name) && student.age == age;
    }
    return false;
}

针对空指针异常改进

java
public static void main(String[] args) {
    // 传入空值
    fun("hello", null);
}

public static void fun(String a, String b) {
    int length = a.length() + b.length();
    System.out.println("总长度:" + length);
}

根据以上方案肯定会爆出空指针异常

java
// 以往异常虽然告诉你空指针但是没告诉你具体是a空指针还是b
Exception in thread "main" java.lang.NullPointerException
	at top.xmln.data.Main.fun(Main.java:13)
	at top.xmln.data.Main.main(Main.java:9)

// 改进后的方案 - 直接说明是b空了
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "b" is null
	at top.xmln.data.Main.fun(Main.java:13)
	at top.xmln.data.Main.main(Main.java:9)

记录类型 — Record

继接口、类、枚举之后的又一个类型:记录

简介

Java14中预览的新特性叫做Record,在Java中,Record是一种特殊类型的Java类。可用来创建不可变类,语法简短

特点:

  • 带有全部参数的构造方法
  • public访问器
  • toString()、hsahCode()、equals()
  • 无get\set方法
  • final类,不能继承Record,Record位隐士的final类,除此之外与普通类一样
  • 不可变类,通过构造创建Record
  • final属性不可修改
  • 不能声明实例属性,能声明static成员

代码

java
public record LuHu(String name, String color, Double price) {
	// ...
}

以上就是一个简单的record,下面是测试方法

java
public class RecordTest {

    public static void main(String[] args) {
        // 实例化
        LuHu luHu = new LuHu("路虎", "red", 10086.0);

        // 调用属性
        String name = luHu.name();
        String color = luHu.color();
        Double price = luHu.price();
        
        // 输出
        System.out.println("name = " + name + ", color = " + color + ", price = " + price);
    }
}

实例 & 静态

java
public record LuHu(String name, String color, Double price) {
    // 定义实例方法
    public void print() {
        System.out.println("name = " + name + ", color = " + color + ", price = " + price);
    }

    // 定义静态方法
    public static String colorToUpperCase(String color) {
        return Optional.ofNullable(color).orElse("color is empty").toUpperCase();
    }
}

构造方法

自定义构造 & 规范构造(推荐)

java
public LuHu(String name, String color, Double price) {
    this.name = name;
    this.color = color;
    this.price = price;
}

紧凑构造

java
public LuHu {
    if (name == null) {
        throw new IllegalArgumentException("name is empty");
    }
    // ...
}

实现接口

接口

java
public interface Car {
    void run();
}

实现

java
public record LuHu(String name, String color, Double price) implements Car {
    @Override
    public void run() {
        StringJoiner stringJoiner = new StringJoiner("-", "[", "]");
        stringJoiner.add(name);
        stringJoiner.add(color);
        stringJoiner.add(price.toString());
        System.out.println(stringJoiner);
    }
}

Local Record

Record可以作为局部对象使用

java
public class RecordTest {

    public static void main(String[] args) {
        record BaoMa(String name, String color, Double price) implements Car {
            @Override
            public void run() {
                StringJoiner stringJoiner = new StringJoiner("-", "[", "]");
                stringJoiner.add(name);
                stringJoiner.add(color);
                stringJoiner.add(price.toString());
                System.out.println(stringJoiner);
            }
        }
        BaoMa baoMa = new BaoMa("宝马", "红色", 500000.0);
        baoMa.run();
    }
}

嵌套Record

多个Record可以组合定义,一个Record能够包含其他的Record

java
public class RecordTest {

    public static void main(String[] args) {
        record CarOwner(String name, LuHu luHu) {
        }
        LuHu luHu = new LuHu("路虎", "白色", 10000.0);
        CarOwner carOwner = new CarOwner("张三", luHu);
    }
}

instanceof能够与Record一起使用,编译器知道记录组件的确切数量和类型

Java17

密封类型

在Java中可以通过继承来实现类的复用、扩展和增强,但是有些时候不想类被继承,这是可以使用final关键字来达到不被继承的目的,但是弊端就是我自己也不能继承,这时候有希望我自己写的类能够继承别人的类无法继承,这个场景就需要使用密封类型:sealed

java
public sealed class Main permits A, B, C {
    // ...
}

sealed关键字表示当前类是一个密封类型,后面的permits是表示哪个类可以继承我

要求:

  • 可以基于普通类、接口、抽象类,也可以是继承自其他接口的子类或者其他接口类等
  • 必须要有permits,不能是匿名内部类或者lambda表达式
  • sealed卸载final位置,且不能和final、non-sealed(非密封的)同时出现
  • 继承的子类必须显示为final、sealed或者是non-sealed类型