3.1 样例数据
public class HTMLColors {
public static final Object[][] ARRAY = {
{0xF0F8FF, "AliceBlue"},
{0xFAEBD7, "AntiqueWhite"},
{0x7FFFD4, "Aquamarine"},
{0xF0FFFF, "Azure"},
{0xF5F5DC, "Beige"},
{0xFFE4C4, "Bisque"},
{0x000000, "Black"},
{0xFFEBCD, "BlanchedAlmond"},
{0x0000FF, "Blue"},
{0x8A2BE2, "BlueViolet"},
{0xA52A2A, "Brown"},
{0xDEB887, "BurlyWood"},
{0x5F9EA0, "CadetBlue"},
{0x7FFF00, "Chartreuse"},
{0xD2691E, "Chocolate"},
{0xFF7F50, "Coral"},
{0x6495ED, "CornflowerBlue"},
{0xFFF8DC, "Cornsilk"},
{0xDC143C, "Crimson"},
{0x00FFFF, "Cyan"},
{0x00008B, "DarkBlue"},
{0x008B8B, "DarkCyan"},
{0xB8860B, "DarkGoldenRod"},
{0xA9A9A9, "DarkGray"},
{0x006400, "DarkGreen"},
{0xBDB76B, "DarkKhaki"},
{0x8B008B, "DarkMagenta"},
{0x556B2F, "DarkOliveGreen"},
{0xFF8C00, "DarkOrange"},
{0x9932CC, "DarkOrchid"},
{0x8B0000, "DarkRed"},
{0xE9967A, "DarkSalmon"},
{0x8FBC8F, "DarkSeaGreen"},
{0x483D8B, "DarkSlateBlue"},
{0x2F4F4F, "DarkSlateGray"},
{0x00CED1, "DarkTurquoise"},
{0x9400D3, "DarkViolet"},
{0xFF1493, "DeepPink"},
{0x00BFFF, "DeepSkyBlue"},
{0x696969, "DimGray"},
{0x1E90FF, "DodgerBlue"},
{0xB22222, "FireBrick"},
{0xFFFAF0, "FloralWhite"},
{0x228B22, "ForestGreen"},
{0xDCDCDC, "Gainsboro"},
{0xF8F8FF, "GhostWhite"},
{0xFFD700, "Gold"},
{0xDAA520, "GoldenRod"},
{0x808080, "Gray"},
{0x008000, "Green"},
{0xADFF2F, "GreenYellow"},
{0xF0FFF0, "HoneyDew"},
{0xFF69B4, "HotPink"},
{0xCD5C5C, "IndianRed"},
{0x4B0082, "Indigo"},
{0xFFFFF0, "Ivory"},
{0xF0E68C, "Khaki"},
{0xE6E6FA, "Lavender"},
{0xFFF0F5, "LavenderBlush"},
{0x7CFC00, "LawnGreen"},
{0xFFFACD, "LemonChiffon"},
{0xADD8E6, "LightBlue"},
{0xF08080, "LightCoral"},
{0xE0FFFF, "LightCyan"},
{0xFAFAD2, "LightGoldenRodYellow"},
{0xD3D3D3, "LightGray"},
{0x90EE90, "LightGreen"},
{0xFFB6C1, "LightPink"},
{0xFFA07A, "LightSalmon"},
{0x20B2AA, "LightSeaGreen"},
{0x87CEFA, "LightSkyBlue"},
{0x778899, "LightSlateGray"},
{0xB0C4DE, "LightSteelBlue"},
{0xFFFFE0, "LightYellow"},
{0x00FF00, "Lime"},
{0x32CD32, "LimeGreen"},
{0xFAF0E6, "Linen"},
{0xFF00FF, "Magenta"},
{0x800000, "Maroon"},
{0x66CDAA, "MediumAquaMarine"},
{0x0000CD, "MediumBlue"},
{0xBA55D3, "MediumOrchid"},
{0x9370DB, "MediumPurple"},
{0x3CB371, "MediumSeaGreen"},
{0x7B68EE, "MediumSlateBlue"},
{0x00FA9A, "MediumSpringGreen"},
{0x48D1CC, "MediumTurquoise"},
{0xC71585, "MediumVioletRed"},
{0x191970, "MidnightBlue"},
{0xF5FFFA, "MintCream"},
{0xFFE4E1, "MistyRose"},
{0xFFE4B5, "Moccasin"},
{0xFFDEAD, "NavajoWhite"},
{0x000080, "Navy"},
{0xFDF5E6, "OldLace"},
{0x808000, "Olive"},
{0x6B8E23, "OliveDrab"},
{0xFFA500, "Orange"},
{0xFF4500, "OrangeRed"},
{0xDA70D6, "Orchid"},
{0xEEE8AA, "PaleGoldenRod"},
{0x98FB98, "PaleGreen"},
{0xAFEEEE, "PaleTurquoise"},
{0xDB7093, "PaleVioletRed"},
{0xFFEFD5, "PapayaWhip"},
{0xFFDAB9, "PeachPuff"},
{0xCD853F, "Peru"},
{0xFFC0CB, "Pink"},
{0xDDA0DD, "Plum"},
{0xB0E0E6, "PowderBlue"},
{0x800080, "Purple"},
{0xFF0000, "Red"},
{0xBC8F8F, "RosyBrown"},
{0x4169E1, "RoyalBlue"},
{0x8B4513, "SaddleBrown"},
{0xFA8072, "Salmon"},
{0xF4A460, "SandyBrown"},
{0x2E8B57, "SeaGreen"},
{0xFFF5EE, "SeaShell"},
{0xA0522D, "Sienna"},
{0xC0C0C0, "Silver"},
{0x87CEEB, "SkyBlue"},
{0x6A5ACD, "SlateBlue"},
{0x708090, "SlateGray"},
{0xFFFAFA, "Snow"},
{0x00FF7F, "SpringGreen"},
{0x4682B4, "SteelBlue"},
{0xD2B48C, "Tan"},
{0x008080, "Teal"},
{0xD8BFD8, "Thistle"},
{0xFF6347, "Tomato"},
{0x40E0D0, "Turquoise"},
{0xEE82EE, "Violet"},
{0xF5DEB3, "Wheat"},
{0xFFFFFF, "White"},
{0xF5F5F5, "WhiteSmoke"},
{0xFFFF00, "Yellow"},
{0x9ACD32, "YellowGreen"},
};
// rgb colorName的map
public static final Map<Integer, String> MAP = Arrays.stream(ARRAY)
.collect(Collectors.toMap(
e -> (Integer) e[0],
e -> (String) e[1],
(e1, e2) -> {
throw new IllegalArgumentException();
},
LinkedHashMap::new
));
// key value 反转
public static <V, K> Map<V, K> invert(Map<K, V> map) {
return map.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getValue,
Map.Entry::getKey,
(e1, e2) -> {
throw new IllegalArgumentException();
},
LinkedHashMap::new
));
}
// 颜色名字转rgb的map
public static final Map<String, Integer> INVMAP = invert(MAP);
//按照颜色名称获取rgb
public static Integer rgb(String colorName) {
return INVMAP.get(colorName);
}
// 颜色名字数组
public static final List<String> LIST = Arrays.stream(ARRAY)
.map(item -> (String) item[1]).collect(Collectors.toList());
// rgb 数组
public static final List<Integer> RGBLIST = Arrays.stream(ARRAY)
.map(item -> (Integer) item[0]).collect(Collectors.toList());
// 显示
public static void show(Map.Entry<Integer, String> e) {
System.out.format("0x%06X: %s%n", e.getKey(), e.getValue());
}
// 显示
public static void show(Map<Integer, String> m, int count) {
m.entrySet().stream().limit(count).forEach(e -> show(e));
}
// 显示全部
public static void show(Map<Integer, String> m) {
show(m, m.size());
}
// 显示集合
public static void show(Collection<String> lst, int count) {
lst.stream().limit(count).forEach(System.out::println);
}
public static void show(Collection<String> lst) {
show(lst, lst.size());
}
public static void showrgb(Collection<Integer> lst, int count) {
lst.stream().limit(count).forEach(n -> System.out.format("0x%06X%n", n));
}
public static void showrgb(Collection<Integer> lst) {
showrgb(lst, lst.size());
}
public static void showInv(Map<String, Integer> m, int count) {
m.entrySet().stream().limit(count).forEach(e -> System.out.format("%-20s 0x%06X%n", e.getKey(), e.getValue()));
}
public static void showInv(Map<String, Integer> m) {
showInv(m, m.size());
}
public static void border() {
System.out.println("******************************");
}
}
- Collectors.toMap(提取键函数,提取值函数,键冲突合并函数,map工厂)
测试代码
public class HTMLColorTest {
static final int DISPLAY_SIZE = 3;
public static void main(String[] args) {
show(MAP, DISPLAY_SIZE);
border();
showInv(INVMAP, DISPLAY_SIZE);
border();
show(LIST, DISPLAY_SIZE);
border();
showrgb(RGBLIST, DISPLAY_SIZE);
}
}
3.2 List的行为
List列表
- 操作
- add 插入元素
- get 访问元素
- iterator 获得序列的迭代器
- stream 获得元素流
- 构造器可以保持元素插入顺序
public class ListOps {
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");
//末尾添加
a.add("x");
// 批量添加
a.addAll(LIST);
// 指定位置批量添加
a.addAll(3, LIST);
// 存在某元素
b = a.contains("1");
// 存在某集合
b = a.containsAll(LIST);
// 获取某位置元素
s = a.get(1);
// 获取某元素位置
i = a.indexOf("1");
// 集合是否为空
b = a.isEmpty();
// 迭代器
it = a.iterator();
// 列表迭代器
lit = a.listIterator();
// 指定位置列表迭代器
lit = a.listIterator(3);
// 获取元素从右侧开始
i = a.lastIndexOf("1");
// 移除指定位置元素
a.remove(1);
//移除指定元素
a.remove("3");
//修改某索引元素的值
a.set(1, "y");
//交集
a.retainAll(LIST);
//差集
a.removeAll(LIST);
//集合大小
i = a.size();
//清空集合
a.clear();
}
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");
it.next();
//删除当前元素
it.remove();
it.next();
//修改当前元素
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);
// 反向遍历
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);
// 类似栈, 入栈
ll.addFirst("one");
ll.addFirst("two");
System.out.println(ll);
// 类似栈, 获取栈顶元素
System.out.println(ll.getFirst());
// 获取栈顶元素并删除
System.out.println(ll.removeFirst());
System.out.println(ll.removeFirst());
//类似队列 获取队列尾部元素
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();
}
}
3.3 Set的行为
Set可以删除重复元素
- 不会保留元素顺序
- 查找就是快
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)
.getConstructor()
.newInstance();
set.addAll(RLIST);
set.stream()
.limit(10)
.forEach(System.out::println);
}
}
}
3.4 在Map上使用函数式操作
操作Map的entry成流,后面就可以接任意的函数方法了
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);
}
}
3.5 选择Map的部分元素
NavigableMap接口,解决选择Map中部分元素的问题
- TreeMap和ConcurrentSkipListMap都实现了该接口
- NavigableMap中键有顺序,firstEntry、lastEntry获取第一个和最后一个
- headMap 从开头到第一个参数所指元素的所有元素,第二个参数表示是不是把当前元素包含
- tailMap 是从指定元素到后面所有的元素
- subMap 则是取两个元素中间的某段元素
- ceilingEntry 从指定的键向后查找下一个键值对
- floorEntry 从指定的键向前查找上一个键值对
- descendingMap 反转NavigableMap的顺序
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));
}
}
3.6 填充集合
Collections中有很多静态工具方法
- fill 将集合中的所有元素都替换成同一个对象引用
- nCopies 拷贝指定数量的引用后装入List
class StringAddress {
private String s;
StringAddress(String s) {
this.s = s;
}
@Override
public String toString() {
return super.toString() + " " + s;
}
}
public class FillingLists {
public static void main(String[] args) {
List<StringAddress> list =
new ArrayList<>(Collections.nCopies(4, new StringAddress("Hello")));
System.out.println(list);
Collections.fill(list, new StringAddress("World!"));
System.out.println(list);
}
}
3.6.1 使用Suppliers来填充Collection
class Government implements Supplier<String> {
static String[] foundation = ("strange women lying in ponds " +
"distributing swords is no basis " +
"for a system of government").split(" ");
private int index;
@Override
public String get() {
return foundation[index++];
}
}
public class SuppliersCollectionTest {
public static void main(String[] args) {
Set<String> set = Suppliers.create(LinkedHashSet::new, new Government(), 15);
System.out.println(set);
List<String> list = Suppliers.create(LinkedList::new, new Government(), 15);
System.out.println(list);
list = new ArrayList<>();
Suppliers.fill(list, new Government(), 15);
System.out.println(list);
//常规用法
set = Arrays.stream(Government.foundation)
.collect(Collectors.toSet());
System.out.println(set);
list = Arrays.stream(Government.foundation)
.collect(Collectors.toList());
System.out.println(list);
list = Arrays.stream(Government.foundation)
.collect(Collectors.toCollection(LinkedList::new));
System.out.println(list);
set = Arrays.stream(Government.foundation)
.collect(Collectors
.toCollection(LinkedHashSet::new));
System.out.println(set);
}
}
public class Suppliers {
// Create a collection and fill it:
public static <T, C extends Collection<T>> C
create(Supplier<C> factory, Supplier<T> gen, int n) {
return Stream.generate(gen)
.limit(n)
.collect(factory, C::add, C::addAll);
}
// Fill an existing collection:
public static <T, C extends Collection<T>>
C fill(C coll, Supplier<T> gen, int n) {
Stream.generate(gen)
.limit(n)
.forEach(coll::add);
return coll;
}
// Use an unbound method reference to
// produce a more general method:
public static <H, A> H fill(H holder, BiConsumer<H, A> adder, Supplier<A> gen, int n) {
Stream.generate(gen)
.limit(n)
.forEach(a -> adder.accept(holder, a));
return holder;
}
}
3.6.2 使用Suppliers来填充Map
Suppliers只能返回一个对象,需要借助一个Pair来装在key和value
- Collectors.toMap 参数分别是获取key和value的函数
public class Pair<K, V> {
public final K key;
public final V value;
public Pair(K k, V v) {
key = k;
value = v;
}
public K key() {
return key;
}
public V value() {
return value;
}
public static <K, V> Pair<K, V> make(K k, V v) {
return new Pair<>(k, v);
}
}
class Letters implements Supplier<Pair<Integer, String>> {
private int number = 1;
private char letter = 'A';
@Override
public Pair<Integer, String> get() {
return new Pair<>(number++, "" + letter++);
}
}
public class StreamFillMaps {
public static void main(String[] args) {
Map<Integer, String> m = Stream.generate(new Letters())
.limit(11)
.collect(Collectors.toMap(Pair::key, Pair::value));
System.out.println(m);
// Two separate Suppliers:
Rand.String rs = new Rand.String(3);
Count.Character cc = new Count.Character();
Map<Character, String> mcs = Stream.generate(
() -> Pair.make(cc.get(), rs.get()))
.limit(8)
.collect(Collectors
.toMap(Pair::key, Pair::value));
System.out.println(mcs);
// A key Supplier and a single value:
Map<Character, String> mcs2 = Stream.generate(
() -> Pair.make(cc.get(), "Val"))
.limit(8)
.collect(Collectors
.toMap(Pair::key, Pair::value));
System.out.println(mcs2);
}
}
Map填充的一些范式,下面的工具类和测试
//map填充工具
public class FillMap {
public static <K, V> Map<K, V> basic(Supplier<Pair<K, V>> pairGen, int size) {
return Stream.generate(pairGen)
.limit(size)
.collect(Collectors.toMap(Pair::key, Pair::value));
}
public static <K, V> Map<K, V> basic(
Supplier<K> keyGen,
Supplier<V> valueGen,
int size) {
return Stream.generate(() -> Pair.make(keyGen.get(), valueGen.get()))
.limit(size)
.collect(Collectors.toMap(Pair::key, Pair::value));
}
public static <K, V, M extends Map<K, V>> M create(
Supplier<K> keyGen,
Supplier<V> valueGen,
Supplier<M> mapFactory,
int size) {
return Stream.generate(() -> Pair.make(keyGen.get(), valueGen.get()))
.limit(size)
.collect(Collectors.toMap(Pair::key, Pair::value, (k, v) -> k, mapFactory));
}
}
public class FillMapTest {
public static void main(String[] args) {
Map<String, Integer> mcs = FillMap.basic(
new Rand.String(3), new Count.Integer(), 7);
System.out.println(mcs);
HashMap<String, Integer> hashhm
= FillMap.create(new Rand.String(4),
new Count.Integer(), HashMap::new, 7);
System.out.println(hashhm);
LinkedHashMap<String, Integer> linkedHashMap = FillMap.create(
new Rand.String(5),
new Count.Integer(),
LinkedHashMap::new,
7);
System.out.println(linkedHashMap);
//{mei=5, ccu=2, nne=6, enp=1, gvg=4, xsz=3, btp=0}
//{npcc=1, ztdv=6, gvgm=3, btpe=0, einn=4, eelo=5, uxsz=2}
//{btpen=0, pccux=1, szgvg=2, meinn=3, eeloz=4, tdvew=5, cippc=6}
}
}
3.7 使用享元自定义Collection和Map
享元设计模式,当对象太多或太大时,可以使用享元模式,把对象放在外面。
实现一个只读的List
public class CountingIntegerList extends AbstractList<Integer> {
private int size;
public CountingIntegerList() {
this(0);
}
public CountingIntegerList(int size) {
this.size = (size < 0) ? 0 : size;
}
@Override
public Integer get(int index) {
return index;
}
@Override
public int size() {
return size;
}
public static void main(String[] args) {
List<Integer> cil = new CountingIntegerList(10);
System.out.println(cil);
System.out.println(cil.get(5));
}
}
3.8 Collection的功能
- 添加元素add addAll
- 转成数组 toArray
- 最大值最小值 max min
- 移除元素 remove removeAll removeIf
- 存在判定 contains containsAll
- 清空 clear
public class CollectionMethods {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>(LIST.subList(0, 4));
c.add("ten");
c.add("eleven");
show(c);
border();
Object[] array = c.toArray();
String[] array1 = c.toArray(new String[0]);
System.out.println(Collections.max(c));
System.out.println(Collections.min(c));
border();
Collection<String> c2 = new ArrayList<>(LIST.subList(10, 14));
c.addAll(c2);
show(c);
border();
c.remove(LIST.get(0));
show(c);
border();
c.removeAll(c2);
show(c);
c.addAll(c2);
show(c);
border();
String s = LIST.get(3);
System.out.println(c.contains(s));
System.out.println(c.containsAll(c2));
border();
List<String> c3 = ((List<String>) c).subList(3, 5);
c2.removeAll(c3);
show(c2);
c2.removeAll(c3);
System.out.println(c2.isEmpty());
border();
c = new ArrayList<>(LIST);
c.removeIf(i -> !i.startsWith("P"));
c.removeIf(i -> i.startsWith("Pale"));
c.stream().forEach(System.out::print);
border();
c.clear();
System.out.println(c);
}
}
3.9 可选的操作
某些方法操作由于底层数据结构的原因不会支持,但是只有在运行时才知道
public class Unsupported {
static void check(String description, Runnable test) {
try {
test.run();
} catch (Exception e) {
System.out.println(description + " : " + e);
}
}
static void test(String msg, List<String> list) {
System.out.println("---" + msg + "---");
Collection<String> c = list;
Collection<String> subList = list.subList(1, 8);
Collection<String> c2 = new ArrayList<>(subList);
check("retainAll", () -> c.retainAll(c2));
check("removeAll", () -> c.removeAll(c2));
check("clear", () -> c.clear());
check("add", () -> c.add("M"));
check("addAll", () -> c.addAll(c2));
check("remove", () -> c.remove("C"));
check("set", () -> list.set(0, "M"));
}
public static void main(String[] args) {
List<String> list = Arrays.asList("A B C D E F G H I J K L".split(" "));
test("modifiable copy", new ArrayList<>(list));
test("Arrays.asList()", list);
test("unmodifiableList()", Collections.unmodifiableList(new ArrayList<>(list)));
}
// ---modifiable copy---
//---Arrays.asList()---
//retainAll : java.lang.UnsupportedOperationException: remove
//removeAll : java.lang.UnsupportedOperationException: remove
//clear : java.lang.UnsupportedOperationException
//add : java.lang.UnsupportedOperationException
//addAll : java.lang.UnsupportedOperationException
//remove : java.lang.UnsupportedOperationException: remove
//---unmodifiableList()---
//retainAll : java.lang.UnsupportedOperationException
//removeAll : java.lang.UnsupportedOperationException
//clear : java.lang.UnsupportedOperationException
//add : java.lang.UnsupportedOperationException
//addAll : java.lang.UnsupportedOperationException
//remove : java.lang.UnsupportedOperationException
//set : java.lang.UnsupportedOperationException
}
3.10 Set与存储顺序
Set接口不保证元素的顺序
- HashSet 元素必须定义hashCode和equals方法
- TreeSet 保证元素顺序,元素必须实现Comparable接口(会抛出错误),按照排序结果保存数据
- LinkedHashSet按照元素插入顺序保存
- 元素没有重写hashcode方法,会导致去重的失败
class SetType {
protected int i;
public SetType(int n) {
i = n;
}
public boolean equals(Object o) {
return o instanceof SetType && i == ((SetType) o).i;
}
@Override
public String toString() {
return Integer.toString(i);
}
}
class HashType extends SetType {
public HashType(int n) {
super(n);
}
public int hashCode() {
return Objects.hashCode(i);
}
}
class TreeType extends SetType implements Comparable<TreeType> {
public TreeType(int n) {
super(n);
}
@Override
public int compareTo(TreeType o) {
return Integer.compare(o.i, i);
}
}
public class TypesForSets {
static <T> void fill(Set<T> set, Function<Integer, T> type) {
for (int i = 10; i >= 5; i--)
set.add(type.apply(i));
for (int i = 0; i < 5; i++)
set.add(type.apply(i));
}
static <T> void test(Set<T> set, Function<Integer, T> type) {
fill(set, type);
fill(set, type);
fill(set, type);
System.out.println(set);
}
public static void main(String[] args) {
test(new HashSet<>(), HashType::new);
test(new LinkedHashSet<>(), HashType::new);
test(new TreeSet<>(), TreeType::new);
test(new HashSet<>(), SetType::new);
test(new HashSet<>(), TreeType::new);
test(new LinkedHashSet<>(), SetType::new);
test(new LinkedHashSet<>(), TreeType::new);
try {
test(new TreeSet<>(), SetType::new);
} catch (Exception e) {
System.out.println(e.getMessage());
}
try {
test(new TreeSet<>(), HashType::new);
} catch (Exception e) {
System.out.println(e.getMessage());
}
//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
//[10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
//[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
//[8, 5, 1, 10, 6, 0, 9, 8, 9, 0, 10, 0, 3, 3, 2, 8, 5, 2, 7, 10, 4, 4, 1, 3, 1, 9, 6, 7, 2, 6, 5, 4, 7]
//[7, 6, 4, 1, 5, 3, 1, 10, 7, 9, 0, 2, 10, 0, 2, 6, 6, 9, 3, 4, 9, 7, 4, 0, 8, 8, 3, 10, 2, 8, 1, 5, 5]
//[10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4, 10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4, 10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
//[10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4, 10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4, 10, 9, 8, 7, 6, 5, 0, 1, 2, 3, 4]
//class com.edfeff.ch02.SetType cannot be cast to class java.lang.Comparable (com.edfeff.ch02.SetType is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
//class com.edfeff.ch02.HashType cannot be cast to class java.lang.Comparable (com.edfeff.ch02.HashType is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
}
}
SortedSet 的元素是有序的
- comparator()生成比较器对象
- first()最小元素
- last()最大元素
- subSet(from,to)生成Set的一个视图 (from,to]
- headSet(to)生成Set的一个视图 (...,to)
- tailSet(from) 生成Set的一个视图 (from,...)
public class SortedSetDemo {
public static void main(String[] args) {
SortedSet<String> sortedSet = Arrays
.stream("one two three four five six seven eight".split(" "))
.collect(Collectors.toCollection(TreeSet::new));
System.out.println(sortedSet);//[eight, five, four, one, seven, six, three, two]
String low = sortedSet.first();
String high = sortedSet.last();
System.out.println(low); //eight
System.out.println(high);//two
Iterator<String> it = sortedSet.iterator();
for (int i = 0; i <= 6; i++) {
if (i == 3)
low = it.next();
if (i == 6)
high = it.next();
else
it.next();
}
System.out.println(low);//one
System.out.println(high);//two
System.out.println(sortedSet.subSet(low, high));//[one, seven, six, three]
System.out.println(sortedSet.headSet(high));//[eight, five, four, one, seven, six, three]
System.out.println(sortedSet.tailSet(low));//[one, seven, six, three, two]
}
}
3.11 Queue
队列
- 除了优先级队列外,queue都是按照元素的插入顺序来的
- SynchronousQueue没有结果,因为这是一个阻塞队列,必须由另外一个线程进行移除操作
public class QueueBehavior {
static Stream<String> strings() {
return Stream.of("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten");
}
static void test(int id, Queue<String> queue) {
System.out.print(id + ": ");
strings().forEach(queue::offer);
while (queue.peek() != null) {
System.out.print(queue.remove() + " ");
}
System.out.println();
}
public static void main(String[] args) {
int count = 10;
test(1, new LinkedList<>());
test(2, new PriorityQueue<>());
test(3, new ArrayBlockingQueue<>(count));
test(4, new ConcurrentLinkedDeque<>());
test(5, new LinkedBlockingDeque<>());
test(6, new PriorityBlockingQueue<>());
test(7, new ArrayDeque<>());
test(8, new ConcurrentLinkedDeque<>());
test(9, new LinkedBlockingDeque<>());
test(10, new LinkedTransferQueue<>());
test(11, new SynchronousQueue<>());
//1: one two three four five six seven eight nine ten
//2: eight five four nine one seven six ten three two
//3: one two three four five six seven eight nine ten
//4: one two three four five six seven eight nine ten
//5: one two three four five six seven eight nine ten
//6: eight five four nine one seven six ten three two
//7: one two three four five six seven eight nine ten
//8: one two three four five six seven eight nine ten
//9: one two three four five six seven eight nine ten
//10: one two three four five six seven eight nine ten
//11:
}
}
3.11.1 优先级队列
PriorityQueue
- 元素必须实现Comparable接口
class TodoItem implements Comparable<TodoItem> {
private char primary;
private int secondary;
private String item;
public TodoItem(String item, char primary, int secondary) {
this.primary = primary;
this.secondary = secondary;
this.item = item;
}
@Override
public int compareTo(TodoItem arg) {
if (primary > arg.primary) {
return +1;
}
if (primary == arg.primary) {
if (secondary > arg.secondary) {
return +1;
} else if (secondary == arg.secondary) {
return 0;
}
}
return -1;
}
@Override
public String toString() {
return Character.toString(primary) + secondary + ": " + item;
}
}
public class TodoList {
public static void main(String[] args) {
PriorityQueue<TodoItem> todo = new PriorityQueue<>();
todo.add(new TodoItem("Empty trash", 'C', 4));
todo.add(new TodoItem("Feed trash", 'A', 2));
todo.add(new TodoItem("Feed dog", 'B', 7));
todo.add(new TodoItem("Pick up milk", 'A', 1));
todo.add(new TodoItem("Pick up bread", 'B', 1));
while (!todo.isEmpty()) {
System.out.println(todo.remove());
}
//A1: Pick up milk
//A2: Feed trash
//B1: Pick up bread
//B7: Feed dog
//C4: Empty trash
}
}
3.11.2 Dequeue
双向队列
- LinkedList
- ArrayDeque
- LinkedBlockingDeque
- ConcurrentLinkedDeque
class CountString implements Supplier<String> {
private int n = 0;
CountString() {
}
CountString(int start) {
n = start;
}
@Override
public String get() {
return Integer.toString(n++);
}
}
public class SimpleDeques {
static void test(Deque<String> deque) {
CountString s1 = new CountString(),
s2 = new CountString(20);
for (int i = 0; i < 8; i++) {
deque.offerFirst(s1.get());
deque.offerLast(s2.get());//==offer()
}
System.out.println(deque);
String result = "";
while (!deque.isEmpty()) {
System.out.print(deque.peekFirst() + " ");
result += deque.pollFirst() + " ";
System.out.print(deque.peekLast() + " ");
result += deque.pollLast() + " ";
}
System.out.println("\n" + result);
}
public static void main(String[] args) {
int count = 10;
System.out.println("LinkedList");
test(new LinkedList<>());
System.out.println("ArrayDeque");
test(new ArrayDeque<>());
System.out.println("LinkedBlockingDeque");
test(new LinkedBlockingDeque<>());
System.out.println("ConcurrentLinkedDeque");
test(new ConcurrentLinkedDeque<>());
/*
LinkedList
[7, 6, 5, 4, 3, 2, 1, 0, 20, 21, 22, 23, 24, 25, 26, 27]
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
ArrayDeque
[7, 6, 5, 4, 3, 2, 1, 0, 20, 21, 22, 23, 24, 25, 26, 27]
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
LinkedBlockingDeque
[7, 6, 5, 4, 3, 2, 1, 0, 20, 21, 22, 23, 24, 25, 26, 27]
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
ConcurrentLinkedDeque
[7, 6, 5, 4, 3, 2, 1, 0, 20, 21, 22, 23, 24, 25, 26, 27]
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
7 27 6 26 5 25 4 24 3 23 2 22 1 21 0 20
*/
}
}
3.12 理解Map
Map是一个高性能的键值对存储
我们用一个低性能的固定长度的数组来处理键值对存储,来探究里面的原理。
- 使用一个固定长度的二维数组存储键值对
- 插入使用索引
- 查询使用遍历
public class AssociativeArray<K, V> {
private Object[][] pairs;
private int index;
public AssociativeArray(int length) {
pairs = new Object[length][2];
}
public void put(K key, V value) {
// 插入键值对
if (index >= pairs.length) {
throw new ArrayIndexOutOfBoundsException();
}
pairs[index++] = new Object[]{key, value};
}
public V get(K key) {
// 通过键获取值
// O(n)复杂度
for (int i = 0; i < index; i++) {
if (key.equals(pairs[i][0])) {
return (V) pairs[i][1];
}
}
return null;
}
@Override
public String toString() {
StringBuilder res = new StringBuilder();
for (int i = 0; i < index; i++) {
res.append(pairs[i][0].toString())
.append(" : ")
.append(pairs[i][1].toString());
if (i < index - 1) {
res.append("\n");
}
}
return res.toString();
}
public static void main(String[] args) {
// 测试
var map = new AssociativeArray<String, String>(6);
map.put("sky", "blue");
map.put("grass", "green");
map.put("ocean", "dancing");
map.put("tree", "tall");
map.put("earth", "brown");
map.put("sun", "warm");
try {
map.put("extra", "object");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Too many objects");
}
System.out.println(map);
System.out.println(map.get("ocean"));
}
}
3.12.1 性能
哈希码-将对象转成一个int,方法来自hashCode。
- 通过哈希码查找键
| 集合 | 性能 |
|---|---|
| HashMap | 哈希表实现,支持设置容量capacity和负载因子loadFactor |
| LinkedHashMap | 内部链表实现,遍历时以插入顺序或者LRU顺序,除遍历外,性能低于HashMap |
| TreeMap | 红黑树实现,键有序 |
| WeakHashMap | 弱键组成的Map,引用的对象可以被释放 |
| ConcurrentHashMap | 线程安全Map |
| IdentityHashMap | 哈希映射,使用==比较键 |
public class MapOps {
public static void printKeys(Map<Integer, String> map) {
System.out.print("size=" + map.size());
System.out.print(" keys: ");
System.out.println(map.keySet());
}
public static void test(Map<Integer, String> map) {
System.out.println(map.getClass().getSimpleName());
map.putAll(new CountMap(25));
map.putAll(new CountMap(25));
printKeys(map);
System.out.print("values:");
System.out.println(map.values());
System.out.println("map.containsKey(11):" + map.containsKey(11));
System.out.println("map.get(11):" + map.get(11));
System.out.println("map.containsValue("F0"):" + map.containsValue("F0"));
Integer key = map.keySet().iterator().next();
System.out.println("First key in map:" + key);
map.remove(key);
printKeys(map);
map.clear();
System.out.println("map.isEmpty():" + map.isEmpty());
map.putAll(new CountMap(25));
map.keySet().removeAll(map.keySet());
System.out.println("map.isEmpty():" + map.isEmpty());
System.out.println("*********************");
}
public static void main(String[] args) {
test(new HashMap<>());
test(new TreeMap<>());
test(new LinkedHashMap<>());
test(new IdentityHashMap<>());
test(new ConcurrentHashMap<>());
test(new WeakHashMap<>());
/*
HashMap
size=25 keys: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
values:[A0, B0, C0, D0, E0, F0, G0, H0, I0, J0, K0, L0, M0, N0, O0, P0, Q0, R0, S0, T0, U0, V0, W0, X0, Y0]
map.containsKey(11):true
map.get(11):L0
map.containsValue("F0"):true
First key in map:0
size=24 keys: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
map.isEmpty():true
map.isEmpty():true
*********************
TreeMap
size=25 keys: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
values:[A0, B0, C0, D0, E0, F0, G0, H0, I0, J0, K0, L0, M0, N0, O0, P0, Q0, R0, S0, T0, U0, V0, W0, X0, Y0]
map.containsKey(11):true
map.get(11):L0
map.containsValue("F0"):true
First key in map:0
size=24 keys: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
map.isEmpty():true
map.isEmpty():true
*********************
LinkedHashMap
size=25 keys: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
values:[A0, B0, C0, D0, E0, F0, G0, H0, I0, J0, K0, L0, M0, N0, O0, P0, Q0, R0, S0, T0, U0, V0, W0, X0, Y0]
map.containsKey(11):true
map.get(11):L0
map.containsValue("F0"):true
First key in map:0
size=24 keys: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
map.isEmpty():true
map.isEmpty():true
*********************
IdentityHashMap
size=25 keys: [19, 15, 13, 2, 6, 11, 3, 9, 1, 10, 16, 18, 22, 20, 23, 0, 24, 17, 8, 12, 14, 5, 4, 7, 21]
values:[T0, P0, N0, C0, G0, L0, D0, J0, B0, K0, Q0, S0, W0, U0, X0, A0, Y0, R0, I0, M0, O0, F0, E0, H0, V0]
map.containsKey(11):true
map.get(11):L0
map.containsValue("F0"):false
First key in map:19
size=24 keys: [15, 13, 2, 6, 11, 3, 9, 1, 10, 16, 18, 22, 20, 23, 0, 24, 17, 8, 12, 14, 5, 4, 7, 21]
map.isEmpty():true
map.isEmpty():true
*********************
ConcurrentHashMap
size=25 keys: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
values:[A0, B0, C0, D0, E0, F0, G0, H0, I0, J0, K0, L0, M0, N0, O0, P0, Q0, R0, S0, T0, U0, V0, W0, X0, Y0]
map.containsKey(11):true
map.get(11):L0
map.containsValue("F0"):true
First key in map:0
size=24 keys: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
map.isEmpty():true
map.isEmpty():true
*********************
WeakHashMap
size=25 keys: [24, 22, 23, 20, 21, 18, 19, 16, 17, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
values:[Y0, W0, X0, U0, V0, S0, T0, Q0, R0, P0, O0, N0, M0, L0, K0, J0, I0, H0, G0, F0, E0, D0, C0, B0, A0]
map.containsKey(11):true
map.get(11):L0
map.containsValue("F0"):true
First key in map:24
size=24 keys: [22, 23, 20, 21, 18, 19, 16, 17, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
map.isEmpty():true
map.isEmpty():true
*********************
*/
}
}
数字映射成字母序号的Map
public class CountMap extends AbstractMap<Integer, String> {
private int size;
private static char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static String value(int key) {
// A0 B0 ... A1 B1 ...
return chars[key % chars.length] + Integer.toString(key / chars.length);
}
public CountMap(int size) {
this.size = size < 0 ? 0 : size;
}
@Override
public String get(Object key) {
return value((Integer) key);
}
private static class Entry implements Map.Entry<Integer, String> {
int index;
Entry(int index) {
this.index = index;
}
@Override
public boolean equals(Object o) {
return o instanceof Entry && Objects.equals(index, ((Entry) o).index);
}
@Override
public Integer getKey() {
return index;
}
@Override
public String getValue() {
return value(index);
}
@Override
public String setValue(String value) {
throw new UnsupportedOperationException();
}
@Override
public int hashCode() {
return Objects.hashCode(index);
}
}
@Override
public Set<Map.Entry<Integer, String>> entrySet() {
// LinkedHashSet retains initialization order:
return IntStream.range(0, size)
.mapToObj(Entry::new)
.collect(Collectors.toCollection(LinkedHashSet::new));
}
public static void main(String[] args) {
final int size = 6;
CountMap cm = new CountMap(60);
System.out.println(cm);
System.out.println(cm.get(500));
cm.values().stream()
.limit(size)
.forEach(System.out::println);
System.out.println();
new Random(47).ints(size, 0, 1000)
.mapToObj(cm::get)
.forEach(System.out::println);
}
}
3.12.2 SortedMap
SortedMap 可以确保键是有序的
- 实现类 TreeMap,ConcurrentSkipListMap
public class SortedMapDemo {
public static void main(String[] args) {
TreeMap<Integer, String> sortedMap = new TreeMap<>(new CountMap(10));
System.out.println(sortedMap);
Integer low = sortedMap.firstKey();
Integer high = sortedMap.lastKey();
System.out.println(low);
System.out.println(high);
Iterator<Integer> iterator = sortedMap.keySet().iterator();
for (int i = 0; i <= 6; i++) {
if (i == 3) low = iterator.next();
if (i == 3) high = iterator.next();
else iterator.next();
}
System.out.println(low);
System.out.println(high);
System.out.println(sortedMap.subMap(low, high));
System.out.println(sortedMap.headMap(high));
System.out.println(sortedMap.tailMap(low));
}
/*
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0, 9=J0}
0
9
3
4
{3=D0}
{0=A0, 1=B0, 2=C0, 3=D0}
{3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0, 9=J0}
*/
}
3.12.3 LinkedHashMap
遍历过程中按照插入顺序输出键值对
- 构造函数LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder) accessOrder可以设置基于访问量使用最近最少使用LRU算法,尚未访问的元素就出现在列表的前面
public class LinkedHashMapDemo {
public static void main(String[] args) {
LinkedHashMap<Integer, String> linkedMap = new LinkedHashMap<>(new CountMap(9));
System.out.println(linkedMap);
linkedMap = new LinkedHashMap<>(16, 0.75f, true);
linkedMap.putAll(new CountMap(9));
System.out.println(linkedMap);
for (int i = 0; i < 6; i++) {
System.out.print(linkedMap.get(i) + " ");
}
System.out.println();
System.out.println(linkedMap);
linkedMap.get(0);
System.out.println(linkedMap);
}
/*
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0}
{0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 6=G0, 7=H0, 8=I0}
A0 B0 C0 D0 E0 F0
{6=G0, 7=H0, 8=I0, 0=A0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0}
{6=G0, 7=H0, 8=I0, 1=B0, 2=C0, 3=D0, 4=E0, 5=F0, 0=A0}
*/
}
可以看到访问过的元素被移动到尾部
3.13 工具函数
Collections 中定义了很多工具函数
min(Collection x,Comparator y)
max(Collection x)
reverse(List x)
sort(List x)
copy(List x,List y)
replaceAll(List x,Object y,Object arg2)
fill(List x,Object y)
list(Enumeration x)
addAll(Collection x,Object[] y)
emptyEnumeration()
newSetFromMap(Map x)
emptyList()
unmodifiableSet(Set x)
enumeration(Collection x)
synchronizedSet(Set x)
synchronizedCollection(Collection x)
emptyIterator()
nCopies(int x,Object y)
reverseOrder()
unmodifiableMap(Map x)
swap(List x,int y,int arg2)
binarySearch(List x,Object y,Comparator arg2)
shuffle(List x,Random y)
rotate(List x,int y)
indexOfSubList(List x,List y)
lastIndexOfSubList(List x,List y)
unmodifiableCollection(Collection x)
unmodifiableSequencedCollection(SequencedCollection x)
unmodifiableSequencedSet(SequencedSet x)
unmodifiableSortedSet(SortedSet x)
unmodifiableNavigableSet(NavigableSet x)
unmodifiableList(List x)
unmodifiableSequencedMap(SequencedMap x)
unmodifiableSortedMap(SortedMap x)
unmodifiableNavigableMap(NavigableMap x)
synchronizedSortedSet(SortedSet x)
synchronizedNavigableSet(NavigableSet x)
synchronizedList(List x)
synchronizedMap(Map x)
synchronizedSortedMap(SortedMap x)
synchronizedNavigableMap(NavigableMap x)
checkedCollection(Collection x,Class y)
checkedQueue(Queue x,Class y)
checkedSet(Set x,Class y)
checkedSortedSet(SortedSet x,Class y)
checkedNavigableSet(NavigableSet x,Class y)
checkedList(List x,Class y)
checkedMap(Map x,Class y,Class arg2)
checkedSortedMap(SortedMap x,Class y,Class arg2)
checkedNavigableMap(NavigableMap x,Class y,Class arg2)
emptyListIterator()
emptySet()
emptySortedSet()
emptyNavigableSet()
emptyMap()
emptySortedMap()
emptyNavigableMap()
singleton(Object x)
singletonList(Object x)
singletonMap(Object x,Object y)
frequency(Collection x,Object y)
disjoint(Collection x,Collection y)
newSequencedSetFromMap(SequencedMap x)
asLifoQueue(Deque x)
示例
public class Utilities {
static List<String> list = Arrays.asList("one", "two", "three", "four", "five");
public static void main(String[] args) {
System.out.println(list);
// 没有共同元素
System.out.println(Collections.disjoint(list, Collections.singletonList("Four")));
// 最大元素
System.out.println(Collections.max(list));
// 最小元素
System.out.println(Collections.min(list));
// 忽略大小写
System.out.println(Collections.max(list, String.CASE_INSENSITIVE_ORDER));
System.out.println(Collections.min(list, String.CASE_INSENSITIVE_ORDER));
// 是否全部出现的索引
List<String> subList = Arrays.asList("Four", "five", "six");
System.out.println(Collections.indexOfSubList(list, subList));
System.out.println("lastIndexOfSubList: " + Collections.lastIndexOfSubList(list, subList));
// 替换
Collections.replaceAll(list, "one", "Yo");
System.out.println("replaceAll: " + list);
// 反转
Collections.reverse(list);
System.out.println("reverse: " + list);
// 旋转 所有元素前移动,超过列表长度的元素将移动到列表的末尾
Collections.rotate(list, 3);
System.out.println("rotate: " + list);
// 拷贝(源,目标)
List<String> source = Arrays.asList("in the matrix".split(" "));
Collections.copy(list, source);
System.out.println("copy: " + list);
// 交换
Collections.swap(list, 0, list.size() - 1);
System.out.println("swap: " + list);
// 随机打乱
Collections.shuffle(list, new Random(47));
System.out.println("shuffled: " + list);
// 填充
Collections.fill(list, "pop");
System.out.println("fill: " + list);
// 频数
System.out.println("frequency of 'pop': " +
Collections.frequency(list, "pop"));
// 重复
List<String> dups = Collections.nCopies(3, "snap");
System.out.println("dups: " + dups);
System.out.println("'list' disjoint 'dups'?: " + Collections.disjoint(list, dups));
// 枚举 Enumeration 转换为 List
Enumeration<String> e = Collections.enumeration(dups);
Vector<String> v = new Vector<>();
while (e.hasMoreElements())
v.addElement(e.nextElement());
ArrayList<String> arrayList = Collections.list(v.elements());
System.out.println("arrayList: " + arrayList);
/*
[one, two, three, four, five]
true
two
five
two
five
-1
lastIndexOfSubList: -1
replaceAll: [Yo, two, three, four, five]
reverse: [five, four, three, two, Yo]
rotate: [three, two, Yo, five, four]
copy: [in, the, matrix, five, four]
swap: [four, the, matrix, five, in]
shuffled: [matrix, four, in, the, five]
fill: [pop, pop, pop, pop, pop]
frequency of 'pop': 5
dups: [snap, snap, snap]
'list' disjoint 'dups'?: true
arrayList: [snap, snap, snap]
* */
}
}
3.13.1 List上的排序和查找
Collections.sort
- 排序,支持自定义比较器
Collections.binarySearch
- 二分法查找,支持自定义比较器
public class ListSortSearch {
public static void main(String[] args) {
List<String> data = Arrays.asList("one", "two", "three", "four", "five");
List<String> list = new ArrayList<>(data);
list.addAll(data);
System.out.println(list);
Collections.shuffle(list);
System.out.println("shuffle " + list);
ListIterator<String> it = list.listIterator(10);
while (it.hasNext()) {
it.next();
it.remove();
}
System.out.println(list);
Collections.sort(list);
System.out.println(list);
String key = list.get(7);
int index = Collections.binarySearch(list, key);
System.out.println(index);
Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
System.out.println(list);
key = list.get(7);
index = Collections.binarySearch(list, key, String.CASE_INSENSITIVE_ORDER);
System.out.println(index);
}
}
3.13.2 创建不可修改的Collection 和 Map
Collections创建只读的
- unmodifiableList
- unmodifiableSet
- unmodifiableSortedSet
- unmodifiableMap
- unmodifiableSortedMap
public class ReadOnly {
static Collection<String> data = new ArrayList<>(Countries.names(3));
public static void main(String[] args) {
Collection<String> c = Collections.unmodifiableList(new ArrayList<>(data));
System.out.println(c);
try {
c.add("xxx");
} catch (Exception e) {
System.out.println(e); //java.lang.UnsupportedOperationException
}
List<String> a = Collections.unmodifiableList(new ArrayList<>(data));
ListIterator<String> lit = a.listIterator();
try {
lit.add("xxx");
} catch (Exception e) {
System.out.println(e);//java.lang.UnsupportedOperationException
}
Set<String> s = Collections.unmodifiableSet(new HashSet<>(data));
System.out.println(s); // Reading is OK
try {
s.add("one");
} catch (Exception e) {
System.out.println(e);//java.lang.UnsupportedOperationException
}
// For a SortedSet:
Set<String> ss = Collections.unmodifiableSortedSet(new TreeSet<>(data));
Map<String, String> m = Collections.unmodifiableMap(new HashMap<>(Countries.capitals(6)));
System.out.println(m); // Reading is OK
try {
m.put("Ralph", "Howdy!");
} catch (Exception e) {
System.out.println(e);//java.lang.UnsupportedOperationException
}
// For a SortedMap:
Map<String, String> sm = Collections.unmodifiableSortedMap(new TreeMap<>(Countries.capitals(6)));
try {
sm.put("Ralph", "Howdy!");
} catch (Exception e) {
System.out.println(e);//java.lang.UnsupportedOperationException
}
}
}
3.13.3 同步Collection 和 Map
Collections创建线程安全的集合,基于synchronized关键字实现
- synchronizedCollection
- synchronizedList
- synchronizedSet
- synchronizedSortedSet
- synchronizedMap
- synchronizedSortedMap
public class Synchronization {
public static void main(String[] args) {
Collection<String> c = Collections.synchronizedCollection(new ArrayList<>());
List<String> list = Collections.synchronizedList(new ArrayList<>());
Set<String> s = Collections.synchronizedSet(new HashSet<>());
Set<String> ss = Collections.synchronizedSortedSet(new TreeSet<>());
Map<String, String> m = Collections.synchronizedMap(new HashMap<>());
Map<String, String> sm = Collections.synchronizedSortedMap(new TreeMap<>());
}
}
快速失败 java的集合类防止多个任务同时修改集合内容的机制,在遍历的过程中,如果有修改行为,就会抛出异常
public class FastFail {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
Iterator<String> iterator = c.iterator();
c.add("xxx");
try {
iterator.next();
} catch (ConcurrentModificationException e) {
System.out.println(e);//java.util.ConcurrentModificationException
}
}
}
3.14 持有引用
Reference 类的实现
- SoftReference 软引用,用于对内存敏感的缓存
- WeakReference 弱引用。用于实现规范映射,对象的实例可以同时在程序的多个位置使用
- PhantomReference 虚引用,用于安排更灵活的事后清理动作
使用Reference持有一个对象的引用,可以进行访问,同时允许GC进行收集。
- Reference就是我们和普通引用之间的中介,同时不能存在指向该对象的其他普通引用
使用SoftReference和WeakReference时,可选择是否放入ReferenceQueue中 使用PhantomReference时,必须放入ReferenceQueue中
class VeryBig {
private static final int SIZE = 10000;
private long[] la = new long[SIZE];
private String ident;
public VeryBig(String ident) {
this.ident = ident;
}
@Override
public String toString() {
return ident;
}
@Override
protected void finalize() throws Throwable {
System.out.println("Finalizing " + ident);
}
}
public class References {
private static ReferenceQueue<VeryBig> rq = new ReferenceQueue<>();
public static void checkQueue() {
Reference<? extends VeryBig> inq = rq.poll();
if (inq != null)
System.out.println("In queue: " + inq.get());
}
public static void main(String[] args) {
int size = 10;
LinkedList<SoftReference<VeryBig>> sa = new LinkedList<>();
for (int i = 0; i < size; i++) {
sa.add(new SoftReference<>(new VeryBig("Soft " + i), rq));
System.out.println("Just created: " + sa.getLast());
checkQueue();
}
LinkedList<WeakReference<VeryBig>> wa = new LinkedList<>();
for (int i = 0; i < size; i++) {
wa.add(new WeakReference<>(new VeryBig("Weak " + i), rq));
System.out.println("Just created: " + wa.getLast());
checkQueue();
}
SoftReference<VeryBig> s = new SoftReference<>(new VeryBig("Soft"));
WeakReference<VeryBig> w = new WeakReference<>(new VeryBig("Weak"));
System.gc();
LinkedList<PhantomReference<VeryBig>> pa =
new LinkedList<>();
for (int i = 0; i < size; i++) {
pa.add(new PhantomReference<>(new VeryBig("Phantom " + i), rq));
System.out.println("Just created: " + pa.getLast());
checkQueue();
}
/*
Just created: java.lang.ref.SoftReference@312b1dae
Just created: java.lang.ref.SoftReference@7530d0a
Just created: java.lang.ref.SoftReference@27bc2616
Just created: java.lang.ref.SoftReference@3941a79c
Just created: java.lang.ref.SoftReference@506e1b77
Just created: java.lang.ref.SoftReference@4fca772d
Just created: java.lang.ref.SoftReference@9807454
Just created: java.lang.ref.SoftReference@3d494fbf
Just created: java.lang.ref.SoftReference@1ddc4ec2
Just created: java.lang.ref.SoftReference@133314b
Just created: java.lang.ref.WeakReference@b1bc7ed
Just created: java.lang.ref.WeakReference@7cd84586
Just created: java.lang.ref.WeakReference@30dae81
Just created: java.lang.ref.WeakReference@1b2c6ec2
Just created: java.lang.ref.WeakReference@4edde6e5
Just created: java.lang.ref.WeakReference@70177ecd
Just created: java.lang.ref.WeakReference@1e80bfe8
Just created: java.lang.ref.WeakReference@66a29884
Just created: java.lang.ref.WeakReference@4769b07b
Just created: java.lang.ref.WeakReference@cc34f4d
Finalizing Weak 6
Just created: java.lang.ref.PhantomReference@17a7cec2
Finalizing Weak 5
In queue: null
Finalizing Weak 4
Finalizing Weak 3
Just created: java.lang.ref.PhantomReference@65b3120a
Finalizing Weak 2
In queue: null
Finalizing Weak 1
Finalizing Weak 0
Just created: java.lang.ref.PhantomReference@6f539caf
Finalizing Weak
Finalizing Weak 9
In queue: null
Finalizing Weak 8
Finalizing Weak 7
Just created: java.lang.ref.PhantomReference@79fc0f2f
In queue: null
Just created: java.lang.ref.PhantomReference@50040f0c
In queue: null
Just created: java.lang.ref.PhantomReference@2dda6444
In queue: null
Just created: java.lang.ref.PhantomReference@5e9f23b4
In queue: null
Just created: java.lang.ref.PhantomReference@4783da3f
In queue: null
Just created: java.lang.ref.PhantomReference@378fd1ac
In queue: null
Just created: java.lang.ref.PhantomReference@49097b5d
In queue: null
*/
}
}
WeakHashMap WeakHashMap持有的是弱引用,在映射中,对于某个值,我们只创建一个实例,可节省存储。需要时就查找现有对象并使用,可以在初始化时构造这些值。
- 可以节省存储,WeakHashMap会允许GC清理不用的值,内部key和value会被自动包裹在WeakReference中
public class CanonicalMapping {
static void showKeys(Map<String, String> m) {
// Display sorted keys
List<String> keys = new ArrayList<>(m.keySet());
Collections.sort(keys);
System.out.println(keys);
}
public static void main(String[] args) {
int size = 100;
String[] savedKeys = new String[size];
WeakHashMap<String, String> map = new WeakHashMap<>();
for (int i = 0; i < size; i++) {
String key = String.format("%03d", i);
String value = Integer.toString(i);
if (i % 3 == 0) {
savedKeys[i] = key;//真实强引用
}
map.put(key, value);
}
showKeys(map);
System.gc();
showKeys(map);
/*
[000, 001, 002, 003, 004, 005, 006, 007, 008, 009, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 021, 022, 023, 024, 025, 026, 027, 028, 029, 030, 031, 032, 033, 034, 035, 036, 037, 038, 039, 040, 041, 042, 043, 044, 045, 046, 047, 048, 049, 050, 051, 052, 053, 054, 055, 056, 057, 058, 059, 060, 061, 062, 063, 064, 065, 066, 067, 068, 069, 070, 071, 072, 073, 074, 075, 076, 077, 078, 079, 080, 081, 082, 083, 084, 085, 086, 087, 088, 089, 090, 091, 092, 093, 094, 095, 096, 097, 098, 099]
[000, 003, 006, 009, 012, 015, 018, 021, 024, 027, 030, 033, 036, 039, 042, 045, 048, 051, 054, 057, 060, 063, 066, 069, 072, 075, 078, 081, 084, 087, 090, 093, 096, 099]
* */
}
}
调用System.gc后,只有强引用的键才会保存下来。
3.15 Java 1.0、1.1的集合类
一些旧的集合、过时的集合类。
3.15.1 Vector和Enumeration
- Vector 同步的ArrayList
- Enumeration 用于遍历
public class Enumerations {
public static void main(String[] args) {
Vector<String> v = new Vector<>(Countries.names(6));
Enumeration<String> elements = v.elements();
while (elements.hasMoreElements()) {
String s = elements.nextElement();
System.out.println(s + ", ");
}
//兼容旧集合类的做法
elements = Collections.enumeration(new ArrayList<>());
}
}
3.15.2 Hashtable
- 同步的HashMap,不要用
3.15.3 Stack
- 栈 Stack 继承自Vector
- 现在栈可以使用LinkedList替代
public class Stacks {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
for (Month m : Month.values()) {
stack.push(m.toString());
}
System.out.println("stack=" + stack);
// 栈当vector用 ,stack 继承自 Vector
stack.addElement("The last one");
System.out.println("element 5=" + stack.elementAt(5));
System.out.println("pop..");
while (!stack.isEmpty()) {
System.out.print(stack.pop() + " ");
}
System.out.println();
// linkedList作为栈
LinkedList<String> lstack = new LinkedList<>();
for (Month m : Month.values()) {
lstack.push(m.toString());
}
System.out.println("lstack=" + lstack);
while (!lstack.isEmpty()) {
String e = lstack.removeFirst();
System.out.print(e + " ");
}
System.out.println();
}
}
3.15.4 BitSet
BitSet可以高效的存储一组开关数据。底层使用long数组存储数据。
- 提供了通过索引操作位数据的方法
- 支持自动长度扩展,减少位操作难度
public class Bits {
public static void printBitSet(BitSet b) {
System.out.println("bits " + b);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < b.size(); i++) {
stringBuilder.append(b.get(i) ? "1" : "0");
}
System.out.println("bit pattern: " + stringBuilder);
}
public static void main(String[] args) {
Random random = new Random(47);
byte bt = (byte) random.nextInt();
BitSet bb = new BitSet();
for (int i = 7; i >= 0; i--) {
if (((1 << i) & bt) != 0) {
bb.set(i);
} else {
bb.clear(i);
}
}
System.out.println("byte value " + bt);
printBitSet(bb);
// 大于64的情况
BitSet b127 = new BitSet(127);
b127.set(127);
System.out.println("b127 " + b127);
}
}