集合的接口到底干啥用
从今天开始,我要重新总结一遍java里面有关于集合的东西,便于自己复习,而且春招也在这里,非常可怕,我要认认真真学习了。疫情让我开不了学压哈哈哈。美哉美哉。
先告诉自己,这篇文章没太多实用性,只要了解几个重点接口的关系就行了。
好了,废话不多说了,先看一张图
这是集合里面最常见的一张图,各种类和接口都在上面。可以看到,最顶层的是Iterator,接着是Collection和ListIterator。那么ListIterator我们不说,暂且先看看另外两个,扒光他们看看😄😄😄😄😄😄😄😄👨👨👨👨👨
GOGOGOGO~~~~
Iterator
迭代器作用于集合,是用来遍历集合元素的对象。迭代器不是Java独有的,大部分高级语言都提供了迭代器来遍历集合。实际上,迭代器是一种设计模式:
迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
迭代器封装了对集合的遍历,使得不用了解集合的内部细节,就可以使用同样的方式遍历不同的集合。
什么都不说,就只看源码:
public interface Iterator<E> {
/**
* 这个方法一般是在next方法之前使用,来判断迭代器还有没有元素
*
*/
boolean hasNext();
/**
*返回下一个元素
*如果已经没有元素了就会@throws NoSuchElementException
*/
E next();
/**
* 移除上一次调用next方法返回一个元素,也就是说他和next方法紧密相连,如果没有在之前调用next,就会出错
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
*
* 这个方法是JDK1.8才有的,这个可以调用然后传入一个lambda表达式,它相当于不用写循环就可以遍历,然后根据lambda的逻辑操作
*
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
foreachRemaining方法使用
当然,每个集合实现可能不同,到时候总结看看。
插一段小话
看看这个
最上面的图,好像是Collection和Iterator有关系,而现在怎么又和Iterable有关系了。看看源码就知道怎么回事了。走,看看Iterable
Iterable
public interface Iterable<T> {
/**
*实现接口这个方法,可以返回迭代器,所以这里看清楚了,Iterable有个方法返回Iterator需要我们去实现的。
*/
Iterator<T> iterator();
/**
* 这个是jdk1.8的一个语法糖的东西,这个方法在编译阶段会以迭代器去遍历元素,但是我们仍然可以使用foreach去使用
*
*其实和这种形式是一样的效果,他的默认实现就是这样。
* for (T t : this)
* action.accept(t);
* }
*/
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
/**
*
*/
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
上面的代码我们可以看见Iterable的iterator方法返回的是Iterator。这样关系就清楚了吧
那么我们再仔细看看Collection接口
Collection
哇,原来是Collection接口又继承了Iterable接口,那么理应实现了Collection接口的话,就要实现iterator方法,这样就可以得到一个迭代器Iterator了。但是这个Iterator的方法没有实现怎么吧。不急,以后会看到的,今天只管Collection接口
public interface Collection<E> extends Iterable<E> {
/**
* 返回集合的大小
*/
int size();
boolean isEmpty();
boolean contains(Object o);
Iterator<E> iterator();
Object[] toArray();
<T> T[] toArray(T[] a);
boolean add(E e);
boolean remove(Object o);
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
boolean removeAll(Collection<?> c);
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
boolean retainAll(Collection<?> c);
void clear();
// Comparison and hashing
//hashcode和equals方法要重点注意
boolean equals(Object o);
int hashCode();
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
}
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<E> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
}
源代码没有多少行,目的在于搞清楚三者关系,下面慢慢深入其他的接口和抽象类和实现类。
但是呢,其实以后会看到,在其他的链表和树还有Set这些都可能用到Map的实现
那Map接口又是啥呢
Map
我们都知道Map是一种键值对的形式存在的,比如Redis,MongoDB,JSON都运用了其中的原理,那我们先来看看java里面的Map接口到底有什么东西,可以实现的。
package java.util;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;
/**
* 一个Map对象不能有多个相同key,一个key最多对应一个value
public interface Map<K,V> {
//返回Map的个数
int size();
boolean isEmpty();
boolean containsKey(Object key);
boolean containsValue(Object value);
V get(Object key);
V put(K key, V value);
V remove(Object key);
void putAll(Map<? extends K, ? extends V> m);
void clear();
//这里居然还用到了集合里面的东西
Set<K> keySet();
Collection<V> values();
Set<Map.Entry<K, V>> entrySet();
/**
* 一个Map对象的实际数据结构
*/
interface Entry<K,V> {
K getKey();
V getValue();
V setValue(V value);
boolean equals(Object o);
int hashCode();
/************************************************************/
//下面是比较器,以后重点介绍,这一系列文章只复习集合主要结构,比较器用于排序。
public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K,V>> comparingByKey() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getKey().compareTo(c2.getKey());
}
public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K,V>> comparingByValue() {
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> c1.getValue().compareTo(c2.getValue());
}
public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
}
public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
Objects.requireNonNull(cmp);
return (Comparator<Map.Entry<K, V>> & Serializable)
(c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
}
}
boolean equals(Object o);
int hashCode();
//如果存在就获取,如果没有就又一个默认值
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
Objects.requireNonNull(function);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
// ise thrown from function is not a cme.
v = function.apply(k, v);
try {
entry.setValue(v);
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
}
}
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
default boolean remove(Object key, Object value) {
Object curValue = get(key);
if (!Objects.equals(curValue, value) ||
(curValue == null && !containsKey(key))) {
return false;
}
remove(key);
return true;
}
default boolean replace(K key, V oldValue, V newValue) {
Object curValue = get(key);
if (!Objects.equals(curValue, oldValue) ||
(curValue == null && !containsKey(key))) {
return false;
}
put(key, newValue);
return true;
}
default V replace(K key, V value) {
V curValue;
if (((curValue = get(key)) != null) || containsKey(key)) {
curValue = put(key, value);
}
return curValue;
}
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return v;
}
default V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue;
if ((oldValue = get(key)) != null) {
V newValue = remappingFunction.apply(key, oldValue);
if (newValue != null) {
put(key, newValue);
return newValue;
} else {
remove(key);
return null;
}
} else {
return null;
}
}
default V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue = get(key);
V newValue = remappingFunction.apply(key, oldValue);
if (newValue == null) {
// delete mapping
if (oldValue != null || containsKey(key)) {
// something to remove
remove(key);
return null;
} else {
// nothing to do. Leave things as they were.
return null;
}
} else {
// add or replace old mapping
put(key, newValue);
return newValue;
}
}
default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value);
V oldValue = get(key);
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value);
if(newValue == null) {
remove(key);
} else {
put(key, newValue);
}
return newValue;
}
}