1. 程式人生 > 其它 >Java基礎(7)

Java基礎(7)

技術標籤:Java基礎Java基礎java程式語言

文章目錄

Java集合、泛型和列舉

Java 8中Map新增的方法

Java 8 除了為 Map 增加了 remove(Object key, Object value) 預設方法之外,還增加了如下方法

名稱說明
Object compute(Object key, BiFunction remappingFunction)該方法使用 remappingFunction 根據原 key-value 對計算一個新 value。只要新 value 不為 null,就使用新 value 覆蓋原 value;如果原 value 不為 null,但新 value 為 null,則刪除原 key-value 對;如果原 value、新 value 同時為 null,那麼該方法不改變任何 key-value 對,直接返回 null。
Object computeIfAbsent(Object key, Function mappingFunction)如果傳給該方法的 key 引數在 Map 中對應的 value 為 null,則使用 mappingFunction 根據 key 計算一個新的結果,如果計算結果不為 null,則用計算結果覆蓋原有的 value。如果原 Map 原來不包括該 key,那麼該方法可能會新增一組 key-value 對。
Object computeIfPresent(Object key, BiFunction remappingFunction)如果傳給該方法的 key 引數在 Map 中對應的 value 不為 null,該方法將使用 remappingFunction 根據原 key、value 計算一個新的結果,如果計算結果不為 null,則使用該結果覆蓋原來的 value;如果計算結果為 null,則刪除原 key-value 對。
void forEach(BiConsumer action)該方法是 Java 8 為 Map 新增的一個遍歷 key-value 對的方法,通過該方法可以更簡潔地遍歷 Map 的 key-value 對。
Object getOrDefault(Object key, V defaultValue)獲取指定 key 對應的 value。如果該 key 不存在,則返回 defaultValue。
Object merge(Object key, Object value, BiFunction remappingFunction)該方法會先根據 key 引數獲取該 Map 中對應的 value。如果獲取的 value 為 null,則直接用傳入的 value 覆蓋原有的 value(在這種情況下,可能要新增一組 key-value 對);如果獲取的 value 不為 null,則使用 remappingFunction 函式根據原 value、新 value 計算一個新的結果,並用得到的結果去覆蓋原有的 value。
Object putIfAbsent(Object key, Object value)該方法會自動檢測指定 key 對應的 value 是否為 null,如果該 key 對應的 value 為 null,該方法將會用新 value 代替原來的 null 值。
Object replace(Object key, Object value)將 Map 中指定 key 對應的 value 替換成新 value。與傳統 put() 方法不同的是,該方法不可能新增新的 key-value 對。如果嘗試替換的 key 在原 Map 中不存在,該方法不會新增 key-value 對,而是返回 null。
boolean replace(K key, V oldValue, V newValue)將 Map 中指定 key-value 對的原 value 替換成新 value。如果在 Map 中找到指定的 key-value 對,則執行替換並返回 true,否則返回 false。
replaceAll(BiFunction function)該方法使用 BiFunction 對原 key-value 對執行計算,並將計算結果作為該 key-value 對的 value 值。

下面程式示範了 Map 常用預設方法的功能和用法

import java.util.Map;
import java.util.HashMap;

public class Test13 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		 Map map = new HashMap();
        // 成對放入多個key-value對
        map.put("Java入門教程", 10);
        map.put("C語言入門教程", 20);
        map.put("Python基礎教程", 30);
        
        // 嘗試替換key為”Go語言入門教程”的 value,由於原 Map 中沒有對應的 key
        // 因此Map沒有改變,不會新增新的key-value對
        map.replace("Go語言入門教程", 40);
        System.out.println(map);
        // 使用原value與傳入引數計算出來的結果覆蓋原有的value,oldVal此時為原來的20,param為傳入的25
        map.merge("C語言入門教程", 25, (oldVal, param) -> (Integer) oldVal + (Integer) param);
        System.out.println(map);
        map.merge("C語言入門教程2", 35, (oldVal, param) -> (Integer) oldVal + (Integer) param);
        System.out.println(map);
        // 當key為"Java"對應的value為null (或不存在)時,使用計算的結果作為新value
        map.computeIfAbsent("Java", (key) -> ((String) key).length());
        System.out.println(map); // map 中添加了 Java=4 這組 key-value 對
        // 當key為"Java"對應的value存在時,使用計算的結果作為新value
        map.computeIfPresent("Java", (key, value) -> (Integer) value * (Integer) value);
        System.out.println(map); // map 中 Java=4 變成 Java=16
	}
}

