Java8之后新的开发者友好特性
在本文中,我将描述自第8版以来Java最重要、最有利于开发人员的特性。为什么会有这样的想法?您可以在Web上找到许多文章,其中列出了每个Java版本的新特性。然而,缺少文章简要概述自第8版以来最重要的变化。好的,但是为什么是第八版呢?令人惊讶的是,它仍然是Java最常用的版本。尽管Java17已发布,但所有这些都是值得一提的。你可以在Twitter上查看我的调查结果。正如您所看到的,46%以上的响应者仍然在生产中使用Java8。相比之下,只有不到10%的响应者使用Java12或更高版本。

Java8之后新的开发者友好特性

当然,Java8引入了大量的更改,包括Lambda表达式。在此之后,没有类似的版本具有如此庞大的一组关键特性。不过,您会发现自Java8以来的一些有趣的新特性。我已经在Twitter上发布了所有的例子,它们以图形形式显示在下面。您可以使用#AfterJava8标签找到它们。

Java8之后新的开发者友好特性

源代码

如果您想自己尝试,您可以随时查看我的源代码。为此,您需要克隆我的GitHub存储库(https://github.com/piomin/sample-java-new-features.git)。我正在使用Maven和Java15进行编译。

Switch表达式(JDK 12)

使用开关表达式,可以使用箭头定义多个大小写标签和返回值。此功能从JDK 12开始提供。它使Switch表达式更容易访问。

public String newMultiSwitch(int day) {
        return switch (day) {
            case 1, 2, 3, 4, 5 -> "workday";
            case 6, 7 -> "weekend";
            default -> "invalid";
        };
    }

对于低于12的Java,相同的示例相当复杂。

public String oldMultiSwitch(int day) {
        switch (day) {
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
                return "workday";
            case 6:
            case 7:
                return "weekend";
            default:
                return "invalid";
        }
    }

Sealed类(JDK 15)

使用Sealed密封类功能,可以限制超类的使用。使用新的关键字sealed,您可以定义哪些其他类或接口可以扩展或实现当前类。

public abstract sealed class Pet permits Cat, Dog {}

允许的子类必须定义修饰符。如果不想允许任何其他扩展,则需要使用final关键字。

public final class Cat extends Pet {}

另一方面,您可以打开类进行扩展。在这种情况下,应该使用非密封修改器。

public non-sealed class Dog extends Pet {}

当然,下面可见的声明是不允许的。

public final class Tiger extends Pet {}

文本块(JDK 13)

文本块是一种多行字符串文字,它避免使用转义序列,并以可预测的方式自动格式化字符串。它还允许开发人员控制字符串的格式。自Java13以来,文本块作为预览功能提供。它们以三个双引号(""")开始。让我们看看创建和格式化JSON消息有多容易。

public String getNewPrettyPrintJson() {
        return """
               {
                    "firstName": "Piotr",
                    "lastName": "Mińkowski"
               }
               """;
    }

Java13之前的JSON字符串创建起来相当复杂。

public String getOldPrettyPrintJson() {
        return "{\n" +
               "     \"firstName\": \"Piotr\",\n" +
               "     \"lastName\": \"Mińkowski\"\n" +
               "}";
    }

新的可选方法(JDK 9/JDK 10)

自Java9和Java10以来,有几种可选的有用方法。其中最有趣的两个是orElseThrowifPresentOrElse。使用orElseThrow方法,如果不存在值,则抛出NoTouchElementException。否则,它将返回一个值。

public Person getPersonById(Long id) {
	Optional<Person> personOpt = repository.findById(id);
	return personOpt.orElseThrow();
}

正因为如此,您可以避免在isPresent方法中使用if语句。

public Person getPersonByIdOldWay(Long id) {
	Optional<Person> personOpt = repository.findById(id);
	if (personOpt.isPresent())
		return personOpt.get();
	else
		throw new NoSuchElementException();
}

第二个有趣的方法是ifPresentOrElse。如果存在值,它将使用该值执行给定操作。否则,它将执行给定的基于空的操作。

public void printPersonById(Long id) {
	Optional<Person> personOpt = repository.findById(id);
	personOpt.ifPresentOrElse(
			System.out::println,
			() -> System.out.println("Person not found")
	);
}

对于Java8,我们可以将if-else直接用于isPresent方法。

public void printPersonByIdOldWay(Long id) {
	Optional<Person> personOpt = repository.findById(id);
	if (personOpt.isPresent())
		System.out.println(personOpt.get());
	else
		System.out.println("Person not found");
}

集合工厂方法(JDK 9)

通过Java9的一个称为集合工厂方法的新特性,您可以轻松地使用预定义的数据创建不可变的集合。您只需要对特定集合类型使用of方法。

List<String> fruits = List.of("apple", "banana", "orange");
Map<Integer, String> numbers = Map.of(1, "one", 2,"two", 3, "three");

在Java9之前,您可能会使用集合,但这肯定是一种更复杂的方式。

public List<String> fruits() {
	List<String> fruitsTmp = new ArrayList<>();
	fruitsTmp.add("apple");
	fruitsTmp.add("banana");
	fruitsTmp.add("orange");
	return Collections.unmodifiableList(fruitsTmp);
}

public Map<Integer, String> numbers() {
	Map<Integer, String> numbersTmp = new HashMap<>();
	numbersTmp.put(1, "one");
	numbersTmp.put(2, "two");
	numbersTmp.put(3, "three");
	return Collections.unmodifiableMap(numbersTmp);
}

另外,只要从对象表创建ArrayList,就可以使用Arrays.asList(…)方法。

public List<String> fruitsFromArray() {
	String[] fruitsArray = {"apple", "banana", "orange"};
	return Arrays.asList(fruitsArray);
}

Records(JDK 14)

对于Records记录,您可以定义不可变的、仅数据的类(仅限getter)。它自动创建toStringequalshashCode方法。实际上,您只需要定义如下所示的字段。

public record Person(String name, int age) {}

具有与record类似功能的类包含字段、构造函数、getter以及toStringequalshashCode方法的实现。

public class PersonOld {

    private final String name;
    private final int age;

    public PersonOld(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;
        PersonOld personOld = (PersonOld) o;
        return age == personOld.age && name.equals(personOld.name);
    }

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

    @Override
    public String toString() {
        return "PersonOld{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

}

接口中的私有方法(JDK 9)

自Java8以来,您可以在接口中使用公共默认方法。但只有在Java9之后,由于接口中的私有方法,您才能充分利用这个特性。

public interface ExampleInterface {

    private void printMsg(String methodName) {
        System.out.println("Calling interface");
        System.out.println("Interface method: " + methodName);
    }

    default void method1() {
        printMsg("method1");
    }

    default void method2() {
        printMsg("method2");
    }
}

局部变量类型推断(JDK 10/JDK 11)

由于Java10,您可以声明一个不带类型的局部变量。您只需要定义var关键字而不是类型。由于Java11,您还可以将其与lambda表达式一起使用,如下所示。

public String sumOfString() {
	BiFunction<String, String, String> func = (var x, var y) -> x + y;
	return func.apply("abc", "efg");
}

原文地址:https://piotrminkowski.com/2021/02/01/new-developer-friendly-features-after-java-8/