Java 9至12的一些新功能(第一集)

《怎麼樣學Programming篇》最近我於公司做了一個短短的簡報(technical presentation)主要講述Java 9至12的新功能,有很多幹Java的同事都覺得蠻好奇的,因為畢竟我們公司很多的系統還停留於Java 8。。。

身為一名Java軟件工程師,我一直需要提升我的技能。你越懂一種編碼語言的新功能就可以在求職市場上凸顯自己的優勢。譬如我最初是於2013年在大學開始學Java的,那時候還是Java 7盛行的年代,跟本沒有Functional Programming的性能。Functional programming的性能是於Java 8開始才有的。

就算Java 8最終於2014年推出了,但是2014至2016年期間很多企業跟本也還沒用Java 8,直到2016開始企業才開始慢慢地升級用Java 8,所以2014至2016年便是『空窗期』 – 面試考官通常不會需要你懂Java 8,只是“nice to have”而已,你若能描述Java 8新功能的一些細節便會於面試大大加分。

同樣地,很多Java工程師也不懂2019年推出Java 12和Java 13的新功能。你能夠掌握到Java 12和13的新功能便能於面試加分。

你越懂一種編碼語言的新功能就可以在求職市場上凸顯自己的優勢。

這次我會講一些新Java語法的功能(Syntax-level features),我於下面並加插了自己的中文演繹(我為公司做的簡報是沒有這些加插的演繹),下集會提及一些新Java比較複雜的架構性能(Architecture-level features)。

Syntax-level features:

  • Enhanced Stream API (Java 9)
  • Java REPL (Java 9)
  • New Factory Methods for Collections (Java 9)
  • Var keyword (Java 10)
  • Switch-case statement (Java 12)

Architecture-level features:

  • Modules (Java 9)
  • Garbage Collector Z (Java 11)

Enhanced Stream API (Java 9)

『有使用Java 8的人都知道Stream API是於Java 8才推出的,它的目的主要是為了簡化長的代碼,譬如說”filter()”和”map()”功能就省掉一個for-loop或while-loop,Stream API另外也會提升代碼的閱讀簡易度(code readability)。

Java 9則於Stream API增加了一些功能如takeWhile(),DropWhile(),iterate(),ofNullable(),主要也是為了簡化代碼,取代loop。』

1. takeWhile() method

Syntax

 default Stream<T> takeWhile(Predicate<? super T> predicate)  

Example

Stream<Integer> stream = Stream.of(1,2,4,5,3,6,7,8,9,10) 
stream.takeWhile(x -> x < 4).forEach(a -> System.out.println(a))

Output

1
2

2. dropWhile() method

Syntax

 default Stream<T> dropWhile(Predicate<? super T> predicate)  

Example

Stream<Integer> stream = Stream.of(1,2,4,5,3,6,7,8,9,10) 
stream.dropWhile(x -> x < 4).forEach(a -> System.out.print(a))

Output

 453678910

3. iterate() method

Syntax

static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next) 

Example

 IntStream.iterate(2, x -> x < 20, x -> x * x).forEach(System.out::println) 

Output

2
4
16

4. ofNullable() method

Syntax

 static <T> Stream<T> ofNullable (T t) 

Explanation

It helps to handle the null stream and NullPointerException (NPE). Java 8 only has Stream.of() – it cannot handle null stream and NPE.

『新手一定要知道怎麼樣處理exceptions,因為不正確處理exceptions會導致整個程式癱瘓。香港某一個大型超市的線上購網的主頁也最近出現了NullPointerException 😂,令顧客無法線上購物。』

Example

 Stream<String> value = Stream.ofNullable(null);
value.forEach(System.out::println);

Output

{NOTHING}

Read-Eval-Print-Loop or REPL (Java 9)

『簡單來說,REPL就好像Linux bash script,可以給你在terminal寫一點代碼並顯示出一些結果。』

REPL uses a new feature JShell. With JShell, you can:

$ bash ./scripts/run.sh |  Welcome to JShell -- Version 0.710
|  Type /help for help

-> Math.sqrt( 144.0f );
|  Expression value is: 12.0
|    assigned to temporary variable $1 of type double

-> $1 + 100;
|  Expression value is: 112.0
|    assigned to temporary variable $2 of type double