Java Collections類操作集合詳解

Collections 類是 Java 提供的一個操作 Set、List 和 Map 等集合的工具類。Collections 類提供了許多操作集合的靜態方法,藉助這些靜態方法可以實現集合元素的排序、查詢替換和複製等操作

排序(正向和逆向)

Collections 提供瞭如下方法用於對 List 集合元素進行排序。

  • void reverse(List list):對指定 List 集合元素進行逆向排序。
  • void shuffle(List list):對 List 集合元素進行隨機排序(shuffle 方法模擬了“洗牌”動作)。
  • void sort(List list):根據元素的自然順序對指定 List 集合的元素按升序進行排序。
  • void sort(List list, Comparator c):根據指定 Comparator 產生的順序對 List 集合元素進行排序。
  • void swap(List list, int i, int j):將指定 List 集合中的 i 處元素和 j 處元素進行交換。
  • void rotate(List list, int distance):當 distance 為正數時,將 list集合的後distance 個元素“整體”移到前面;當 distance 為負數時,將 list 集合的前 distance 個元素“整體”移到後面。該方法不會改變集合的長度。

對陣列進行排序後輸出

import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

public class Test13 {
	
	public void test2() {
		List prices = new ArrayList();
		prices.add(11);
		prices.add(2);
		prices.add(14);
		prices.add(8);
		Collections.sort(prices);
		System.out.println(prices); // [2, 8, 11, 14]
		Collections.reverse(prices);
		System.out.println(prices); // [2, 8, 11, 14]
	}
	
	public static void main(String[] args) {
		new Test13().test2();
	}

}

查詢、替換操作

Collections 還提供瞭如下常用的用於查詢、替換集合元素的方法。

  • int binarySearch(List list, Object key):使用二分搜尋法搜尋指定的 List 集合,以獲得指定物件在 List 集合中的索引。如果要使該方法可以正常工作,則必須保證 List 中的元素已經處於有序狀態。
  • Object max(Collection coll):根據元素的自然順序,返回給定集合中的最大元素。
  • Object max(Collection coll, Comparator comp):根據 Comparator 指定的順序,返回給定集合中的最大元素。
  • Object min(Collection coll):根據元素的自然順序,返回給定集合中的最小元素。
  • Object min(Collection coll, Comparator comp):根據 Comparator 指定的順序,返回給定集合中的最小元素。
  • void fill(List list, Object obj):使用指定元素 obj 替換指定 List 集合中的所有元素。
  • int frequency(Collection c, Object o):返回指定集合中指定元素的出現次數。
  • int indexOfSubList(List source, List target):返回子 List 物件在父 List 物件中第一次出現的位置索引;如果父 List 中沒有出現這樣的子 List,則返回 -1。
  • int lastIndexOfSubList(List source, List target):返回子 List 物件在父 List 物件中最後一次出現的位置索引;如果父 List 中沒有岀現這樣的子 List,則返回 -1。
  • boolean replaceAll(List list, Object oldVal, Object newVal):使用一個新值 newVal 替換 List 物件的所有舊值 oldVal。

對陣列使用 Collections 類中的 fill() 方法對商品資訊進行重置操作

import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

public class Test13 {
	public void test3() {
		List list = new ArrayList();
		list.add("zengraoli1");
		list.add("zengraoli2");
		list.add("zengraoli3");
		list.add("zengraoli4");
		System.out.println(list);
		Collections.fill(list, "zeng");
		System.out.println(list);
	}
	
	public static void main(String[] args) {
		new Test13().test3();
	}
}

在一個集合中儲存 4 個數據,分別輸出最大最小元素和指定資料在集合中出現的次數。

