JAVA8新特性(吐血整理)—— Optional 類

https://www.cnblogs.com/liuxiaozhi23/p/10880147.html

一、Java 8 Lambda 表達式

Lambda 表達式,也可稱爲閉包,它是推動 Java 8 發佈的最重要新特性。

Lambda 允許把函數作爲一個方法的參數(函數作爲參數傳遞進方法中)。

使用Lambda 表達式可以使代碼變的更加簡潔緊湊。

1.1 語法

lambda 表達式的語法格式如下:

(parameters) -> expression或(parameters) ->{statements; }

以下是lambda表達式的重要特徵:

·        可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。

·        可選的參數圓括號:一個參數無需定義圓括號,但多個參數需要定義圓括號。

·        可選的大括號:如果主體包含了一個語句,就不需要使用大括號。

·        可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數值。

1.2  Lambda 表達式實例

在Java8Tester.java 文件輸入以下代碼:

Java8Tester.java文件

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

public class Java8Tester {

    public static void main(String args[]) {

        Java8Tester tester = new Java8Tester();

        // 類型聲明

        MathOperation addition = (int a, int b) -> a + b;

        // 不用類型聲明

        MathOperation subtraction = (a, b) -> a - b;

        // 大括號中的返回語句

        MathOperation multiplication = (int a, int b) -> {

            return a * b;

        };

        // 沒有大括號及返回語句

        MathOperation division = (int a, int b) -> a / b;

        System.out.println("10 + 5 = " + tester.operate(105, addition));

        System.out.println("10 - 5 = " + tester.operate(105, subtraction));

        System.out.println("10 x 5 = " + tester.operate(105, multiplication));

        System.out.println("10 / 5 = " + tester.operate(105, division));

        // 不用括號

        GreetingService greetService1 = message ->

                System.out.println("Hello " + message);

        // 用括號

        GreetingService greetService2 = (message) ->

                System.out.println("Hello " + message);

        greetService1.sayMessage("Runoob");

        greetService2.sayMessage("Google");

    }

    interface MathOperation {

        int operation(int a, int b);

    }

    interface GreetingService {

        void sayMessage(String message);

    }

    private int operate(int a, int b, MathOperation mathOperation) {

        return mathOperation.operation(a, b);

    }

}

  

執行以上腳本,輸出結果爲:

10+5=15
10-5=5
10 x 5=50
10/5=2
HelloRunoob
HelloGoogle
使用Lambda 表達式需要注意以下兩點:

·        Lambda 表達式主要用來定義行內執行的方法類型接口,例如,一個簡單方法接口。在上面例子中,我們使用各種類型的Lambda表達式來定義MathOperation接口的方法。然後我們定義了sayMessage的執行。

·        Lambda 表達式免去了使用匿名方法的麻煩,並且給予Java簡單但是強大的函數化的編程能力。

1.3 變量作用域

lambda 表達式只能引用標記了 final 的外層局部變量,這就是說不能在lambda 內部修改定義在域外的局部變量,否則會編譯錯誤。

在Java8Tester.java 文件輸入以下代碼:

Java8Tester.java文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class Java8Tester {

    final static String salutation = "Hello! ";

public static void main(String args[]){

    GreetingService greetService1 = message ->

            System.out.println(salutation + message);

    greetService1.sayMessage("Runoob");

//====================相當於下面==============================

    GreetingService g = new GreetingService() {

        @Override

        public void sayMessage(String message) {

            System.out.println(salutation + message);

        }

    };

    g.sayMessage("jack");

  

1

2

3

4

5

//===========================================================

}

interface GreetingService {

    void sayMessage(String message);

}

  

1

}

  

執行以上腳本,輸出結果爲:

Hello! Runoob
Hello! jack

我們也可以直接在lambda 表達式中訪問外層的局部變量:

Java8Tester.java文件

1

2

3

4

5

6

7

8

9

10

11

public class Java8Tester {

    public static void main(String args[]) {

        final int num = 1;

        Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));

        s.convert(2);  // 輸出結果爲 3

    }

 

    public interface Converter<T1, T2> {

        void convert(int i);

    }

}

  

lambda 表達式的局部變量可以不用聲明爲 final,但是必須不可被後面的代碼修改(即隱性的具有final 的語義)

1

2

3

4

5

6

7

8

9

10

11

public class Java8Tester {

    public static void main(String args[]) {

        int num = 1;

        Converter<Integer, String> s = (param) -> System.out.println(String.valueOf(param + num));

        s.convert(2);

        num = 5;

    }

    public interface Converter<T1, T2> {

        void convert(int i);

    }

}

  

1

//報錯信息:Local variable num defined in an enclosing scope must be final or effectively final

  

1

把num=5;註釋掉就不報錯了

  

在Lambda 表達式當中不允許聲明一個與局部變量同名的參數或者局部變量。

把String first = "";注掉就不報錯了

 

 

 

 

二、Java 8 方法引用

方法引用通過方法的名字來指向一個方法。

方法引用可以使語言的構造更緊湊簡潔,減少冗餘代碼。

方法引用使用一對冒號 :: 。

2.1方法引用

下面,我們在 Car 類中定義了 4 個方法作爲例子來區分 Java 中 4 種不同方法的引用。

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

40

41

