Java 自學筆記 05 - Set & Map

Set

Set 的關係圖如下:
Java Set Interface

比較常用的:

  • HashSet: 不保證保存順序,速度最快
  • LinkedHashSet: 保存順序與存入順序相同
  • TreeSet: 依元素的大小排序,存入的元素必須是可比較的

Basic Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Set<String> set = new HashSet<>(); 
// Set<String> set = new LinkedHashSet<>();
// Set<String> set = new TreeSet<>();

set.add("Jack");
set.add("Emma");
set.add("Kevin");
set.add("Jack");

set.contains("Tom") // False
set.remove("Tom"); // False

set.size(); // 3 ([Kevin, Jack, Emma])
set.isEmpty(); // False
// set.clear();

Iterations

Iterator 是老用法了不太推薦,用 for 跟 forEach 好多了

1
2
3
4
5
6
7
8
9
10
11
12
Iterator<String> newSet = set.iterator();     
while (newSet.hasNext()) {
System.out.println(newSet.next());
}
// or
for (String name: set){
System.out.println(name);
}
// or
set.forEach((name)->{
System.out.println(name);
});

Set Operations

set 很適合用來做交集聯集等操作。

Set Operation

1
2
3
4
5
6
7
8
9
10
11
String[] source = {"Jack", "Tom"};
Set<String> set2 = new HashSet<>(Arrays.asList(source));

// union
set.addAll(set2); // [Kevin, Tom, Jack, Emma]

// intersection
set.retainAll(set2); // [Jack]

// difference (自己那邊)
set.removeAll(set2); // [Kevin, Emma]

Map

Map 的關係圖下:
Java Map Interface

上圖最左邊的 Hashtable 跟 Vector 一樣是老舊的語法,透過 synchronized 同步以實現線程安全,性能不佳,大多時候都可以被取代掉,真的要確保線程安全可以改用 ConcurrentHashMap

同樣有三種常用的 Map,各自的特色跟對應到的 Set 一模一樣,只是改成存鍵值對:

  • HashMap: 不保證保存順序,速度最快
  • LinkedHashMap: 保存順序與存入順序相同
  • TreeMap: 依元素的大小排序,存入的元素必須是可比較的

Basic Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Map<String, Integer> map = new HashMap<>();
// Map<String, Integer> set = new LinkedHashMap<>();
// Map<String, Integer> set = new TreeMap<>();

map.put("apple", 3);
map.put("banana", 2);
map.put("orange", 4); // return null
map.put("orange", 5); // return 4 (previous value)
System.out.println(map); // {banana=2, orange=5, apple=3}

map.get("apple"); // return 3
map.get("peach"); // return null
map.getOrDefault("peach", 0); // return default 0

// map.remove("apple"); // return 3
map.remove("peach"); // return null

map.isEmpty(); // return false
map.size(); // return 3
// map.clear();

Keys and Values

取用方式基本上類似於 python 的 keys()values()

1
2
3
4
5
6
7
// get keys
Set<String> keys = map.keySet();
System.out.println(keys); // [banana, orange, apple]

// get values
Collection<Integer> values = map.values();
System.out.println(values); // [2, 5, 3]

Iterations

遍歷 Map 有很多方法,這裡示範三種:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1. keySet(),
for (String key: map.keySet()){
System.out.println("key=" + key + ", value=" + map.get(key));
};

// 2. entrySet(),類愈 python 的 items()
for (Map.Entry<String, Integer> entry: map.entrySet()){
System.out.println("key=" + entry.getKey() + ", value=" + entry.getValue());
};

// 3. forEach(),建議使用
map.forEach((key, value) -> {
System.out.println("key=" + key + ", value=" + value);
});

Map Operations

跟 Set 一樣 Map 也可以做 operations,很酷的是我們對 keySet() 進行操作時,其實也會影響到 Map 本身。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Map<String, Integer> map2 = new HashMap<>(){{
put("orange", 1);
put("lemon", 1);
put("starwberry", 2);
}};

// union
map.putAll(map2);
System.out.println(map); // {banana=2, orange=1, apple=3, lemon=1, starwberry=2}

// intersection
map.keySet().retainAll(map2.keySet());
System.out.println(map); // {orange=5}

// difference (left half)
map.keySet().removeAll(map2.keySet());
System.out.println(map); // {banana=2, apple=3}

參考資料

Set in Java - Javapoint
Java Map - Javapoint