import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

public class Test13 {
	public void test4() {
		ArrayList nums = new ArrayList();
        nums.add(2);
        nums.add(-5);
        nums.add(3);
        nums.add(0);
        nums.add(-5);
        // 判斷-5在List集合中出現的次數,返回1
        System.out.println(Collections.frequency(nums, -5));
        Collections.sort(nums); // 對 nums集合排序
        System.out.println(nums); // 輸出:[-5, 1, 2, 3]
        // 只有排序後的List集合才可用二分法查詢,輸出3
        System.out.println(Collections.binarySearch(nums, 3));
	}
	public static void main(String[] args) {
		new Test13().test4();
	}
}

複製

Collections 類的 copy() 靜態方法用於將指定集合中的所有元素複製到另一個集合中。執行 copy() 方法後,目標集合中每個已複製元素的索引將等同於源集合中該元素的索引。

copy() 方法的語法格式如下,其中,dest 表示目標集合物件,src 表示源集合物件

void copy(List <? super T> dest,List<? extends T> src)

Java使用Lambda表示式遍歷Collection集合

Java 8 為 Iterable 介面新增了一個 forEach(Consumer action) 預設方法,該方法所需引數的型別是一個函式式介面,而 Iterable 介面是 Collection 介面的父介面,因此 Collection 集合也可直接呼叫該方法。

當程式呼叫 Iterable 的 forEach(Consumer action) 遍歷集合元素時,程式會依次將集合元素傳給 Consumer 的 accept(T t) 方法(該介面中唯一的抽象方法)。正因為 Consumer 是函式式介面,因此可以使用 Lambda 表示式來遍歷集合元素

如下程式示範了使用 Lambda 表示式來遍歷集合元素

import java.util.List;
import java.util.ArrayList;

public class Test14 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List list = new ArrayList();
		list.add("zengraoli1");
		list.add("zengraoli2");
		list.add("zengraoli3");
		list.forEach(obj -> System.out.println("迭代集合元素:" + obj));
	}
}

上面程式中呼叫了 Iterable 的 forEach() 預設方法來遍歷集合元素,傳給該方法的引數是一個 Lambda 表示式,該 Lambda 表示式的目標型別是 Comsumer。forEach() 方法會自動將集合元素逐個地傳給 Lambda 表示式的形參,這樣 Lambda 表示式的程式碼體即可遍歷到集合元素了

Java Iterator(迭代器)遍歷Collection集合元素

Iterator 介面隱藏了各種 Collection 實現類的底層細節,嚮應用程式提供了遍歷 Collection 集合元素的統一程式設計介面。Iterator 接口裡定義瞭如下 4 個方法。

  • boolean hasNext():如果被迭代的集合元素還沒有被遍歷完,則返回 true。
  • Object next():返回集合裡的下一個元素。
  • void remove():刪除集合裡上一次 next 方法返回的元素。
  • void forEachRemaining(Consumer action):這是 Java 8 為 Iterator 新增的預設方法,該方法可使用 Lambda 表示式來遍歷集合元素

下面是使用forEachRemaining的程式碼,即Java Lambda表示式遍歷迭代器

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class Test14 {

	public void test2() {
		Collection objs = new HashSet();
        objs.add("zengraoli1");
        objs.add("zengraoli2");
        objs.add("zengraoli3");
        Iterator it = objs.iterator();
        it.forEachRemaining(obj -> System.out.println("迭代集合元素:" + obj));
	}
	
	public static void main(String[] args) {
		new Test14().test2();
	}

}

Java foreach遍歷Collection集合

輸出具有不確定性

public void test3() {
	Collection objs = new HashSet();
    objs.add("zengraoli1");
    objs.add("zengraoli2");
    objs.add("zengraoli3");
    for(Object value:objs) {
    	System.out.println("迭代集合元素:" + value);
    }
}

Predicate操作Collection集合

Java 8 起為 Collection 集合新增了一個 removeIf(Predicate filter) 方法,該方法將會批量刪除符合 filter 條件的所有元素。該方法需要一個 Predicate 物件作為引數,Predicate 也是函式式介面,因此可使用 Lambda 表示式作為引數