42

43

44

class Car {

    @FunctionalInterface

    public interface Supplier<T> {

        T get();

    }

 

    //Supplier是jdk1.8的接口,這裏和lamda一起使用了

    public static Car create(final Supplier<Car> supplier) {

        return supplier.get();

    }

 

    public static void collide(final Car car) {

        System.out.println("Collided " + car.toString());

    }

 

    public void follow(final Car another) {

        System.out.println("Following the " + another.toString());

    }

 

    public void repair() {

        System.out.println("Repaired " this.toString());

    }

 

    public static void main(String[] args) {

        //構造器引用:它的語法是Class::new,或者更一般的Class< T >::new實例如下:

         Car car  = Car.create(Car::new);

         Car car1 = Car.create(Car::new);

         Car car2 = Car.create(Car::new);

         Car car3 = new Car();

        List<Car> cars = Arrays.asList(car,car1,car2,car3);

        System.out.println("===================構造器引用========================");

        //靜態方法引用:它的語法是Class::static_method,實例如下:

        cars.forEach(Car::collide);

        System.out.println("===================靜態方法引用========================");

        //特定類的任意對象的方法引用:它的語法是Class::method實例如下:

        cars.forEach(Car::repair);

        System.out.println("==============特定類的任意對象的方法引用================");

        //特定對象的方法引用:它的語法是instance::method實例如下:

        final Car police = Car.create(Car::new);

        cars.forEach(police::follow);

        System.out.println("===================特定對象的方法引用===================");

 

    }

}

  

2.2方法引用實例

在Java8Tester.java 文件輸入以下代碼:

Java8Tester.java文件

1

2

3

4

5

6

7

8

9

10

11

public class Java8Tester {

    public static void main(String args[]) {

        List names = new ArrayList();

        names.add("Google");

        names.add("Runoob");

        names.add("Taobao");

        names.add("Baidu");

        names.add("Sina");

        names.forEach(System.out::println);

    }

}

  

實例中我們將System.out::println 方法作爲靜態方法來引用。

執行以上腳本,輸出結果爲:

1

2

3

4

5

Google

Runoob

Taobao

Baidu

Sina

  

三、Java 8 函數式接口

函數式接口(FunctionalInterface)就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的接口。

函數式接口可以被隱式轉換爲lambda表達式。

函數式接口可以現有的函數友好地支持 lambda。

JDK 1.8之前已有的函數式接口:

·        java.lang.Runnable

·        java.util.concurrent.Callable

·        java.security.PrivilegedAction

·        java.util.Comparator

·        java.io.FileFilter

·        java.nio.file.PathMatcher

·        java.lang.reflect.InvocationHandler

·        java.beans.PropertyChangeListener

·        java.awt.event.ActionListener

·        javax.swing.event.ChangeListener

JDK 1.8 新增加的函數接口:

·        java.util.function

java.util.function 它包含了很多類,用來支持 Java的函數式編程,該包中的函數式接口有:

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

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

序號

接口 & 描述

1

BiConsumer<T,U>

代表了一個接受兩個輸入參數的操作,並且不返回任何結果

2

BiFunction<T,U,R>

代表了一個接受兩個輸入參數的方法,並且返回一個結果

3

BinaryOperator<T>

代表了一個作用於於兩個同類型操作符的操作,並且返回了操作符同類型的結果

4

BiPredicate<T,U>

代表了一個兩個參數的boolean值方法

5

BooleanSupplier

代表了boolean值結果的提供方

6

Consumer<T>

代表了接受一個輸入參數並且無返回的操作

7

DoubleBinaryOperator

代表了作用於兩個double值操作符的操作,並且返回了一個double值的結果。

8

DoubleConsumer

代表一個接受double值參數的操作,並且不返回結果。

9

DoubleFunction<R>

代表接受一個double值參數的方法,並且返回結果

10

DoublePredicate

代表一個擁有double值參數的boolean值方法

11

DoubleSupplier

代表一個double值結構的提供方

12

DoubleToIntFunction

接受一個double類型輸入,返回一個int類型結果。

13

DoubleToLongFunction

接受一個double類型輸入,返回一個long類型結果

14

DoubleUnaryOperator

接受一個參數同爲類型double,返回值類型也爲double

15

Function<T,R>

接受一個輸入參數,返回一個結果。

16

IntBinaryOperator

接受兩個參數同爲類型int,返回值類型也爲int 

17

IntConsumer

接受一個int類型的輸入參數,無返回值。

18

IntFunction<R>

接受一個int類型輸入參數,返回一個結果。

19

IntPredicate

:接受一個int輸入參數,返回一個布爾值的結果。

20

IntSupplier

無參數,返回一個int類型結果。

21

IntToDoubleFunction

接受一個int類型輸入,返回一個double類型結果。

22

IntToLongFunction

接受一個int類型輸入,返回一個long類型結果。

23

IntUnaryOperator

接受一個參數同爲類型int,返回值類型也爲int 

24

LongBinaryOperator

接受兩個參數同爲類型long,返回值類型也爲long

25

LongConsumer

接受一個long類型的輸入參數,無返回值。

26

LongFunction<R>

接受一個long類型輸入參數,返回一個結果。

27

LongPredicate

