mirror of
https://github.com/LingCoder/OnJava8.git
synced 2026-08-23 22:43:28 +08:00
附录:集合主题 翻译更新至 填充集合
This commit is contained in:
@@ -362,23 +362,453 @@ Cyan
|
||||
可以看到,使用 **LinkedHashMap** 确实能够保留 **HTMLColors.ARRAY** 的顺序。
|
||||
|
||||
<!-- List Behavior -->
|
||||
## List表现
|
||||
## List行为
|
||||
|
||||
**Lists** 是存储和检索对象(次于数组)的最基本方法。基本列表操作包括:
|
||||
|
||||
- **add()** 用于插入元素
|
||||
- **get()** 用于随机访问元素
|
||||
- **iterator()** 获取序列上的一个 **Iterator**
|
||||
- **stream()** 生成元素的一个 **Stream**
|
||||
|
||||
列表构造方法始终保留元素的添加顺序。
|
||||
|
||||
以下示例中的方法各自涵盖了一组不同的行为:每个 **List** 可以执行的操作( **basicTest()** ),使用 **Iterator** ( **iterMotion()** )遍历序列,使用 **Iterator** ( **iterManipulation()** )更改内容,查看 **List** 操作( **testVisual()** )的效果,以及仅可用于 **LinkedLists** 的操作:
|
||||
|
||||
```java
|
||||
// collectiontopics/ListOps.java
|
||||
// Things you can do with Lists
|
||||
import java.util.*;
|
||||
import onjava.HTMLColors;
|
||||
|
||||
public class ListOps {
|
||||
// Create a short list for testing:
|
||||
static final List<String> LIST =
|
||||
HTMLColors.LIST.subList(0, 10);
|
||||
private static boolean b;
|
||||
private static String s;
|
||||
private static int i;
|
||||
private static Iterator<String> it;
|
||||
private static ListIterator<String> lit;
|
||||
public static void basicTest(List<String> a) {
|
||||
a.add(1, "x"); // Add at location 1
|
||||
a.add("x"); // Add at end
|
||||
// Add a collection:
|
||||
a.addAll(LIST);
|
||||
// Add a collection starting at location 3:
|
||||
a.addAll(3, LIST);
|
||||
b = a.contains("1"); // Is it in there?
|
||||
// Is the entire collection in there?
|
||||
b = a.containsAll(LIST);
|
||||
// Lists allow random access, which is cheap
|
||||
// for ArrayList, expensive for LinkedList:
|
||||
s = a.get(1); // Get (typed) object at location 1
|
||||
i = a.indexOf("1"); // Tell index of object
|
||||
b = a.isEmpty(); // Any elements inside?
|
||||
it = a.iterator(); // Ordinary Iterator
|
||||
lit = a.listIterator(); // ListIterator
|
||||
lit = a.listIterator(3); // Start at location 3
|
||||
i = a.lastIndexOf("1"); // Last match
|
||||
a.remove(1); // Remove location 1
|
||||
a.remove("3"); // Remove this object
|
||||
a.set(1, "y"); // Set location 1 to "y"
|
||||
// Keep everything that's in the argument
|
||||
// (the intersection of the two sets):
|
||||
a.retainAll(LIST);
|
||||
// Remove everything that's in the argument:
|
||||
a.removeAll(LIST);
|
||||
i = a.size(); // How big is it?
|
||||
a.clear(); // Remove all elements
|
||||
}
|
||||
public static void iterMotion(List<String> a) {
|
||||
ListIterator<String> it = a.listIterator();
|
||||
b = it.hasNext();
|
||||
b = it.hasPrevious();
|
||||
s = it.next();
|
||||
i = it.nextIndex();
|
||||
s = it.previous();
|
||||
i = it.previousIndex();
|
||||
}
|
||||
public static void iterManipulation(List<String> a) {
|
||||
ListIterator<String> it = a.listIterator();
|
||||
it.add("47");
|
||||
// Must move to an element after add():
|
||||
it.next();
|
||||
// Remove the element after the new one:
|
||||
it.remove();
|
||||
// Must move to an element after remove():
|
||||
it.next();
|
||||
// Change the element after the deleted one:
|
||||
it.set("47");
|
||||
}
|
||||
public static void testVisual(List<String> a) {
|
||||
System.out.println(a);
|
||||
List<String> b = LIST;
|
||||
System.out.println("b = " + b);
|
||||
a.addAll(b);
|
||||
a.addAll(b);
|
||||
System.out.println(a);
|
||||
// Insert, remove, and replace elements
|
||||
// using a ListIterator:
|
||||
ListIterator<String> x =
|
||||
a.listIterator(a.size()/2);
|
||||
x.add("one");
|
||||
System.out.println(a);
|
||||
System.out.println(x.next());
|
||||
x.remove();
|
||||
System.out.println(x.next());
|
||||
x.set("47");
|
||||
System.out.println(a);
|
||||
// Traverse the list backwards:
|
||||
x = a.listIterator(a.size());
|
||||
while(x.hasPrevious())
|
||||
System.out.print(x.previous() + " ");
|
||||
System.out.println();
|
||||
System.out.println("testVisual finished");
|
||||
}
|
||||
// There are some things that only LinkedLists can do:
|
||||
public static void testLinkedList() {
|
||||
LinkedList<String> ll = new LinkedList<>();
|
||||
ll.addAll(LIST);
|
||||
System.out.println(ll);
|
||||
// Treat it like a stack, pushing:
|
||||
ll.addFirst("one");
|
||||
ll.addFirst("two");
|
||||
System.out.println(ll);
|
||||
// Like "peeking" at the top of a stack:
|
||||
System.out.println(ll.getFirst());
|
||||
// Like popping a stack:
|
||||
System.out.println(ll.removeFirst());
|
||||
System.out.println(ll.removeFirst());
|
||||
// Treat it like a queue, pulling elements
|
||||
// off the tail end:
|
||||
System.out.println(ll.removeLast());
|
||||
System.out.println(ll);
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
// Make and fill a new list each time:
|
||||
basicTest(new LinkedList<>(LIST));
|
||||
basicTest(new ArrayList<>(LIST));
|
||||
iterMotion(new LinkedList<>(LIST));
|
||||
iterMotion(new ArrayList<>(LIST));
|
||||
iterManipulation(new LinkedList<>(LIST));
|
||||
iterManipulation(new ArrayList<>(LIST));
|
||||
testVisual(new LinkedList<>(LIST));
|
||||
testLinkedList();
|
||||
}
|
||||
}
|
||||
/* Output:
|
||||
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
|
||||
Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
|
||||
b = [AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
|
||||
Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
|
||||
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
|
||||
Bisque, Black, BlanchedAlmond, Blue, BlueViolet,
|
||||
AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
|
||||
Bisque, Black, BlanchedAlmond, Blue, BlueViolet,
|
||||
AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
|
||||
Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
|
||||
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
|
||||
Bisque, Black, BlanchedAlmond, Blue, BlueViolet,
|
||||
AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige, one,
|
||||
Bisque, Black, BlanchedAlmond, Blue, BlueViolet,
|
||||
AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
|
||||
Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
|
||||
Bisque
|
||||
Black
|
||||
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
|
||||
Bisque, Black, BlanchedAlmond, Blue, BlueViolet,
|
||||
AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige, one,
|
||||
47, BlanchedAlmond, Blue, BlueViolet, AliceBlue,
|
||||
AntiqueWhite, Aquamarine, Azure, Beige, Bisque, Black,
|
||||
BlanchedAlmond, Blue, BlueViolet]
|
||||
BlueViolet Blue BlanchedAlmond Black Bisque Beige Azure
|
||||
Aquamarine AntiqueWhite AliceBlue BlueViolet Blue
|
||||
BlanchedAlmond 47 one Beige Azure Aquamarine
|
||||
AntiqueWhite AliceBlue BlueViolet Blue BlanchedAlmond
|
||||
Black Bisque Beige Azure Aquamarine AntiqueWhite
|
||||
AliceBlue
|
||||
testVisual finished
|
||||
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
|
||||
Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
|
||||
[two, one, AliceBlue, AntiqueWhite, Aquamarine, Azure,
|
||||
Beige, Bisque, Black, BlanchedAlmond, Blue, BlueViolet]
|
||||
two
|
||||
two
|
||||
one
|
||||
BlueViolet
|
||||
[AliceBlue, AntiqueWhite, Aquamarine, Azure, Beige,
|
||||
Bisque, Black, BlanchedAlmond, Blue]
|
||||
*/
|
||||
```
|
||||
|
||||
在 **basicTest()** 和 **iterMotion()** 中,方法调用是为了展示正确的语法,尽管获取了返回值,但不会使用它。在某些情况下,根本不会去获取返回值。在使用这些方法之前,请查看JDK文档中这些方法的完整用法。
|
||||
|
||||
<!-- Set Behavior -->
|
||||
## Set表现
|
||||
## Set行为
|
||||
|
||||
**Set** 的主要用处是测试成员身份,不过也可以将其用作删除重复元素的工具。如果不关心元素顺序或并发性, **HashSet** 总是最好的选择,因为它是专门为了快速查找而设计的(这里使用了在[附录:理解equals和hashCode方法]()章节中探讨的散列函数)。
|
||||
|
||||
其它的 **Set** 实现产生不同的排序行为:
|
||||
|
||||
```java
|
||||
// collectiontopics/SetOrder.java
|
||||
import java.util.*;
|
||||
import onjava.HTMLColors;
|
||||
|
||||
public class SetOrder {
|
||||
static String[] sets = {
|
||||
"java.util.HashSet",
|
||||
"java.util.TreeSet",
|
||||
"java.util.concurrent.ConcurrentSkipListSet",
|
||||
"java.util.LinkedHashSet",
|
||||
"java.util.concurrent.CopyOnWriteArraySet",
|
||||
};
|
||||
static final List<String> RLIST =
|
||||
new ArrayList<>(HTMLColors.LIST);
|
||||
static {
|
||||
Collections.reverse(RLIST);
|
||||
}
|
||||
public static void
|
||||
main(String[] args) throws Exception {
|
||||
for(String type: sets) {
|
||||
System.out.format("[-> %s <-]%n",
|
||||
type.substring(type.lastIndexOf('.') + 1));
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<String> set = (Set<String>)
|
||||
Class.forName(type).newInstance();
|
||||
set.addAll(RLIST);
|
||||
set.stream()
|
||||
.limit(10)
|
||||
.forEach(System.out::println);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Output:
|
||||
[-> HashSet <-]
|
||||
MediumOrchid
|
||||
PaleGoldenRod
|
||||
Sienna
|
||||
LightSlateGray
|
||||
DarkSeaGreen
|
||||
Black
|
||||
Gainsboro
|
||||
Orange
|
||||
LightCoral
|
||||
DodgerBlue
|
||||
[-> TreeSet <-]
|
||||
AliceBlue
|
||||
AntiqueWhite
|
||||
Aquamarine
|
||||
Azure
|
||||
Beige
|
||||
Bisque
|
||||
Black
|
||||
BlanchedAlmond
|
||||
Blue
|
||||
BlueViolet
|
||||
[-> ConcurrentSkipListSet <-]
|
||||
AliceBlue
|
||||
AntiqueWhite
|
||||
Aquamarine
|
||||
Azure
|
||||
Beige
|
||||
Bisque
|
||||
Black
|
||||
BlanchedAlmond
|
||||
Blue
|
||||
BlueViolet
|
||||
[-> LinkedHashSet <-]
|
||||
YellowGreen
|
||||
Yellow
|
||||
WhiteSmoke
|
||||
White
|
||||
Wheat
|
||||
Violet
|
||||
Turquoise
|
||||
Tomato
|
||||
Thistle
|
||||
Teal
|
||||
[-> CopyOnWriteArraySet <-]
|
||||
YellowGreen
|
||||
Yellow
|
||||
WhiteSmoke
|
||||
White
|
||||
Wheat
|
||||
Violet
|
||||
Turquoise
|
||||
Tomato
|
||||
Thistle
|
||||
Teal
|
||||
*/
|
||||
```
|
||||
|
||||
这里需要使用 **@SuppressWarnings(“unchecked”)** ,因为这里将一个 **String** (可能是任何东西)传递给了 **Class.forName(type).newInstance()** 。编译器并不能保证这是一次成功的操作。
|
||||
|
||||
**RLIST** 是 **HTMLColors.LIST** 的反转版本。因为 **Collections.reverse()** 是通过修改参数来执行反向操作,而不是返回包含反向元素的新 **List** ,所以该调用在 **static** 块内执行。 **RLIST** 可以防止我们意外地认为 **Set** 对其结果进行了排序。
|
||||
|
||||
**HashSet** 的输出结果似乎没有可辨别的顺序,因为它是基于散列函数的。 **TreeSet** 和 **ConcurrentSkipListSet** 都对它们的元素进行了排序,它们都实现了 **SortedSet** 接口来标识这个特点。因为实现该接口的 **Set** 按顺序排列,所以该接口还有一些其他的可用操作。 **LinkedHashSet** 和 **CopyOnWriteArraySet** 尽管没有用于标识的接口,但它们还是保留了元素的插入顺序。
|
||||
|
||||
**ConcurrentSkipListSet** 和 **CopyOnWriteArraySet** 是线程安全的。
|
||||
|
||||
在附录的最后,我们将了解在非 **HashSet** 实现的 **Set** 上添加额外排序的性能成本,以及不同实现中的任何其他功能的成本。
|
||||
|
||||
<!-- Using Functional Operations with any Map -->
|
||||
## 在Map中使用函数式操作
|
||||
|
||||
与 **Collection** 接口一样,**forEach()** 也内置在 **Map** 接口中。但是如果想要执行任何其他的基本功能操作,比如 **map()** ,**flatMap()** ,**reduce()** 或 **filter()** 时,该怎么办? 查看 **Map** 接口发现并没有这些。
|
||||
|
||||
可以通过 **entrySet()** 连接到这些方法,该方法会生成一个由 **Map.Entry** 对象组成的 **Set** 。这个 **Set** 包含 **stream()** 和 **parallelStream()** 方法。只需要记住一件事,这里正在使用的是 **Map.Entry** 对象:
|
||||
|
||||
```java
|
||||
// collectiontopics/FunctionalMap.java
|
||||
// Functional operations on a Map
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
import java.util.concurrent.*;
|
||||
import static onjava.HTMLColors.*;
|
||||
|
||||
public class FunctionalMap {
|
||||
public static void main(String[] args) {
|
||||
MAP.entrySet().stream()
|
||||
.map(Map.Entry::getValue)
|
||||
.filter(v -> v.startsWith("Dark"))
|
||||
.map(v -> v.replaceFirst("Dark", "Hot"))
|
||||
.forEach(System.out::println);
|
||||
}
|
||||
}
|
||||
/* Output:
|
||||
HotBlue
|
||||
HotCyan
|
||||
HotGoldenRod
|
||||
HotGray
|
||||
HotGreen
|
||||
HotKhaki
|
||||
HotMagenta
|
||||
HotOliveGreen
|
||||
HotOrange
|
||||
HotOrchid
|
||||
HotRed
|
||||
HotSalmon
|
||||
HotSeaGreen
|
||||
HotSlateBlue
|
||||
HotSlateGray
|
||||
HotTurquoise
|
||||
HotViolet
|
||||
*/
|
||||
```
|
||||
|
||||
生成 **Stream** 后,所有的基本功能方法,甚至更多就都可以使用了。
|
||||
|
||||
<!-- Selecting Parts of a Map -->
|
||||
## 选择Map的部分
|
||||
## 选择Map片段
|
||||
|
||||
由 **TreeMap** 和 **ConcurrentSkipListMap** 实现的 **NavigableMap** 接口解决了需要选择Map片段的问题。下面是一个示例,使用了 **HTMLColors** :
|
||||
|
||||
```java
|
||||
// collectiontopics/NavMap.java
|
||||
// NavigableMap produces pieces of a Map
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import static onjava.HTMLColors.*;
|
||||
|
||||
public class NavMap {
|
||||
public static final
|
||||
NavigableMap<Integer,String> COLORS =
|
||||
new ConcurrentSkipListMap<>(MAP);
|
||||
public static void main(String[] args) {
|
||||
show(COLORS.firstEntry());
|
||||
border();
|
||||
show(COLORS.lastEntry());
|
||||
border();
|
||||
NavigableMap<Integer, String> toLime =
|
||||
COLORS.headMap(rgb("Lime"), true);
|
||||
show(toLime);
|
||||
border();
|
||||
show(COLORS.ceilingEntry(rgb("DeepSkyBlue") - 1));
|
||||
border();
|
||||
show(COLORS.floorEntry(rgb("DeepSkyBlue") - 1));
|
||||
border();
|
||||
show(toLime.descendingMap());
|
||||
border();
|
||||
show(COLORS.tailMap(rgb("MistyRose"), true));
|
||||
border();
|
||||
show(COLORS.subMap(
|
||||
rgb("Orchid"), true,
|
||||
rgb("DarkSalmon"), false));
|
||||
}
|
||||
}
|
||||
/* Output:
|
||||
0x000000: Black
|
||||
******************************
|
||||
0xFFFFFF: White
|
||||
******************************
|
||||
0x000000: Black
|
||||
0x000080: Navy
|
||||
0x00008B: DarkBlue
|
||||
0x0000CD: MediumBlue
|
||||
0x0000FF: Blue
|
||||
0x006400: DarkGreen
|
||||
0x008000: Green
|
||||
0x008080: Teal
|
||||
0x008B8B: DarkCyan
|
||||
0x00BFFF: DeepSkyBlue
|
||||
0x00CED1: DarkTurquoise
|
||||
0x00FA9A: MediumSpringGreen
|
||||
0x00FF00: Lime
|
||||
******************************
|
||||
0x00BFFF: DeepSkyBlue
|
||||
******************************
|
||||
0x008B8B: DarkCyan
|
||||
******************************
|
||||
0x00FF00: Lime
|
||||
0x00FA9A: MediumSpringGreen
|
||||
0x00CED1: DarkTurquoise
|
||||
0x00BFFF: DeepSkyBlue
|
||||
0x008B8B: DarkCyan
|
||||
0x008080: Teal
|
||||
0x008000: Green
|
||||
0x006400: DarkGreen
|
||||
0x0000FF: Blue
|
||||
0x0000CD: MediumBlue
|
||||
0x00008B: DarkBlue
|
||||
0x000080: Navy
|
||||
0x000000: Black
|
||||
******************************
|
||||
0xFFE4E1: MistyRose
|
||||
0xFFEBCD: BlanchedAlmond
|
||||
0xFFEFD5: PapayaWhip
|
||||
0xFFF0F5: LavenderBlush
|
||||
0xFFF5EE: SeaShell
|
||||
0xFFF8DC: Cornsilk
|
||||
0xFFFACD: LemonChiffon
|
||||
0xFFFAF0: FloralWhite
|
||||
0xFFFAFA: Snow
|
||||
0xFFFF00: Yellow
|
||||
0xFFFFE0: LightYellow
|
||||
0xFFFFF0: Ivory
|
||||
0xFFFFFF: White
|
||||
******************************
|
||||
0xDA70D6: Orchid
|
||||
0xDAA520: GoldenRod
|
||||
0xDB7093: PaleVioletRed
|
||||
0xDC143C: Crimson
|
||||
0xDCDCDC: Gainsboro
|
||||
0xDDA0DD: Plum
|
||||
0xDEB887: BurlyWood
|
||||
0xE0FFFF: LightCyan
|
||||
0xE6E6FA: Lavender
|
||||
*/
|
||||
```
|
||||
|
||||
在 **main()** 方法中可以看到 **NavigableMap** 的各种功能。 因为 **NavigableMap** 具有键顺序,所以它使用了 **firstEntry()** 和 **lastEntry()** 的概念。调用 **headMap()** 会生成一个 **NavigableMap** ,其中包含了从 **Map** 的开头到 **headMap()** 参数中所指向的一组元素,其中 **boolean** 值指示结果中是否包含该参数。调用 **tailMap()** 执行了类似的操作,只不过是从参数开始到 **Map** 的末尾。 **subMap()** 则允许生成 **Map** 中间的一部分。
|
||||
|
||||
**ceilingEntry()** 从当前键值对向上搜索下一个键值对,**floorEntry()** 则是向下搜索。 **descendingMap()** 反转了 **NavigableMap** 的顺序。
|
||||
|
||||
如果需要通过分割 **Map** 来简化所正在解决的问题,则 **NavigableMap** 可以做到。具有类似的功能的其它集合实现也可以用来帮助解决问题。
|
||||
|
||||
<!-- Filling Collections -->
|
||||
## 集合的fill方法
|
||||
## 填充集合
|
||||
|
||||
|
||||
<!-- Custom Collection and Map using Flyweight -->
|
||||
|
||||
Reference in New Issue
Block a user