New Factory Methods for Collections (Java 9)

一句而言,Java 9簡化了初始List,Set和Map的代碼。Java 8或以前用new ArrayList<>(),new HashSet<>()或new HashMap<>(),現在用List.of(),Set.of(),或Map.of()則可以建立List,Set和Map了,但一次只能最多建立10個物件。

這樣的功能當然是好事,但是令我感到無奈的是List class的implementation有一些不能refactor的redundant code:

public class List<A> extends AbstractCollection<A> implements java.util.List<A> {
...
public static <A> List<A> of(A x1) { return new List<>(x1, List.nil()); }
public static <A> List<A> of(A x1, A x2) { return new List<>(x1, of(x2)); }
public static <A> List<A> of(A x1, A x2, A x3) { return new List<>(x1, of(x2, x3)); }
...
}

其實上面的代碼被寫成下方便可以了:

public class List<A> extends AbstractCollection<A> implements java.util.List<A> {
...

public static <A> List<A> of(A x1, A x2, A x3, A... rest) {

return new List<>(x1, new List<>(x2, new List<>(x3, from(rest))));
}
...
}

1. Factory method for List

Before Java 9:

 public static void main(String[] args) {
    List<String> list1 = new ArrayList<>();
    list1.add("Java");
    list1.add("JavaFX");
}

Since Java 9, List.of() can store up to 10 items:

public static void main(String[] args) {
          List<String> list = List.of("Java","JavaFX");  
}

2. Factory method for Set

Before Java 9:

 public static void main(String[] args) {
    Set<String> set1 = new HashSet<>();
    set.add("Java");
    set.add("JavaFX");
}

Since Java 9, Set.of() can store up to 10 items:

public static void main(String[] args) {
          Set<String> set = Set.of("Java","JavaFX");  
}

3. Factory method for Map

Before Java 9:

 public static void main(String[] args) {  
    Map<Integer,String> integerString = new HashMap<Integer,String>();
    integerString.put(101, "JavaFX");
    integerString.put(102, "Hibernate");
}

Since Java 9, Map.of() can store up to 10 items, but does not allow null keys nor null values.

public static void main(String[] args) {
        Map<Integer,String> map = Map.of(101,"JavaFX",102,"Hibernate");
}

Var keyword (Java 10)

Before Java 10

 String greeting = "Hello World"; ArrayList<String> messages = new ArrayList<String>(); 
messages.add(greeting); 
Stream<String> stream = messages.stream();

Since Java 10

 var greeting = "Hello World";var messages = new ArrayList<String>();
messages.add(greeting);
var stream = messages.stream();

Things to note:

  • “var” can only be used in local variables, not in instance/global variables
  • “var” must be declared & initialized, otherwise compiler error

Usage of Var

 public class VarKeyword {
var stuff1 = 123; // compiler error

public static void main(String[] args) {
    var stuff2 = "asdf";
    while(true) {
        var stuff3 = "wefew";
        break;
    }
    var stuff4 = 21342;
}
}

Switch-case statement (Java 12)

Basics:

Before Java 12

 int numLetters;switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
default:
throw new IllegalStateException("Huh? " + day);
}

Since Java 12

 int numLetters = switch (day) {case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
default -> throw new IllegalStateException("Huh? " + day);
};

“Breaks”:

Before Java 12

 int numLetters;switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
default:
throw new IllegalStateException("Huh? " + day);
}

Since Java 12

 final int integer = 1;  System.out.println("Switch Expression with Colons/Breaks:");  
final String numericString =  
      switch (integer)  
      {  
         case 1 :  
            break "uno";  
         case 2 :  
            break "dos";  
         case 3 :  
            break "tres";  
         default :  
            break "N/A";  
      }; 

Additional note

新舊的switch-case statement不能互相兼容。Old and New switch-case statements cannot be mixed, below won’t work:

  final int integer = 3;
   String numericString;  
   switch(integer)  
   {  
      case 1 :  
         numericString = "one";  
         break;  // old switch-case syntax
      case 2 -> numericString = "two";  // new switch-case syntax
      default -> numericString = "N/A";  
   }  
   return numericString; 

下一篇持續…

Leave a Reply

Your email address will not be published. Required fields are marked *