R接受一個long輸入參數,返回一個布爾值類型結果。

28

LongSupplier

無參數,返回一個結果long類型的值。

29

LongToDoubleFunction

接受一個long類型輸入,返回一個double類型結果。

30

LongToIntFunction

接受一個long類型輸入,返回一個int類型結果。

31

LongUnaryOperator

接受一個參數同爲類型long,返回值類型也爲long

32

ObjDoubleConsumer<T>

接受一個object類型和一個double類型的輸入參數,無返回值。

33

ObjIntConsumer<T>

接受一個object類型和一個int類型的輸入參數,無返回值。

34

ObjLongConsumer<T>

接受一個object類型和一個long類型的輸入參數,無返回值。

35

Predicate<T>

接受一個輸入參數,返回一個布爾值結果。

36

Supplier<T>

無參數,返回一個結果。

37

ToDoubleBiFunction<T,U>

接受兩個輸入參數,返回一個double類型結果

38

ToDoubleFunction<T>

接受一個輸入參數,返回一個double類型結果

39

ToIntBiFunction<T,U>

接受兩個輸入參數,返回一個int類型結果。

40

ToIntFunction<T>

接受一個輸入參數,返回一個int類型結果。

41

ToLongBiFunction<T,U>

接受兩個輸入參數,返回一個long類型結果。

42

ToLongFunction<T>

接受一個輸入參數,返回一個long類型結果。

43

UnaryOperator<T>

接受一個參數爲類型T,返回值類型也爲T。

  

3.1 函數式接口實例

Predicate <T> 接口是一個函數式接口,它接受一個輸入參數 T,返回一個布爾值結果。

該接口包含多種默認方法來將Predicate組合成其他複雜的邏輯(比如:與,或,非)。

該接口用於測試對象是 true 或 false。

我們可以通過以下實例(Java8Tester.java)來了解函數式接口 Predicate <T> 的使用:

Java8Tester.java文件
 

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

public class Java8Tester {

    public static void main(String args[]){

        List<Integer> list = Arrays.asList(123456789);

 

        // Predicate<Integer> predicate = n -> true

        // n 是一個參數傳遞到 Predicate 接口的 test 方法

        // n 如果存在則 test 方法返回 true

 

        System.out.println("輸出所有數據:");

 

        // 傳遞參數 n

        eval(list, n->true);

 

        // Predicate<Integer> predicate1 = n -> n%2 == 0

        // n 是一個參數傳遞到 Predicate 接口的 test 方法

        // 如果 n%2 爲 0 test 方法返回 true

 

        System.out.println("輸出所有偶數:");

        eval(list, n-> n%2 == 0 );

 

        // Predicate<Integer> predicate2 = n -> n > 3

        // n 是一個參數傳遞到 Predicate 接口的 test 方法

        // 如果 n 大於 3 test 方法返回 true

 

        System.out.println("輸出大於 3 的所有數字:");

        eval(list, n-> n > 3 );

    }

 

    public static void eval(List<Integer> list, Predicate<Integer> predicate) {

        for(Integer n: list) {

 

            if(predicate.test(n)) {

                System.out.println(n + " ");

            }

        }

    }

}

  

執行以上腳本,輸出結果爲:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

1

2

3

4

5

6

7

8

9

輸出所有偶數:

2

4

6

8

輸出大於3的所有數字:

4

5

6

7

8

9

  

四、Java 8 默認方法

Java 8 新增了接口的默認方法。

簡單說,默認方法就是接口可以有實現方法,而且不需要實現類去實現其方法。

我們只需在方法名前面加個default關鍵字即可實現默認方法。

爲什麼要有這個特性?

首先,之前的接口是個雙刃劍,好處是面向抽象而不是面向具體編程,缺陷是,當需要修改接口時候,需要修改全部實現該接口的類,目前的java 8之前的集合框架沒有foreach方法,通常能想到的解決辦法是在JDK裏給相關的接口添加新的方法及實現。然而,對於已經發布的版本,是沒法在給接口添加新方法的同時不影響已有的實現。所以引進的默認方法。他們的目的是爲了解決接口的修改與現有的實現不兼容的問題。

4.1語法

默認方法語法格式如下:
 

1

2

3

4

5

public interface vehicle {

    default void print() {

        System.out.println("我是一輛車!");

    }

}

  

4.2多個默認方法

一個接口有默認方法,考慮這樣的情況,一個類實現了多個接口,且這些接口有相同的默認方法,以下實例說明了這種情況的解決方法

1

2

3

4

5

public interface vehicle {

    default void print() {

        System.out.println("我是一輛車!");

    }

}

  

1

2

3

4

5

public interface fourWheeler {

    default void print() {

        System.out.println("我是一輛四輪車!");

    }

}

  

第一個解決方案是創建自己的默認方法,來覆蓋重寫接口的默認方法:

1

2

3

4

5

6

7

public class Car implements vehicle, fourWheeler {

 

    @Override

    public void print() {

        System.out.println("我是一輛四輪汽車!");

    }

}

  

第二種解決方案可以使用 super 來調用指定接口的默認方法:

1

2

3

4

5

6

public class Car implements vehicle, fourWheeler {

    @Override

    public void print() {

        vehicle.super.print();

    }

}

  

4.3 靜態默認方法

