Java 集合一口气讲完!(下)p\··/q
Java 映射
Java集合教程 - Java映射
映射表示包含的集合键值映射。
Map是一个集合,其中每个元素表示一个键值对作为<key,value> ;.<key,value> 对也称为映射中的条目。键和值必须是引用类型。
映射由 Map<K,V>
接口的实例表示,它不是继承自 Collection
接口。
映射不允许任何重复的键。每个键映射到正好一个值。值不必是唯一的。 两个键可以映射到相同的值。
Map
允许最多一个空值键和多个空值作为其值。
Map接口中的方法可以根据其执行的操作分为以下四类:
- 基本操作
- 批量操作
- 查看操作
- 比较操作
基本操作
基本方法在Map上执行基本操作,
- 将一个条目放入映射
- 获取指定键的值
- 获取条目的数量
- 删除条目
- 检查Map是否为空。
本类别中的方法示例如下:
int size() boolean isEmpty() boolean containsKey (Object key) boolean containsValue (Object value) V get(Object key) V getOrDefault(Object key, V defaultValue) V put(K key, V value) V putIfAbsent(K key, V value) V remove (Object key) boolean remove(Object key, Object value) boolean replace(K key, V oldValue, V newValue)
批量操作
映射批量操作在映射上执行批量操作,例如将条目复制到另一个Map或从映射中删除所有条目。
本类别中的方法示例如下:
void clear() void putAll (Map<? extends K, ? extends V> t) void replaceAll(BiFunction<? super K,? super V,? extends V> function)
查看操作
视图操作包含三种方法。我们可以从映射中查看以下集合。
- 所有键在一个Map中作为一个Set,
- 所有的值作为Collection,
- 所有<key,value>对作为Set。
本类别中的方法示例如下:
Set<K> keySet() Collection<V> values() Set<Map. Entry<K, V>>entrySet()
所有键和所有< key,value> 对在映射中始终是唯一的并作为设置视图返回。
由于映射可能包含重复值,它返回一个 Collection
视图的值。
比较操作
比较操作方法处理比较两个图的相等性。本类别中的方法示例如下:
boolean equals (Object o) int hashCode()
实施
HashMap
, LinkedHashMap
,和 WeakHashMap
是三个实现类用于 Map
界面。
HashMap
允许一个 null
值作为键和多个空值作为值。
以下代码演示了如何创建和使用 Map
接口从它的实现类 HashMap
。HashMap不保证Map中条目的任何特定的迭代顺序。
下面的代码从HashMap创建一个Map
// Create a map using HashMap Map<String, String> map = new HashMap<>(); map.put("CSS", "style");
LinkedHashMap是Map接口的另一个实现类。 它使用双向链表在Map中存储条目,并保持迭代排序作为插入顺序。
以下代码演示了如何使用Map。
import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("CSS", "style"); map.put("HTML", "mark up"); map.put("Oracle", "database"); map.put("XML", "data"); printDetails(map); map.clear(); printDetails(map); } public static void printDetails(Map<String, String> map) { String usage = map.get("CSS"); System.out.println("Map: " + map); System.out.println("Map Size: " + map.size()); System.out.println("Map is empty: " + map.isEmpty()); System.out.println("Map contains CSS key: " + map.containsKey("CSS")); System.out.println("Usage: " + usage); System.out.println("removed: " + map.remove("CSS")); } }
上面的代码生成以下结果。
WeakHashMap
类是 Map
接口的另一种实现。
WeakHashMap
类包含弱键。当除了在映射中没有对键的引用时,键是垃圾回收的候选。
如果一个键被垃圾回收,它的相关条目从 WeakHashMap
中删除。
WeakHashMap
允许一个空键和多个空值。
Java 映射操作
Java集合教程 - Java映射操作
映射迭代
要迭代地图的键,值或条目,使用映射的 keySet()
, values()
和 entrySet
它分别返回一组键,值集合和一组条目。
以下代码段显示了如何打印映射的所有键:
import java.util.HashMap; import java.util.Map; import java.util.Set; public class Main { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("CSS", "style"); map.put("HTML", "mark up"); map.put("Oracle", "database"); map.put("XML", "data"); // Get the set of keys Set<String> keys = map.keySet(); // Print all keys using the forEach() method. keys.forEach(System.out::println); } }
上面的代码生成以下结果。
映射条目
映射中的每个键值对都称为条目。条目由 Map.Entry<K,V>
接口的实例表示。
Map.Entry
是 Map
接口的内部静态接口。
Map.Entry
有三个方法调用 getKey()
, getValue()
和 setValue()
它返回条目的键值,值,并分别在条目中设置新值。
Map的条目集上的典型迭代如下:
import java.util.HashMap; import java.util.Map; import java.util.Set; public class Main { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("CSS", "style"); map.put("HTML", "mark up"); map.put("Oracle", "database"); map.put("XML", "data"); // Get the entry Set Set<Map.Entry<String, String>> entries = map.entrySet(); entries.forEach((Map.Entry<String, String> entry) -> { String key = entry.getKey(); String value = entry.getValue(); System.out.println("key=" + key + ", value=" + value); }); } }
上面的代码生成以下结果。
映射条目迭代
forEach(BiConsumer<?super K,?super V> action)
从 Map
界面遍历映射中的所有条目。
该方法需要一个 BiConsumer
实例第一个参数是键,第二个参数是值用于映射中的当前条目。
import java.util.HashMap; import java.util.Map; public class Main { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("CSS", "style"); map.put("HTML", "mark up"); map.put("Oracle", "database"); map.put("XML", "data"); map.forEach((String key, String value) -> { System.out.println("key=" + key + ", value=" + value); }); } }
上面的代码生成以下结果。
映射视图
以下代码演示了如何获取Map的三个不同视图迭代这些视图中的元素。
import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; public class Main { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("CSS", "style"); map.put("HTML", "mark up"); map.put("Oracle", "database"); map.put("XML", "data"); System.out.println("Map: " + map.toString()); listValues(map); listEntries(map); } public static void listKeys(Map<String, String> map) { System.out.println("Key Set:"); Set<String> keys = map.keySet(); keys.forEach(System.out::println); System.out.println(); } public static void listValues(Map<String, String> map) { System.out.println("Values Collection:"); Collection<String> values = map.values(); values.forEach(System.out::println); System.out.println(); } public static void listEntries(Map<String, String> map) { System.out.println("Entry Set:"); // Get the entry Set Set<Map.Entry<String, String>> entries = map.entrySet(); entries.forEach((Map.Entry<String, String> entry) -> { String key = entry.getKey(); String value = entry.getValue(); System.out.println("key=" + key + ", value=" + value); }); } }
上面的代码生成以下结果。
Java 特殊类型映射
Java集合教程 - Java特殊类型映射
已排序的映射
分类映射按顺序保存映射条目。
它基于键对映射条目进行排序从代码中的 Comparable
接口a Comparator
对象。
如果键实现 Comparable
接口并且您使用 Comparator
对象, Comparator
对象会做排序。
SortedMap
接口继承了Map接口表示排序的映射。
Comparator comparator()
返回用于在SortedMap中进行自定义排序的 Comparator
对象。
K firstKey()
返回SortedMap中第一个条目的键。如果SortedMap为空,它会抛出一个 NoSuchElementException
。
SortedMap headMap(K toKey)
返回其条目的SortedMap的视图将具有小于指定的toKey的键。视图由原始SortedMap支持。
K lastKey()
返回SortedMap中最后一个条目的键。如果SortedMap为空,它会抛出一个NoSuchElementException异常。
SortedMap subMap(K fromKey,K toKey)
返回SortedMap的视图其条目将具有从指定的键fromKey(包含)和toKey(exclusive)。
SortedMap tailMap(K fromKey)
返回其条目的SortedMap的视图将具有等于或大于指定的fromKey的密钥。
TreeMap
类是实现类 SortedMap
界面。下面的代码演示了如何使用 SortedMap
。
import java.util.SortedMap; import java.util.TreeMap; public class Main { public static void main(String[] args) { SortedMap<String, String> sMap = new TreeMap<>(); sMap.put("CSS", "style"); sMap.put("HTML", "mark up"); sMap.put("Oracle", "database"); sMap.put("XML", "data"); SortedMap<String, String> subMap = sMap.subMap("CSS", "XML"); System.out.println(subMap); // Get the first and last keys String firstKey = sMap.firstKey(); String lastKey = sMap.lastKey(); System.out.println("First Key: " + firstKey); System.out.println("Last key: " + lastKey); } }
上面的代码生成以下结果。
SortedMap与Comparator
要使用 Comparator
对象对 SortedMap
中的条目进行排序,使用 TreeMap
类的构造函数以 Comparator
作为参数。
以下代码显示了如何对基于排序映射的条目进行排序在他们的钥匙的长度随后按字母顺序键忽略情况:
import java.util.Comparator; import java.util.SortedMap; import java.util.TreeMap; public class Main { public static void main(String[] args) { Comparator<String> keyComparator = Comparator.comparing(String::length).thenComparing(String::compareToIgnoreCase); SortedMap<String, String> sMap = new TreeMap<>(keyComparator); sMap.put("CSS", "style"); sMap.put("HTML", "mark up"); sMap.put("Oracle", "database"); sMap.put("XML", "data"); SortedMap<String, String> subMap = sMap.subMap("CSS", "XML"); System.out.println(subMap); // Get the first and last keys String firstKey = sMap.firstKey(); String lastKey = sMap.lastKey(); System.out.println("First Key: " + firstKey); System.out.println("Last key: " + lastKey); } }
上面的代码生成以下结果。
导航映射
可导航映射由 NavigableMap
界面的实例表示。
它通过添加方法来扩展 SortedMap
接口对于键的最接近的匹配,以相反的顺序获得映射的视图等。
TreeMap类是NavigableMap接口的实现类。
以下代码显示如何使用 NavigableMap
。
import java.util.Map.Entry; import java.util.NavigableMap; import java.util.TreeMap; public class Main { public static void main(String[] args) { NavigableMap<String, String> nMap = new TreeMap<>(); nMap.put("CSS", "style"); nMap.put("HTML", "mark up"); nMap.put("Oracle", "database"); nMap.put("XML", "data"); System.out.println("Navigable Map:" + nMap); Entry<String, String> lowerXML = nMap.lowerEntry("XML"); Entry<String, String> floorXML = nMap.floorEntry("XML"); Entry<String, String> higherXML = nMap.higherEntry("XML"); Entry<String, String> ceilingXML = nMap.ceilingEntry("XML"); System.out.println("Lower:" + lowerXML); System.out.println("Floor:" + floorXML); System.out.println("Higher:" + higherXML); System.out.println("Ceiling:" + ceilingXML); // Get the reverse order view of the map NavigableMap<String, String> reverseMap = nMap.descendingMap(); System.out.println("Navigable Map(Reverse Order):" + reverseMap); } }
上面的代码生成以下结果。
并发映射
ConcurrentMap
允许我们在不锁定映射的情况下执行并发操作。
我们可以在使用其实现类创建并发映射时选择并发级别。
ConcurrentHashMap类是ConcurrentMap接口的实现类。 它们都在java.util.concurrent包中。
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class Main { public static void main(String[] args) { ConcurrentMap<String, String> cMap = new ConcurrentHashMap<>(); cMap.put("A", "A"); System.out.println("Concurrent Map: " + cMap); System.out.println(cMap.putIfAbsent("A", "1")); System.out.println(cMap.putIfAbsent("B", "B")); System.out.println(cMap.remove("A", "B")); System.out.println(cMap.replace("A", "B")); System.out.println("Concurrent Map: " + cMap); } }
上面的代码生成以下结果。
Java 集合算法
Java集合教程 - Java集合算法
列表排序
Collection类中的两个静态方法会对List进行排序。
- sort(List list)按照由元素实现的Comparable接口定义的顺序对List中的元素进行排序。
- sort(List list,Comparator c)使用传入的Comparator对象对元素进行排序。
我们还可以使用List接口中的sort(Comparator c)对List进行排序,而不使用Collections类。
以下代码演示了如何对 List
进行排序:
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("J"); list.add("R"); list.add("C"); list.add("X"); System.out.println("List: " + list); // Uses Comparable implementation in String class // to sort the list in natural order Collections.sort(list); System.out.println("Sorted List: " + list); } }
上面的代码生成以下结果。
例子
以下代码使用List接口中的sort()方法按其元素长度的升序对列表进行排序:
import java.util.ArrayList; import java.util.Comparator; import java.util.List; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Java"); list.add("R"); list.add("CSS"); list.add("XML"); System.out.println("List: " + list); // Uses List.sort() method with a Comparator list.sort(Comparator.comparing(String::length)); System.out.println("Sorted List: " + list); } }
上面的代码生成以下结果。
sort()
方法使用修改的mergeesort算法,这是一个稳定的排序。
在稳定的排序中,相等的元素将在排序操作之后保持在它们当前的位置。
排序提供了 n*log(n)
性能,其中 n
是列表中元素的数量。
搜索列表
Collections类中的两个静态binarySearch()方法在List中搜索键。
该方法使用二分搜索算法执行搜索。
int binarySearch(List list, T key) int binarySearch(List list, T key, Comparator c)
List
必须按升序排序,然后才能使用 binarySearch()
方法。
如果在列表中找到该键,则该方法将在列表中返回其索引。
如果在列表中没有找到键,它返回( - (insertion_index)-1)
,其中 Math.abs(( - (insertion_index)-1))
是我们可以插入这个键的索引仍然保持列表订购。
在列表中找不到键时,返回值为负值。
以下代码段显示了如何使用此方法:
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Java"); list.add("R"); list.add("CSS"); list.add("XML"); Collections.sort(list); System.out.println("List: " + list); int index = Collections.binarySearch(list, "CSS"); System.out.println("CSS in List is at " + index); index = Collections.binarySearch(list, "Javascript"); System.out.println("Javascript in List is at " + index); } }
上面的代码生成以下结果。
由于“Javascript”不在列表中,二进制搜索返回-3。这意味着如果在列表中插入“Javascript”,它将被插入索引2,使用表达式( - ( - 2 + 1))计算。
随机播放列表
Shuffle给我们一个列表中的元素的随机排列。
来自Collections类的shuffle()方法的两个版本如下:
void shuffle(List list) void shuffle(List list, Random rnd)
以下代码显示如何使用shuffle方法。
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Java"); list.add("R"); list.add("CSS"); list.add("XML"); Collections.sort(list); System.out.println("List: " + list); Collections.shuffle(list); System.out.println("List: " + list); Collections.shuffle(list); System.out.println("List: " + list); } }
上面的代码生成以下结果。
反向列表
我们可以使用 Collections
类的 reverse()
的静态方法来反转列表中的元素。
void reverse(List list)
以下代码显示如何使用 reverse()
方法。
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Java"); list.add("R"); list.add("CSS"); list.add("XML"); Collections.sort(list); System.out.println("List: " + list); Collections.reverse(list); System.out.println("List: " + list); } }
上面的代码生成以下结果。
交换列表项
交换交换列表中的两个元素。
Collections类的 swap()
静态方法执行交换。
void swap(List list, int i, int j)
i
和 j
是两个元素的索引,它们必须在0和size-1之间,其中size是List的大小。
以下代码显示了如何使用这些方法对List的元素重新排序。
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Java"); list.add("R"); list.add("CSS"); list.add("XML"); Collections.sort(list); System.out.println("List: " + list); // Swap elements at indexes 1 and 3 Collections.swap(list, 1, 3); System.out.println(list); } }
上面的代码生成以下结果。
旋转列表
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Main { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("Java"); list.add("R"); list.add("CSS"); list.add("XML"); Collections.sort(list); System.out.println("List: " + list); // Rotate elements by 2 Collections.rotate(list, 2); System.out.println("After Rotating by 2: " + list); } }
上面的代码生成以下结果。
创建集合的不同视图
我们可以使用Collections类的asLifoQueue()静态方法创建Deque的LIFO队列视图:
<T> Queue<T> asLifoQueue(Deque<T> deque)
要将Map的实现用作Set实现,请使用Collections类的 newSetFromMap()
静态方法:
<E> Set<E> newSetFromMap(Map<E, Boolean> map)
只读集合视图
当将集合传递到其他方法时,我们可以获取集合的只读视图,并且我们不希望被调用的方法修改集合。
Collections类提供了以下方法来获取不同类型集合的只读视图:
<T> Collection<T> unmodifiableCollection(Collection<? extends T> c) <T> List<T> unmodifiableList(List<? extends T> list) <K,V> Map<K,V> unmodifiableMap(Map<? extends K,? extends V> m) <K,V> NavigableMap<K,V> unmodifiableNavigableMap(NavigableMap<K,? extends V> m) <T> Set<T> unmodifiableSet(Set<? extends T> s) <T> NavigableSet<T> unmodifiableNavigableSet(NavigableSet<T> s) static <T> SortedSet<T> unmodifiableSortedSet(SortedSet<T> s) <K,V> SortedMap<K,V> unmodifiableSortedMap(SortedMap<K,? extends V> m)
我们传递一个特定类型的集合,并获得相同类型的只读集合。
集合的同步视图
我们可以使用Collections类的以下静态方法之一获取集合的同步视图。
<T> Collection<T> synchronizedCollection(Collection<T> c) <T> List<T> synchronizedList(List<T> list) <K,V> Map<K,V> synchronizedMap(Map<K,V> m) <K,V> NavigableMap<K,V> synchronizedNavigableMap(NavigableMap<K,V> m) <T> NavigableSet<T> synchronizedNavigableSet(NavigableSet<T> s) <T> Set<T> synchronizedSet(Set<T> s) <T> SortedSet<T> synchronizedSortedSet(SortedSet<T> s) <K,V> SortedMap<K,V> synchronizedSortedMap (SortedMap<K,V> m)
检查集合
泛型为集合提供编译时类型安全。
下面的代码有一个编译时错误,因为我们试图添加Integer类型值到一个只能有String值的Set。
Set<String> s = new HashSet<>(); s.add("Hello"); a.add(new Integer(1)); // A compile-time error
我们可以通过使用以下代码绕过编译器检查:
Set<String> s = new HashSet< >(); s.add("Hello"); Set s2 = s; s2.add(new Integer(123)); // No runtime exception
我们可以通过使用检查的集合避免上述错误。Collection类的以下静态方法返回特定类型的已检查集合:
<E> Collection<E> checkedCollection(Collection<E> c, Class<E> type) <E> List<E> checkedList(List<E> list, Class<E> type) <K,V> Map<K,V> checkedMap(Map<K,V> m, Class<K> keyType, Class<V> valueType) <K,V> NavigableMap<K,V> checkedNavigableMap(NavigableMap<K,V> m, Class<K> keyType, Class<V> valueType) <E> NavigableSet<E> checkedNavigableSet(NavigableSet<E> s, Class<E> type) <E> Queue<E> checkedQueue(Queue<E> queue, Class<E> type) <E> Set<E> checkedSet(Set<E> s, Class<E> type) <K,V> SortedMap<K,V> checkedSortedMap(SortedMap<K,V> m, Class<K> keyType, Class<V> valueType) <E> SortedSet<E> checkedSortedSet(SortedSet<E> s, Class<E> type)
下面的代码重写了上面的代码。
Set<String> checkedSet = Collections.checkedSet(new HashSet<String>(), String.class); Set s2 = checkedSet; s2.add(new Integer(1)); // Throws ClassCastException
创建空集合
Collections
类可以返回每种类型的不可变空集合对象。
它也可以返回一个空的迭代器。以下代码在Collections类中列出了这些静态方法:
<T> List<T> emptyList() <K,V> Map<K,V> emptyMap() <T> Set<T> emptySet() <T> Iterator<T> emptyIterator() <T> ListIterator<T> emptyListIterator()
Singleton集合
我们可以使用Collections类创建一个只有一个元素的集合。
我们必须创建这种集合对象,当一个方法接受一个集合作为其参数,我们只有一个对象传递给该方法。
这些方法如下:
<T> Set<T> singleton(T o) <T> List<T> singletonList(T o) <K,V> Map<K,V> singletonMap(K key, V value)
以下代码显示了如何使用Collections.singleton()方法。
Set<String> singletonSet = Collections.singleton("Lonely"); // Throws a runtime exception since a singleton set is immutable singletonSet.add("Hello");