如下程式示範了使用 Predicate 來過濾集合,刪掉等於zengraoli3的集合元素

import java.util.Collection;

public class Test14 {

	public void test4() {
		Collection objs = new HashSet();
        objs.add("zengraoli1-1");
        objs.add("zengraoli1-2");
        objs.add("zengraoli3");
        objs.removeIf(els -> els.equals("zengraoli3"));
        System.out.println(objs);
	}
	
	public static void main(String[] args) {
		new Test14().test4();
	}

}

另外一個例子

public class ForeachTest2 {
    public static void main(String[] args) {
        // 建立一個集合
        Collection objs = new HashSet();
        objs.add(new String("C語言中文網Java教程"));
        objs.add(new String("C語言中文網C++教程"));
        objs.add(new String("C語言中文網C語言教程"));
        objs.add(new String("C語言中文網Python教程"));
        objs.add(new String("C語言中文網Go教程"));
        // 統計集合中出現“C語言中文網”字串的數量
        System.out.println(calAll(objs, ele -> ((String) ele).contains("C語言中文網")));
        // 統計集合中出現“Java”字串的數量
        System.out.println(calAll(objs, ele -> ((String) ele).contains("Java")));
        // 統計集合中出現字串長度大於 12 的數量
        System.out.println(calAll(objs, ele -> ((String) ele).length() > 12));
    }
    public static int calAll(Collection books, Predicate p) {
        int total = 0;
        for (Object obj : books) {
            // 使用Predicate的test()方法判斷該物件是否滿足Predicate指定的條件
            if (p.test(obj)) {
                total++;
            }
        }
        return total;
    }
}

上面程式先定義了一個 calAll() 方法,它使用 Predicate 判斷每個集合元素是否符合特定條件,條件將通過 Predicate 引數動態傳入。從上面程式中第 11、13、15 行程式碼可以看到,程式傳入了 3 個 Lambda 表示式,其目標型別都是 Predicate,這樣 calAll() 方法就只會統計滿足 Predicate 條件的圖書

使用Java 8新增的Stream操作Collection集合

Java 8 還新增了 Stream、IntStream、LongStream、DoubleStream 等流式 API,這些 API 代表多個支援序列和並行聚集操作的元素。上面 4 個介面中,Stream 是一個通用的流介面,而 IntStream、LongStream、 DoubleStream 則代表元素型別為 int、long、double 的流。

Java 8 還為上面每個流式 API 提供了對應的 Builder,例如 Stream.Builder、IntStream.Builder、LongStream.Builder、DoubleStream.Builder,開發者可以通過這些 Builder 來建立對應的流。

獨立使用 Stream 的步驟如下:

  • 使用 Stream 或 XxxStream 的 builder() 類方法建立該 Stream 對應的 Builder。
  • 重複呼叫 Builder 的 add() 方法向該流中新增多個元素。
  • 呼叫 Builder 的 build() 方法獲取對應的 Stream。
  • 呼叫 Stream 的聚集方法。

示例程式碼如下

import java.util.stream.IntStream;

public class Test15 {
	public void test1() {
		IntStream is = IntStream.builder().add(20).add(13).add(-2).add(18).build();
		// 下面呼叫聚集方法的程式碼每次只能執行一行
//        System.out.println("is 所有元素的最大值:" + is.max().getAsInt());
//        System.out.println("is 所有元素的最小值:" + is.min().getAsInt());
//        System.out.println("is 所有元素的總和:" + is.sum());
//        System.out.println("is 所有元素的總數:" + is.count());
//        System.out.println("is 所有元素的平均值:" + is.average());
//        System.out.println("is所有元素的平方是否都大於20: " + is.allMatch(ele -> ele * ele > 20));
//        System.out.println("is是否包含任何元素的平方大於20 : " + is.anyMatch(ele -> ele * ele > 20));
        // 將is對映成一個新Stream,新Stream的每個元素是原Stream元素的2倍+1
        IntStream newIs = is.map(ele -> ele * 2 + 1);
        newIs.forEach(p -> System.out.println(p));
        // 等價於下面的寫法
        newIs.forEach(System.out::println);
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Test15().test1();
	}
}