Java 8 的另一個特性是接口可以聲明(並且可以提供實現)靜態方法。例如:

1

2

3

4

5

6

7

8

9

public interface vehicle {

    default void print() {

        System.out.println("我是一輛車!");

    }

    // 靜態方法

    static void blowHorn() {

        System.out.println("按喇叭!!!");

    }

}

  

4.4 默認方法實例

我們可以通過以下代碼來了解關於默認方法的使用,可以將代碼放入 Java8Tester.java 文件中:

Java8Tester.java文件

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

public class Java8Tester {

    public static void main(String args[]) {

        Vehicle vehicle = new Car();

        vehicle.print();

    }

}

 

interface Vehicle {

    default void print() {

        System.out.println("我是一輛車!");

    }

 

    static void blowHorn() {

        System.out.println("按喇叭!!!");

    }

}

 

interface FourWheeler {

    default void print() {

        System.out.println("我是一輛四輪車!");

    }

}

 

class Car implements Vehicle, FourWheeler {

    public void print() {

        Vehicle.super.print();

        FourWheeler.super.print();

        Vehicle.blowHorn();

        System.out.println("我是一輛汽車!");

    }

}

  

執行以上腳本,輸出結果爲:

1

2

3

4

我是一輛車!

我是一輛四輪車!

按喇叭!!!

我是一輛汽車!

  

五、Java 8 Stream

Java 8 API添加了一個新的抽象稱爲流Stream,可以讓你以一種聲明的方式處理數據。

Stream使用一種類似用SQL語句從數據庫查詢數據的直觀方式來提供一種對Java集合運算和表達的高階抽象。

Stream API可以極大提高Java程序員的生產力,讓程序員寫出高效率、乾淨、簡潔的代碼。

這種風格將要處理的元素集合看作一種流,流在管道中傳輸,並且可以在管道的節點上進行處理,比如篩選,排序,聚合等。

元素流在管道中經過中間操作(intermediate operation)的處理,最後由最終操作(terminal operation)得到前面處理的結果。

5.1什麼是 Stream?

Stream(流)是一個來自數據源的元素隊列並支持聚合操作

元素:是特定類型的對象,形成一個隊列。Java中的Stream並不會存儲元素,而是按需計算。

數據源 :流的來源。可以是集合,數組,I/O channel,產生器generator等。

聚合操作: 類似SQL語句一樣的操作,比如filter, map, reduce, find,match, sorted等。

和以前的Collection操作不同,Stream操作還有兩個基礎的特徵:

Pipelining::中間操作都會返回流對象本身。這樣多個操作可以串聯成一個管道,如同流式風格(fluent style)。這樣做可以對操作進行優化,比如延遲執行(laziness)和短路( short-circuiting)。

內部迭代:以前對集合遍歷都是通過Iterator或者For-Each的方式,顯式的在集合外部進行迭代,這叫做外部迭代。Stream提供了內部迭代的方式,通過訪問者模式(Visitor)實現。

5.2生成流

在Java 8中,集合接口有兩個方法來生成流:

stream() −爲集合創建串行流。

parallelStream() − 爲集合創建並行流。
 

1

2

3

4

public static void main(String[] args) {

    List<String> strings = Arrays.asList("abc""""bc""efg""abcd""""jkl");

    List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

}

  

5.3  forEach

Stream 提供了新的方法 'forEach' 來迭代流中的每個數據。以下代碼片段使用forEach 輸出了10個隨機數:

1

2

Random random = new Random();

random.ints().limit(10).forEach(System.out::println);

  

5.4  map

map 方法用於映射每個元素到對應的結果,以下代碼片段使用 map 輸出了元素對應的平方數:

1

2

3

List<Integer> numbers = Arrays.asList(3223735);

// 獲取對應的平方數

List<Integer> squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());

  

5.5  filter

filter 方法用於通過設置條件過濾出元素。以下代碼片段使用filter 方法過濾出空字符串:

1

2

3

List<String>strings = Arrays.asList("abc""""bc""efg""abcd","""jkl");

// 獲取空字符串的數量

int count = (int) strings.stream().filter(string -> string.isEmpty()).count();

  

5.6  limit

limit 方法用於獲取指定數量的流。以下代碼片段使用 limit 方法打印出 10 條數據:

1

2

Random random = new Random();

random.ints().limit(10).forEach(System.out::println);

  

 

5.7  sorted

sorted 方法用於對流進行排序。以下代碼片段使用 sorted 方法對輸出的 10 個隨機數進行排序:

1

2

Random random = new Random();

random.ints().limit(10).sorted().forEach(System.out::println);

  

5.8  並行(parallel)程序

parallelStream 是流並行處理程序的代替方法。以下實例我們使用parallelStream 來輸出空字符串的數量:

1

2

3

List<String> strings = Arrays.asList("abc""""bc""efg""abcd""""jkl");

// 獲取空字符串的數量

int count = (int) strings.parallelStream().filter(string -> string.isEmpty()).count();

  

 

我們可以很容易的在順序運行和並行直接切換。


5.9  Collectors

Collectors 類實現了很多歸約操作,例如將流轉換成集合和聚合元素。Collectors可用於返回列表或字符串:

1

2

3

4

5

List<String> strings = Arrays.asList("abc""""bc""efg""abcd""""jkl");

List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

System.out.println("篩選列表: " + filtered);

String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));

