原文链接
在这篇文章中,我将描述自 Java8 依赖对开发者来说最重要也最友好的特性,之所以选择 Java8 ,那是因为它依然是目前使用最多的版本。
具体可见这个调查报告:
Switch 表达式 (JDK 12)
使用 switch 表达式,你可以定义多个 case 条件,并使用箭头 ->
符号返回值,这个特性在 JDK12 之后启用,它使得 switch 表达式更容易理解了。
1 2 3 4 5 6 7 | public String newMultiSwitch(int day) { return switch (day) { case 1, 2, 3, 4, 5 -> "workday"; case 6, 7 -> "weekend"; default -> "invalid"; }; } |
在 JDK12 之前,同样的例子要复杂的多:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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"; } } |
文本块 (JDK 13)
文本块是一个多行字符串,可以避免使用转移字符;从 Java13 之后它成为了预览特性,使用 """
符号定义。接下来看看使用它声明一个 JSON 字符串有多简单。
1 2 3 4 5 6 7 8 | public String getNewPrettyPrintJson() { return """ { "firstName": "Piotr", "lastName": "Mińkowski" } """; } |
Java13 之前的版本:
1 2 3 4 5 6 | public String getOldPrettyPrintJson() { return "{\n" + " \"firstName\": \"Piotr\",\n" + " \"lastName\": \"Mińkowski\"\n" + "}"; } |
新的 Optional Methods (JDK 9/ JDK 10)
Java 9/10 版本之后新增了几种可选方法,有意思的是这两个:
-
orElseThrow
-
ifPresentOrElse
使用 orElseThrow
当数据不存在时你能抛出 NoSuchElementException
异常,相反会返回数据。
1 2 3 4 | public Person getPersonById(Long id) { Optional<Person> personOpt = repository.findById(id); return personOpt.orElseThrow(); } |
正因为如此,可以避免在 isPresent 中使用 if 条件。
1 2 3 4 5 6 7 | public Person getPersonByIdOldWay(Long id) { Optional<Person> personOpt = repository.findById(id); if (personOpt.isPresent()) return personOpt.get(); else throw new NoSuchElementException(); } |
第二个有趣的方法是 ifPresentOrElse
,当数据存在时,会执行带数据参数的函数,相反会执行参数为空的函数。
1 2 3 4 5 6 7 | public void printPersonById(Long id) { Optional<Person> personOpt = repository.findById(id); personOpt.ifPresentOrElse( System.out::println, () -> System.out.println("Person not found") ); } |
在 Java8 中,你需要在 isPresent 方法中使用 if else 语句。
集合工厂方法(JDK 9)
使用 Java9 中的集合工厂方法可以简单的使用预定义数据创建不可变集合。
1 2 | List<String> fruits = List.of("apple", "banana", "orange"); Map<Integer, String> numbers = Map.of(1, "one", 2,"two", 3, "three"); |
在 Java9 之前,你可以使用 Collections ,但肯定是更复杂:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); } |
Records (JDK 14)
使用 Records
你可以定义一个不可变、只能访问数据(只有 getter 方法) 的类,它可以自动创建 toString,equals,hashcode
方法。
1 | public record Person(String name, int age) {} |
以下效果与 Records
类似:
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 | 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 的私有方法你就能充分使用该特性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 表达式中使用类型推导了。
1 2 3 4 | public String sumOfString() { BiFunction<String, String, String> func = (var x, var y) -> x + y; return func.apply("abc", "efg"); } |