上面程式先建立了一個 IntStream,接下來分別多次呼叫 IntStream 的聚集方法執行操作,這樣即可獲取該流的相關資訊。注意:上面 5~13 行程式碼每次只能執行一行,因此需要把其他程式碼註釋掉

Stream 提供了大量的方法進行聚集操作,這些方法既可以是“中間的”(intermediate),也可以是 “末端的”(terminal)。

  • 中間方法:中間操作允許流保持開啟狀態,並允許直接呼叫後續方法。上面程式中的 map() 方法就是中間方法。中間方法的返回值是另外一個流。
  • 末端方法:末端方法是對流的最終操作。當對某個 Stream 執行末端方法後,該流將會被“消耗”且不再可用。上面程式中的 sum()、count()、average() 等方法都是末端方法。

下面簡單介紹一下 Stream 常用的中間方法

方法說明
filter(Predicate predicate)過濾 Stream 中所有不符合 predicate 的元素
mapToXxx(ToXxxFunction mapper)使用 ToXxxFunction 對流中的元素執行一對一的轉換,該方法返回的新流中包含了 ToXxxFunction 轉換生成的所有元素。
peek(Consumer action)依次對每個元素執行一些操作,該方法返回的流與原有流包含相同的元素。該方法主要用於除錯。
distinct()該方法用於排序流中所有重複的元素(判斷元素重複的標準是使用 equals() 比較返回 true)。這是一個有狀態的方法。
sorted()該方法用於保證流中的元素在後續的訪問中處於有序狀態。這是一個有狀態的方法。
limit(long maxSize)該方法用於保證對該流的後續訪問中最大允許訪問的元素個數。這是一個有狀態的、短路方法。

下面簡單介紹一下 Stream 常用的末端方法

方法說明
forEach(Consumer action)遍歷流中所有元素,對每個元素執行action
toArray()將流中所有元素轉換為一個數組
reduce()該方法有三個過載的版本,都用於通過某種操作來合併流中的元素
min()返回流中所有元素的最小值
max()返回流中所有元素的最大值
count()返回流中所有元素的數量
anyMatch(Predicate predicate)判斷流中是否至少包含一個元素符合 Predicate 條件。
allMatch(Predicate predicate)判斷流中是否每個元素都符合 Predicate 條件
noneMatch(Predicate predicate)判斷流中是否所有元素都不符合 Predicate 條件
findFirst()返回流中的第一個元素
findAny()返回流中的任意一個元素

對於前面的程式做一下stream優化的程式碼

import java.util.Collection;
import java.util.HashSet;
import java.util.stream.IntStream;

public class Test15 {
	public void test2() {
		// 建立一個集合
        Collection objs = new HashSet();
        objs.add(new String("C語言中文網Java教程"));
        objs.add(new String("C語言中文網C++教程"));
        objs.add(new String("C語言中文網C語言教程"));
        objs.add(new String("C語言中文網Python教程"));
        objs.add(new String("C語言中文網Go教程"));
//        // 統計集合中出現“C語言中文網”字串的數量
//        System.out.println(objs.stream().filter(ele -> ((String)ele).contains("C++教程")).count());
//        // 統計集合中出現“Java”字串的數量
//        System.out.println(objs.stream().filter(ele -> ((String) ele).contains("Java")).count()); // 輸出 1
//        // 統計集合中出現字串長度大於 12 的數量
//        System.out.println(objs.stream().filter(ele -> ((String) ele).length() > 12).count()); // 輸出 1
        // 先呼叫Collection物件的stream ()方法將集合轉換為Stream
        // 再呼叫Stream的mapToInt()方法獲取原有的Stream對應的IntStream
        objs.stream().mapToInt(ele -> ((String) ele).length())
        // 呼叫forEach()方法遍歷IntStream中每個元素
        .forEach(System.out::println);// 輸出 11 11 12 10 14
	}
	
	public static void main(String[] args) {
		new Test15().test2();
	}

}

參考連結