System.out.println("合併字符串: " + mergedString);

  

5.10  統計

另外,一些產生統計結果的收集器也非常有用。它們主要用於int、double、long等基本類型上,它們可以用來產生類似如下的統計結果。

1

2

3

4

5

6

List<Integer> numbers = Arrays.asList(3223735);

IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();

System.out.println("列表中最大的數 : " + stats.getMax());

System.out.println("列表中最小的數 : " + stats.getMin());

System.out.println("所有數之和 : " + stats.getSum());

System.out.println("平均數 : " + stats.getAverage());

  

5.11  Stream 完整實例

將以下代碼放入Java8Tester.java 文件中:

Java8Tester.java文件

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

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

public class Java8Tester {

    public static void main(String args[]) {

        System.out.println("使用 Java 7: ");

        // 計算空字符串

        List<String> strings = Arrays.asList("abc""""bc""efg""abcd""""jkl");

        System.out.println("列表: " + strings);

        long count = getCountEmptyStringUsingJava7(strings);

        System.out.println("空字符數量爲: " + count);

        count = getCountLength3UsingJava7(strings);

        System.out.println("字符串長度爲 3 的數量爲: " + count);

        // 刪除空字符串

        List<String> filtered = deleteEmptyStringsUsingJava7(strings);

        System.out.println("篩選後的列表: " + filtered);

        // 刪除空字符串,並使用逗號把它們合併起來

        String mergedString = getMergedStringUsingJava7(strings, ", ");

        System.out.println("合併字符串: " + mergedString);

        List<Integer> numbers = Arrays.asList(3223735);

        // 獲取列表元素平方數

        List<Integer> squaresList = getSquares(numbers);

        System.out.println("平方數列表: " + squaresList);

        List<Integer> integers = Arrays.asList(1213415617819);

        System.out.println("列表: " + integers);

        System.out.println("列表中最大的數 : " + getMax(integers));

        System.out.println("列表中最小的數 : " + getMin(integers));

        System.out.println("所有數之和 : " + getSum(integers));

        System.out.println("平均數 : " + getAverage(integers));

        System.out.println("隨機數: ");

        // 輸出10個隨機數

        Random random = new Random();

        for (int i = 0; i < 10; i++) {

            System.out.println(random.nextInt());

        }

        System.out.println("使用 Java 8: ");

        System.out.println("列表: " + strings);

        count = strings.stream().filter(string -> string.isEmpty()).count();

        System.out.println("空字符串數量爲: " + count);

        count = strings.stream().filter(string -> string.length() == 3).count();

        System.out.println("字符串長度爲 3 的數量爲: " + count);

        filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

        System.out.println("篩選後的列表: " + filtered);

        mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));

        System.out.println("合併字符串: " + mergedString);

        squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());

        System.out.println("Squares List: " + squaresList);

        System.out.println("列表: " + integers);

        IntSummaryStatistics stats = integers.stream().mapToInt((x) -> x).summaryStatistics();

        System.out.println("列表中最大的數 : " + stats.getMax());

        System.out.println("列表中最小的數 : " + stats.getMin());

        System.out.println("所有數之和 : " + stats.getSum());

        System.out.println("平均數 : " + stats.getAverage());

        System.out.println("隨機數: ");

        random.ints().limit(10).sorted().forEach(System.out::println);

        // 並行處理

        count = strings.parallelStream().filter(string -> string.isEmpty()).count();

        System.out.println("空字符串的數量爲: " + count);

    }

 

    private static int getCountEmptyStringUsingJava7(List<String> strings) {

        int count = 0;

        for (String string : strings) {

            if (string.isEmpty()) {

                count++;

            }

        }

        return count;

    }

 

    private static int getCountLength3UsingJava7(List<String> strings) {

        int count = 0;

        for (String string : strings) {

            if (string.length() == 3) {

                count++;

            }

        }

        return count;

    }

 

    private static List<String> deleteEmptyStringsUsingJava7(List<String> strings) {

        List<String> filteredList = new ArrayList<String>();

        for (String string : strings) {

            if (!string.isEmpty()) {

                filteredList.add(string);

            }

        }

        return filteredList;

    }

 

    private static String getMergedStringUsingJava7(List<String> strings, String separator) {

        StringBuilder stringBuilder = new StringBuilder();

        for (String string : strings) {

            if (!string.isEmpty()) {

                stringBuilder.append(string);

                stringBuilder.append(separator);

            }

        }

        String mergedString = stringBuilder.toString();

        return mergedString.substring(0, mergedString.length() - 2);

    }

 

    private static List<Integer> getSquares(List<Integer> numbers) {

        List<Integer> squaresList = new ArrayList<Integer>();

        for (Integer number : numbers) {

            Integer square = new Integer(number.intValue() * number.intValue());

            if (!squaresList.contains(square)) {

                squaresList.add(square);

            }

        }

        return squaresList;

    }

 

    private static int getMax(List<Integer> numbers) {

        int max = numbers.get(0);

        for (int i = 1; i < numbers.size(); i++) {

            Integer number = numbers.get(i);

            if (number.intValue() > max) {

                max = number.intValue();

            }

        }

        return max;

    }

 

    private static int getMin(List<Integer> numbers) {

        int min = numbers.get(0);

        for (int i = 1; i < numbers.size(); i++) {

            Integer number = numbers.get(i);

            if (number.intValue() < min) {

                min = number.intValue();

            }

        }

        return min;

    }

 

    private static int getSum(List numbers) {

        int sum = (int) (numbers.get(0));

        for (int i = 1; i < numbers.size(); i++) {

            sum += (int) numbers.get(i);

        }

        return sum;

    }

 

    private static int getAverage(List<Integer> numbers) {

        return getSum(numbers) / numbers.size();

    }

}

  

