1. 程式人生 > 實用技巧 >Java之語言基礎知識(二)

Java之語言基礎知識(二)

8、新增Stream類

JDK1.8新增了Stream類,從而把函數語言程式設計的風格引入到了Java語言中,Stream的API提供了非常強大的功能,使用Stream類後,可以寫出更加強大、更加簡潔的程式碼(例如可以代替迴圈控制語句)。示例程式碼如下:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Cllectors;

class Student{
    
private String name; private Integer age; public Student(String name,Integer age){ this.name = name; this.age = age; } public String getName(){return name;} public Integer getAge(){return age;} } public class Test{ public static void main(String[] args){ List
<Student> list = new ArrayList<>(); list.add(new Student("Wang",10)); list.add(new Student("Li",13)); list.add(new Student("Zhang",10)); list.add(new Student("Zhao",15)); System.out.println("找出年齡為10的第一個學生:"); Optional<Student> s = list.stream().filter(stu->.getAge().equals(10)).findFirst();
if(s.isPresent()) System.out.println(s.get().getName()+","+s.get().getAge());
     System.out.println("找出年齡為10的所有學生:");
     List<Student> searchResult = list.stream().filter(stu->getAge().equals(10)).collect(Collectors.toList());
     for(Student stu: searchResult)
       System.out.println(stu.getName()+","+stu.getAge());
     System.out.println("對學生按年齡分組:");
     Map(Integer,List<Student>)map = list.stream().collect(Collectors.groupingBy(Student::getAge));
     Iterator<Map.Entry<Integer,List<Student>>> iter = map.entrySet().iterator();
     while(iter.hasNext()){
        Map.Entry<Integer,List<Student>> entry = (Map.Entry<Integer,List<Student>>)iter.next();
        int age = entry.getKey();
        System.out.println(age+":");
        List<Student> group = entry.getValue();
        for(Student stu: group)
          System.out.println(stu.getName()+" ");
        System.out.println();
      }
    }
}

程式的執行結果為:

此外,Stream類還提供了parallel、map、reduce等方法,這些方法用於增加對原生類併發處理的能力。

9、日期新特性

在JDK1.8之前,處理日期相關的類主要有如下三個:

  • Calendar:實現日期和時間欄位之間轉換,它的屬性是可變的。因此它不是執行緒安全的。
  • DateFormat:格式化和分析日期字串。
  • Date:用來承載日期和時間資訊,它的屬性是可變的。因此它不是執行緒安全的。

這些API使用很不方便,而且有很多缺點,以如下程式碼為例:

Date date = new Date(2015,10,1);
System.out.println(date);

在Date類傳入引數中,月份為10月,輸出卻為Mon Nov 01 00:00:00 CST3915。

JDK1.8對時間相關的API進行了改進,提供了更加強大的API。新的java.time主要包含了處理日期、時間、日期/時間、時區、時刻(Instants)和時鐘(clock)等操作,示例程式碼如下:

import java.time.Clock;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;

public class Test{
public static void main(String[] args){
//Clock類通過指定一個一個時區,可以獲取到當前的時刻、日期和時間
Clock clock = Clock.system(ZoneId.of("Asia/Shanghai"));
System.out.println("測試Clock:");
System.out.println(clock.millis());
System.out.println(clock.instant());

//Instance使用方法
System.out.println("測試Instant:");
Instant instant = Instant.now();
System.out.println(instant.getEpochSecond());//精確到秒
System.out.println(instant.toEpochMilli());//精確到毫秒

//LocalDate以ISO-8601格式顯示的日期型別,無時區資訊
LocalDate date = LocalDate.now();
LocalDate dateFromClock = LocalDate.now(clock);
System.out.println("測試LocalDate:");
System.out.println(date);
System.out.println(dateFromClock);

//LocalTime是以ISO-8601格式顯示時間型別,無時區資訊
final LocalTime time = LocalTime.now();
final LocalTime timeFromClock = LocalTime.now(clock);
System.out.println("測試LocalTime:");
System.out.println(time);
System.out.println(timeFromClock);

//LocalDate是以ISO-8601格式顯示的日期和時間
final LocalDateTime dateTime = LocalDateTime.now();
final LocalDateTime datetimeFromClock = LocalDateTime.now(clock);
System.out.println("測試LocalDateTime:");
System.out.println(dateTime);
System.out.println(datetimeFromClock);
}
}

