史上最全jdk新特性總結,涵蓋jdk8到jdk15!

前言

在本文中,我將描述自第8版以來Java最重要且對開發人員友好的功能。為什麼會有這樣的主意?在Web上,您可以找到許多文章,其中包含每種Java版本的新功能列表。但是,由於缺少文章,因此無法簡要概述自第8版以來最重要的更改。好的,但是為什麼是第8版?令人驚訝的是,它仍然是最常用的Java版本。即使我們已經到了Java 16發行版的前夕果。如您所見,超過46%的響應者仍在生產中使用Java 8。相比之下,只有不到10%的響應者使用Java 12或更高版本。

java版本使用佔比
java版本使用佔比

那接下來咋們從JDK8到JDK15,給大家介紹新的JDK提供給咋們的新特性!

JDK8

  1. Lambda表達式

最直接作用就是減少程式碼,程式碼直接減少50%+,顯得非常簡潔

 //使用java匿名內部類
  Comparator<Integer> cpt = new Comparator<Integer>() {
      @Override
      public int compare(Integer o1, Integer o2) {
          return Integer.compare(o1,o2);
      }
  };

  TreeSet<Integer> set = new TreeSet<>(cpt);

  System.out.println("=========================");

  //使用JDK8 lambda表達式
  Comparator<Integer> cpt2 = (x,y) -> Integer.compare(x,y);
  TreeSet<Integer> set2 = new TreeSet<>(cpt2);
// java7中  篩選產品為nike的
public  List<Product> filterProductByColor(List<Product> list){
    List<Product> prods = new ArrayList<>();
    for (Product product : list){
        if ("nike".equals(product.getName())){
            prods.add(product);
        }
    }
    return prods;
 }

// 使用 lambda
public  List<Product> filterProductByPrice(List<Product> list){
  return list.stream().filter(p->"nike".equals(p.getName())).collect(Collectors.toList());  
 }

  1. 函數式介面

位於java.util.function包下,下面介紹最常用的幾個

  • Predicate

接收一個值返回boolean

  Predicate p = t->true;
  • Supplier

無接受參數返回一個值

Supplier<T> s = () -> new T();
  • Consumer

接受一個參數無返回值

Consumer<String> c = c -> System.out.println(s);
  • Function<T,R>

接受參數T 返回參數R

Function<Long,String> f = c -> String.valueof(c);
  • 其他還有一些 BiFunction,BiConsumer,DoubleSupplier等大家有興趣自己去閱讀下源碼
  1. 方法引用

  • 靜態引用:
    格式:Class::static_method
List<String> list = Arrays.asList("a","b","c");
list.forEach(str -> System.out.print(str));
list.forEach(System.out::print);
  • 構造器調用
    構造器方法引用格式:Class::new,調用默認構造器
List<String> list = Arrays.asList("a","b","c");
List<Test> list.stream().map(Test::new).collect(Collectors.toList());

public class Test{
    private final String desc;
  
    public Test(String desc){
      this.desc=desc;
    }
}
  • 方法調用
    格式:instance::method
List<String> list = Arrays.asList("a","b","c");
Test test = new Test();
List<String> list.stream().map(test::toAdd).collect(Collectors.toList());

public class Test{
    private final String desc;
  
    public Test(String desc){
      this.desc=desc;
    }

    public String toAdd(String desc){
        return desc+"add";
    }
}
  1. Stream API

// 使用jdk1.8中的Stream API進行集合的操作
@Test
public void test(){

    // 循環過濾元素                                       
    proList.stream()
           .fliter((p) -> "紅色".equals(p.getColor()))
           .forEach(System.out::println);

    // map處理元素然後再循環遍歷
    proList.stream()
           .map(Product::getName)
           .forEach(System.out::println);
  
   // map處理元素轉換成一個List
   proList.stream()
           .map(Product::getName)
           .collect(Collectors.toList());
}
  1. 介面中的默認方法和靜態方法

public interface ProtocolAdaptor {

    ProtocolAdaptor INSTANCE = DynamicLoader.findFirst(ProtocolAdaptor.class).orElse(null);

   
    default ProtocolAdaptor proxy() {
        return (ProtocolAdaptor) Proxy.newProxyInstance(ProtocolAdaptor.class.getClassLoader(),
                new Class[]{ProtocolAdaptor.class},
                (proxy, method, args) -> intercept(method, args));
    }
}  
  1. Optional

用於處理對象空指針異常:

  public String getDesc(Test test){
          return Optional.ofNullable(test)
                  .map(Test::getDesc).else("");
      }

JDK9

  • 收集工廠方法

藉助Java 9的一項新功能,即集合工廠方法,您可以輕鬆地使用預定義的數據創建不可變的集合。您只需要在特定集合類型上使用of方法。

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

在Java 9之前,您可以使用Collections,但這絕對是一種更複雜的方法。

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(…)method。

public List<String> fruitsFromArray() {
 String[] fruitsArray = {"apple""banana""orange"};
 return Arrays.asList(fruitsArray);
}
  • 介面中的私有方法

從Java 8開始,您可以在介面內部使用公共默認方法。但是僅從Java 9開始,由於介面中的私有方法,您將能夠充分利用此功能。

ublic 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");
    }
}

JDK10

從Java 9和Java 10開始,有幾種用於Optional的有用方法。其中最有趣的兩個是orElseThrow和ifPresentOrElse。如果沒有值,則使用該orElseThrow方法拋出NoSuchElementException。否則,它返回一個值。

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

因此,您可以避免將帶參數的if語句與isPresentmethod一起使用。

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")
 );
}

在Java 8中,我們可以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 10 && JDK 11

從Java 10開始,您可以聲明沒有其類型的局部變數。您只需要定義var關鍵字而不是類型。從Java 11開始,您還可以將其與lambda表達式一起使用,如下所示。

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

JDK 12

使用Switch表達式,您可以定義多個case標籤並使用箭頭返回值。此功能自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";
        }
    }

JDK 13

文本塊是多行字元串文字,它避免使用轉義序列,並以可預測的方式自動設置字元串格式。它還使開發人員可以控制字元串的格式。從Java 13開始,文本塊可用作預覽功能。它們以三個雙引號(”””)開頭。讓我們看看我們如何輕鬆地創建和格式化JSON消息。

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

創建Java 13之前的相同JSON字元串要複雜得多。

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

JDK14

使用Records,您可以定義不可變的純數據類(僅限getter)。它會自動創建toString,equals和hashCode方法。實際上,您只需要定義如下所示的欄位即可。

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

具有類似功能的類如record包含欄位,構造函數,getter和實施toString,equals以及hashCode方法。

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 +
                '
}';
    }

}

JDK15

使用密封類功能,您可以限制超類的使用。使用new關鍵字,sealed您可以定義哪些其他類或介面可以擴展或實現當前類。

public abstract sealed class Pet permits Cat, Dog {}

允許的子類必須定義一個修飾符。如果您不想允許任何其他擴展名,則需要使用final關鍵字。

public final class Cat extends Pet {}

另一方面,您可以打開擴展類。在這種情況下,應使用non-sealed修飾符。

public non-sealed class Dog extends Pet {}

當然,下面的可見聲明是不允許的。

public final class Tiger extends Pet {}

END

原創整理不容易,歡迎大家關注公眾號!閱讀更多好文!

歡迎關注公眾號!
公眾號回復:入群 ,掃碼加入我們交流群!
掃碼關注公眾號獲取更多學習資料