執行以上腳本,輸出結果爲:

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

40

41

42

43

44

45

46

47

使用Java7:

列表:[abc,, bc, efg, abcd,, jkl]

空字符數量爲:2

字符串長度爲3的數量爲:3

篩選後的列表:[abc, bc, efg, abcd, jkl]

合併字符串: abc, bc, efg, abcd, jkl

平方數列表:[9,4,49,25]

列表:[1,2,13,4,15,6,17,8,19]

列表中最大的數:19

列表中最小的數:1

所有數之和:85

平均數:9

隨機數:

-393170844

-963842252

447036679

-1043163142

-881079698

221586850

-1101570113

576190039

-1045184578

1647841045

使用Java8:

列表:[abc,, bc, efg, abcd,, jkl]

空字符串數量爲:2

字符串長度爲3的數量爲:3

篩選後的列表:[abc, bc, efg, abcd, jkl]

合併字符串: abc, bc, efg, abcd, jkl

SquaresList:[9,4,49,25]

列表:[1,2,13,4,15,6,17,8,19]

列表中最大的數:19

列表中最小的數:1

所有數之和:85

平均數:9.444444444444445

隨機數:

-1743813696

-1301974944

-1299484995

-779981186

136544902

555792023

1243315896

1264920849

1472077135

1706423674

空字符串的數量爲:2

  

六、Java 8 Optional 類

Optional 類是一個可以爲null的容器對象。如果值存在則isPresent()方法會返回true,調用get()方法會返回該對象。

Optional 是個容器:它可以保存類型T的值,或者僅僅保存null。Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測。

Optional 類的引入很好的解決空指針異常。

6.1類聲明

以下是一個 java.util.Optional<T> 類的聲明:

publicfinalclassOptional<T> extendsObject

6.2 類方法
 

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

40

41

42

43

44

45

46

47

序號

方法 & 描述

1

static <T> Optional<T> empty()

返回空的 Optional 實例。

2

boolean equals(Object obj)

判斷其他對象是否等於 Optional。

3

Optional<T> filter(Predicate<? super <T> predicate)

如果值存在,並且這個值匹配給定的 predicate,返回一個Optional用以描述這個值,否則返回一個空的Option Optional。

4

<U> Optional<U> flatMap(Function<? super T,Optional<U>> mapper)

如果值存在,返回基於Optional包含的映射方法的值,否則返回一個空的Optional

5

T get()

如果在這個Optional中包含這個值,返回值,否則拋出異常:NoSuchElementException

6

int hashCode()

返回存在值的哈希碼,如果值不存在返回 0

7

void ifPresent(Consumer<? super T> consumer)

如果值存在則使用該值調用 consumer , 否則不做任何事情。

8

boolean isPresent()

如果值存在則方法會返回true,否則返回 false

9

<U>Optional<U> map(Function<? super T,? extends U> mapper)

如果存在該值,提供的映射方法,如果返回非null,返回一個Optional描述結果。

10

static <T> Optional<T> of(T value)

返回一個指定非null值的Optional。

11

static <T> Optional<T> ofNullable(T value)

如果爲非空,返回 Optional 描述的指定值,否則返回空的 Optional。

12

T orElse(T other)

如果存在該值,返回值,否則返回 other。

13

T orElseGet(Supplier<? extends T> other)

如果存在該值,返回值,否則觸發 other,並返回 other 調用的結果。

14

<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)

如果存在該值,返回包含的值,否則拋出由 Supplier 繼承的異常

15

String toString()

返回一個Optional的非空字符串,用來調試

  

注意: 這些方法是從 java.lang.Object 類繼承來的。


6.3  Optional 實例

我們可以通過以下實例來更好的瞭解 Optional 類的使用:

Java8Tester.java文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

public class Java8Tester {

    public static void main(String args[]) {

        Java8Tester java8Tester = new Java8Tester();

        Integer value1 = null;

        Integer value2 = new Integer(10);

        // Optional.ofNullable - 允許傳遞爲 null 參數

        Optional<Integer> a = Optional.ofNullable(value1);

        // Optional.of - 如果傳遞的參數是 null,拋出異常 NullPointerException

        Optional<Integer> b = Optional.of(value2);

        System.out.println(java8Tester.sum(a, b));

    }

 

    public Integer sum(Optional<Integer> a, Optional<Integer> b) {

        // Optional.isPresent - 判斷值是否存在

        System.out.println("第一個參數值存在: " + a.isPresent());

        System.out.println("第二個參數值存在: " + b.isPresent());

        // Optional.orElse - 如果值存在,返回它,否則返回默認值

        Integer value1 = a.orElse(new Integer(0));

        //Optional.get - 獲取值,值需要存在

        Integer value2 = b.get();

        return value1 + value2;

    }

}

  