程式的執行結果為:

10、增加了呼叫JavaScript的引擎

JDK1.8增加API使得可以通過Java程式來呼叫JavaScript程式碼,示例程式碼如下:

import javax.script.*;
public class Test{
    public static void main(String[] args) throws ScriptException{
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");
        System.out.println(engine.getClass().getName());
        System.out.println(engine.eval("function f() {return 'Hello';};f()+'World!';"));
    }
}

程式的執行結果為:

11、Base64編碼解碼

Base64是一種常見的字元編碼,可用來作為電子郵件或Web Service附件的傳輸編碼。JDK1.8把Base64編碼新增到了標準類庫中。示例程式碼如下:

import java.nio.charset.StandardCharsets;
import java.util.Base64;
public class Test{
    public static void main(String[] args) {
        String string = "Hello World";
        String encodeStr = Base64.getEncoder().encodeToString(string.getBytes(StandardCharsets.UTF_8));
        System.out.println(encodeStr);
        String decodeStr = new String(Base64.getDecoder().decode(encodeStr),StandardCharsets.UTF_8);
        System.out.println(decodeStr);
    }
}

程式的執行結果為:

12、並行陣列

JDK1.8增加了對陣列並行處理的方法(parallelXxx),下面以排序為例介紹其用法:

import java.util.Arrays;
public class Test{
    public static void main(String[] args) {
        int[] arr ={1,5,8,3,19,40,6};
        Arrays.parallelSort(arr);
        Arrays.stream(arr).forEach(i->System.out.print(i+" "));
        System.out.println();
    }
}

1.10 foreach的作用

foreach語句是Java5新增的特徵之一,是for迴圈語句的簡化版本。foreach的使用可以大大地簡化對集合、陣列的遍歷,給開發人員帶來很大的便利。

具體而言,foreach可以看做是for的子集,能用foreach實現的流程一定能用for實現,但是需要注意的是,有些for語句就無法用foreach來實現。而且,foreach只能進行順序遍歷,無法採用索引的形式來訪問陣列。

foreach的語句格式如下:

for(型別元素變數x:遍歷物件obj){

  //使用x

}

foreach並不是一個Java的關鍵字,習慣上把這種特殊的for語句的格式成為“foreach”。下面給出一個使用foreach方法遍歷陣列的例子:

public class Test{
    public static void main(String[] args) {
        int arr[]={1,2,3};
        //遍歷一維陣列
        for (int i:arr) {
            System.out.println(i);
        }
        int arr1[][]={{1,2},{3,4}};
        //遍歷二維陣列
        for(int[] i:arr1){
            for (int j:i){
                System.out.println(j);
            }
        }
    }
}

1.11 SimpleDateFormat

SimpleDateFormat是一個以國別敏感的方式格式化和分析資料的具體類,主要用來對日期和字串進行轉換,同時可以指定字串的格式,因此,在專案開發中經常被用到。下面給出用“yyyy/MM/dd HH:mm:ss”形式來顯示當前時間的程式碼。

import java.text.SimpleDateFormat;
import java.util.Date;
public class Test{
    public static void main(String[] args) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        Date curdate = new Date();
        System.out.println(simpleDateFormat.format(curdate));
    }
}

程式的執行結果為:

需要注意的是,DateFormat類和SimpleDateFormat類都不是執行緒安全的,在多執行緒環境下,呼叫format()方法和parse()方法應該使用同步程式碼來避免問題。

1.12 迴圈

1.12.1 for迴圈

for迴圈語句的基本結構為:

for(表示式1;表示式2;表示式3){

迴圈體

}

它的執行過程如下:

(1)首先執行初始化語句:表示式1(只會被執行一次)。

(2)然後執行表示式2,如果表示式2的結果為false,則結束迴圈,否則執行迴圈體,然後執行表示式3.

(3)迴圈執行步驟2,直到表示式2的結果為false時,退出迴圈,或者迴圈體內有退出迴圈的語句(return或break)。

示例程式碼如下:

public class Test{
    static boolean f(char c){
        System.out.print(c);
        return true;
    }
    public static void main(String[] args) {
        int i=0;
        for(f('A');f('B')&&(i<2);f('C')){
            i++;
            f('D');
        }
    }
}

程式執行結果為:

1.12.2 while迴圈或do/while迴圈

相比for迴圈而言,程式執行更加簡單。while迴圈的基本結構為:

while(表示式){

迴圈體

}

當滿足表示式時,執行迴圈體。

1.13 &和&&的區別

&是按位與操作符,a&b是吧a和b都轉換為二進位制數後,然後再進行按位與的運算。而&&為邏輯與操作符,a&&b就是當且僅當兩個運算元均為true時結果才為true,只要有一個為false,a&&b的結果就為false。

此外,&&還具有短路的功能,在參與運算的兩個表示式中,只有當第一個表示式的返回值為true時,不會去計算第二個表示式的值。

二、訪問修飾符

2.1 訪問修飾符的作用範圍

在Java語言中,類的許可權訪問修飾符有以下幾種:private、default(package)、protected和public。以下將具體對這幾個許可權訪問修飾符進行介紹。

(1)私有許可權(private):private可以修飾資料成員、構造方法和方法成員,不可以修飾類(外部類,不考慮內部類)。被private修飾的成員,只能在定義他們的類中使用,在其他類中不能呼叫。

(2)預設許可權(default):類、資料成員、構造方法和方法成員等都能夠使用預設許可權,即不被private、protected和public修飾。預設許可權即同包許可權,同包許可權的元素只能在定義他們的類中以及同包的類中被呼叫。

(3)受保護許可權(protected):protected可以修飾資料成員、構造方法和方法成員,不可以修飾類*(外部類,不考慮內部類)。被protected修飾的類只能在定義它的類和子類中才能訪問。

(4)公共許可權(public):public可以修飾類、資料成員、構造防範和方法成員。被public修飾的成員可以在任何一個類中被呼叫。不管同包不同包,是許可權最大的一個修飾符。被public修飾的類或者介面必須與檔名相同。

以上幾種修飾符的作用範圍詳見下表:

範圍 private default protected public
同一類
同一包中的類 ×
當前類或者子類 × ×
所有 × × ×

因此,訪問修飾符的作用範圍由大到小依次是:public、protected、default、private。

2.2 包(package)

在Java語言中,包是一個比較抽象的邏輯概念,它的宗旨是把.java檔案(Java原始檔)、.class檔案(編譯後的位元組碼檔案)以及其他的resource檔案(例如xml檔案、avi檔案、txt檔案等)有條理地進行組織,以供使用。它類似於Linux系統的檔案系統,有一個根,然後從根開始有目錄和檔案,目錄中巢狀有目錄。

原始碼中如果有package語句,必須放在程式碼的第一行,指明該檔案中定義的類所在的包。而import語句允許開發人員在編譯時將其他類的原始碼包含到原始檔中,具體而言,import語句包括import關鍵字、以及點(.)分割的包路徑、類名或型號(*)。需要注意的是,每條import語句只能對應一個包。

2.3 main方法

在Java中,main方法是程式的入口方法,一個程式要想執行必須要有main方法,但是隻有滿足特定條件的main防範才能作為程式的入口方法。由於java語言是純面嚮物件語言,所以所有的屬性與方法都必須定義在類裡面。Java程式可以定義多個main方法,但是隻有public static void main(String[] args)方法才是Java程式的入口方法,其他main方法都不是,並且這個入口方法必須被定義在類名與檔名相同的被public修飾的類中。如下所示:

class T{
    public static void main(String[] args){
        System.out.println("T main");
    }
}
public class Test{
    //程式入口方法
    public static void main(String[] args) {
        System.out.println("Test main");
    }
}

程式的執行結果為:

從上例可以看出,這個程式中定義了多個main方法,但是隻有滿足特定條件的main方法才能作為程式的入口方法。在Java語言中,一個檔案內部可以有多個類的存在,但只有被public修飾的類的名字與檔案的名字相同,其他類的名字可以根據需求隨意起名字。並且在方法體中不管有多少條語句,所有的方法體都必須用大括號{}括起來。

=========================分割線===========================

2020-07-21

21:44:38