執行以上腳本,輸出結果爲:

1

2

3

第一個參數值存在:false

第二個參數值存在:true

10

  

七、Java 8 Nashorn JavaScript

Nashorn 一個 javascript 引擎。

從JDK1.8開始,Nashorn取代Rhino(JDK 1.6, JDK1.7)成爲Java的嵌入式JavaScript引擎。Nashorn完全支持ECMAScript 5.1規範以及一些擴展。它使用基於JSR292的新語言特性,其中包含在JDK 7中引入的 invokedynamic,將JavaScript編譯成Java字節碼。

與先前的Rhino實現相比,這帶來了2到10倍的性能提升。

7.1 jjs

jjs是個基於Nashorn引擎的命令行工具。它接受一些JavaScript源代碼爲參數,並且執行這些源代碼。

例如,我們創建一個具有如下內容的sample.js文件:

1

print('Hello World!');

  


打開控制檯,輸入以下命令:

1

$ jjs sample.js

  


以上程序輸出結果爲:

1

HelloWorld!

  


7.2  jjs 交互式編程

打開控制檯,輸入以下命令:

1

2

3

4

5

$ jjs

jjs>print("Hello, World!")

Hello,World!

jjs> quit()

>>

  


7.3 傳遞參數

1

2

3

4

5

6

打開控制檯,輸入以下命令:

 

$ jjs -- a b c

jjs>print('字母: '+arguments.join(", "))

字母: a, b, c

jjs>

  

1

2

3

4

5

7.4  Java 中調用 JavaScript

 

使用ScriptEngineManager, JavaScript 代碼可以在 Java 中執行,實例如下:

 

Java8Tester.java文件

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public class Java8Tester {

    public static void main(String args[]) {

 

        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();

        ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");

 

        String name = "Runoob";

        Integer result = null;

 

        try {

            nashorn.eval("print('" + name + "')");

            result = (Integer) nashorn.eval("10 + 2");

 

        catch (ScriptException e) {

            System.out.println("執行腳本錯誤: " + e.getMessage());

        }

 

        System.out.println(result.toString());

    }

}

  

執行以上腳本,輸出結果爲:

1

2

Runoob

12

  

7.5  JavaScript 中調用 Java

以下實例演示瞭如何在 JavaScript 中引用 Java 類:

1

2

3

4

5

6

7

8

9

10

11

12

varBigDecimal=Java.type('java.math.BigDecimal');

  

function calculate(amount, percentage){

  

   var result =newBigDecimal(amount).multiply(

   newBigDecimal(percentage)).divide(newBigDecimal("100"),2,BigDecimal.ROUND_HALF_EVEN);

    

   return result.toPlainString();

}

  

var result = calculate(568000000000000000023,13.9);

print(result);

  

我們使用jjs 命令執行以上腳本,輸出結果如下:

 

1

2

$ jjs sample.js

78952000000000002017.94

  

八、Java 8 日期時間 API

Java 8通過發佈新的Date-Time API (JSR 310)來進一步加強對日期與時間的處理。

在舊版的Java 中,日期時間API 存在諸多問題,其中有:

·        非線程安全 − java.util.Date 是非線程安全的,所有的日期類都是可變的,這是Java日期類最大的問題之一。

·        設計很差 − Java的日期/時間類的定義並不一致,在java.util和java.sql的包中都有日期類,此外用於格式化和解析的類在java.text包中定義。java.util.Date同時包含日期和時間,而java.sql.Date僅包含日期,將其納入java.sql包並不合理。另外這兩個類都有相同的名字,這本身就是一個非常糟糕的設計。

·        時區處理麻煩 − 日期類並不提供國際化,沒有時區支持,因此Java引入了java.util.Calendar和java.util.TimeZone類,但他們同樣存在上述所有的問題。

Java 8 在 java.time 包下提供了很多新的 API。以下爲兩個比較重要的 API:

·        Local(本地) − 簡化了日期時間的處理,沒有時區的問題。

·        Zoned(時區) − 通過制定的時區處理日期時間。

新的java.time包涵蓋了所有處理日期,時間,日期/時間,時區,時刻(instants),過程(during)與時鐘(clock)的操作。

8.1 本地化日期時間 API

LocalDate/LocalTime 和 LocalDateTime 類可以在處理時區不是必須的情況。代碼如下:

Java8Tester.java文件
 

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

public class Java8Tester {

    public static void main(String args[]) {

        Java8Tester java8tester = new Java8Tester();

        java8tester.testLocalDateTime();

    }

 

    public void testLocalDateTime() {

        // 獲取當前的日期時間

        LocalDateTime currentTime = LocalDateTime.now();

        System.out.println("當前時間: " + currentTime);

        LocalDate date1 = currentTime.toLocalDate();

        System.out.println("date1: " + date1);

        Month month = currentTime.getMonth();

        int day = currentTime.getDayOfMonth();

        int seconds = currentTime.getSecond();

        System.out.println("月: " + month + ", 日: " + day + ", 秒: " + seconds);

        LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);

        System.out.println("date2: " + date2);

        // 12 december 2014

        LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);

        System.out.println("date3: " + date3);

        // 22 小時 15 分鐘

        LocalTime date4 = LocalTime.of(2215);

        System.out.println("date4: " + date4);

        // 解析字符串

        LocalTime date5 = LocalTime.parse("20:15:30");

        System.out.println("date5: " + date5);

    }

}

  

執行以上腳本,輸出結果爲:

當前時間: 2018-06-08T15:19:16.910

date1:2018-06-08

月: JUNE, 日: 8, 秒: 16

date2:2012-06-10T15:19:16.910

date3:2014-12-12

date4:22:15

date5:20:15:30

8.2 使用時區的日期時間API

如果我們需要考慮到時區,就可以使用時區的日期時間API:

Java8Tester.java文件
 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public class Java8Tester {

    public static void main(String args[]) {

        Java8Tester java8tester = new Java8Tester();

        java8tester.testZonedDateTime();

    }

 

    public void testZonedDateTime() {

        // 獲取當前時間日期

        ZonedDateTime date1 = ZonedDateTime.parse("2015-12-03T10:15:30+05:30[Asia/Shanghai]");

        System.out.println("date1: " + date1);

        ZoneId id = ZoneId.of("Europe/Paris");

        System.out.println("ZoneId: " + id);

        ZoneId currentZone = ZoneId.systemDefault();

        System.out.println("當期時區: " + currentZone);

    }

}

  

執行以上腳本,輸出結果爲:

date1:2015-12-03T10:15:30+08:00[Asia/Shanghai]

ZoneId:Europe/Paris

當期時區: Asia/Shanghai

 

九、Java8 Base64

在Java8中,Base64編碼已經成爲Java類庫的標準。

Java 8 內置了 Base64 編碼的編碼器和解碼器。

Base64工具類提供了一套靜態方法獲取下面三種BASE64編解碼器:

·        基本:輸出被映射到一組字符A-Za-z0-9+/,編碼不添加任何行標,輸出的解碼僅支持A-Za-z0-9+/。

·        URL:輸出映射到一組字符A-Za-z0-9+_,輸出是URL和文件。

·        MIME:輸出隱射到MIME友好格式。輸出每行不超過76字符,並且使用'\r'並跟隨'\n'作爲分割。編碼輸出最後沒有行分割。

9.1 內嵌類

9.2 方法

 

注意:Base64 類的很多方法從 java.lang.Object 類繼承。


9.3  Base64 實例

以下實例演示了Base64 的使用:

Java8Tester.java文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

public class Java8Tester {

    public static void main(String args[]) {

        try {

            // 使用基本編碼

            String base64encodedString = Base64.getEncoder().encodeToString("runoob?java8".getBytes("utf-8"));

            System.out.println("Base64 編碼字符串 (基本) :" + base64encodedString);

            // 解碼

            byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);

            System.out.println("原始字符串: " new String(base64decodedBytes, "utf-8"));

            base64encodedString = Base64.getUrlEncoder().encodeToString("TutorialsPoint?java8".getBytes("utf-8"));

            System.out.println("Base64 編碼字符串 (URL) :" + base64encodedString);

            StringBuilder stringBuilder = new StringBuilder();

            for (int i = 0; i < 10; ++i) {

                stringBuilder.append(UUID.randomUUID().toString());

            }

            byte[] mimeBytes = stringBuilder.toString().getBytes("utf-8");

            String mimeEncodedString = Base64.getMimeEncoder().encodeToString(mimeBytes);

            System.out.println("Base64 編碼字符串 (MIME) :" + mimeEncodedString);

        catch (UnsupportedEncodingException e) {

            System.out.println("Error :" + e.getMessage());

        }

    }

}

  

執行以上腳本,輸出結果爲:

1

2

3

4

5

6

7

8

9

10

Base64 編碼字符串 (基本) :cnVub29iP2phdmE4

原始字符串: runoob?java8

Base64編碼字符串(URL):VHV0b3JpYWxzUG9pbnQ_amF2YTg=

Base64編碼字符串(MIME):MjY5OGRlYmEtZDU0ZS00MjY0LWE3NmUtNzFiNTYwY2E4YjM1NmFmMDFlNzQtZDE2NC00MDk3LTlh

ZjItYzNkNGJjNmQwOWE2OWM0NDJiN2YtOGM4Ny00MjhkLWJkMzgtMGVlZjFkZjkyYjJhZDUwYzk0

ZWMtNDE5ZC00MTliLWEyMTAtZGMyMjVkYjZiOTE3ZTkxMjljMTgtNjJiZC00YTFiLTg3MzAtOTA0

YzdjYjgxYjQ0YTUxOWNkMTAtNjgxZi00YjQ0LWFkZGMtMzk1YzRkZjIwMjcyMzA0MTQzN2ItYzBk

My00MmQyLWJiZTUtOGM0MTlmMWIxM2MxYTY4NmNiOGEtNTkxZS00NDk1LThlN2EtM2RjMTZjMWJk

ZWQyZTdhNmZiNDgtNjdiYy00ZmFlLThjNTYtMjcyNDNhMTRhZTkyYjNiNWY2MmEtNTZhYS00ZDhk

LWEwZDYtY2I5ZTUwNzJhNGE1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章