參考:http://winterbe.com/posts/2014/03/16/java-8-tutorial/
1.Stream示例
package com.mavsplus.java8.turtorial.streams;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
/**
* java.util.Stream使用例子
*
* <pre>
* java.util.Stream表示了某一種元素的序列,在這些元素上可以進(jìn)行各種操作。Stream操作可以是中間操作,也可以是完結(jié)操作。
* 完結(jié)操作會(huì)返回一個(gè)某種類型的值,而中間操作會(huì)返回流對(duì)象本身,并且你可以通過(guò)多次調(diào)用同一個(gè)流操作方法來(lái)將操作結(jié)果串起來(lái)。
* Stream是在一個(gè)源的基礎(chǔ)上創(chuàng)建出來(lái)的,例如java.util.Collection中的list或者set(map不能作為Stream的源)。
* Stream操作往往可以通過(guò)順序或者并行兩種方式來(lái)執(zhí)行。
* </pre>
*
* public interface Stream<T> extends BaseStream<T, Stream<T>> {
* <p>
* 可以看到Stream是一個(gè)接口,其是1.8引入
*
* <p>
* Java 8中的Collections類的功能已經(jīng)有所增強(qiáng),你可以之直接通過(guò)調(diào)用Collections.stream()或者Collection.
* parallelStream()方法來(lái)創(chuàng)建一個(gè)流對(duì)象
*
* @author landon
* @since 1.8.0_25
*/
public class StreamUtilExample {
private List<String> stringList = new ArrayList<>();
public StreamUtilExample() {
init();
}
private void init() {
initStringList();
}
/**
* 初始化字符串列表
*/
private void initStringList() {
stringList.add("zzz1");
stringList.add("aaa2");
stringList.add("bbb2");
stringList.add("fff1");
stringList.add("fff2");
stringList.add("aaa1");
stringList.add("bbb1");
stringList.add("zzz2");
}
/**
* Filter接受一個(gè)predicate接口類型的變量,并將所有流對(duì)象中的元素進(jìn)行過(guò)濾。該操作是一個(gè)中間操作,
* 因此它允許我們?cè)诜祷亟Y(jié)果的基礎(chǔ)上再進(jìn)行其他的流操作
* (forEach)。ForEach接受一個(gè)function接口類型的變量,用來(lái)執(zhí)行對(duì)每一個(gè)元素的操作
* 。ForEach是一個(gè)中止操作。它不返回流,所以我們不能再調(diào)用其他的流操作
*/
public void useStreamFilter() {
// stream()方法是Collection接口的一個(gè)默認(rèn)方法
// Stream<T> filter(Predicate<? super T>
// predicate);filter方法參數(shù)是一個(gè)Predicate函數(shù)式接口并繼續(xù)返回Stream接口
// void forEach(Consumer<? super T> action);foreach方法參數(shù)是一個(gè)Consumer函數(shù)式接口
// 解釋:從字符串序列中過(guò)濾出以字符a開(kāi)頭的字符串并迭代打印輸出
stringList.stream().filter((s) -> s.startsWith("a")).forEach(System.out::println);
}
/**
* Sorted是一個(gè)中間操作,能夠返回一個(gè)排過(guò)序的流對(duì)象的視圖。流對(duì)象中的元素會(huì)默認(rèn)按照自然順序進(jìn)行排序,
* 除非你自己指定一個(gè)Comparator接口來(lái)改變排序規(guī)則.
*
* <p>
* 一定要記住,sorted只是創(chuàng)建一個(gè)流對(duì)象排序的視圖,而不會(huì)改變?cè)瓉?lái)集合中元素的順序。原來(lái)string集合中的元素順序是沒(méi)有改變的
*/
public void useStreamSort() {
// Stream<T> sorted();返回Stream接口
// 另外還有一個(gè) Stream<T> sorted(Comparator<? super T>
// comparator);帶Comparator接口的參數(shù)
stringList.stream().sorted().filter((s) -> s.startsWith("a")).forEach(System.out::println);
// 輸出原始集合元素,sorted只是創(chuàng)建排序視圖,不影響原來(lái)集合順序
stringList.stream().forEach(System.out::println);
}
/**
* map是一個(gè)對(duì)于流對(duì)象的中間操作,通過(guò)給定的方法,它能夠把流對(duì)象中的每一個(gè)元素對(duì)應(yīng)到另外一個(gè)對(duì)象上。
* 下面的例子就演示了如何把每個(gè)string都轉(zhuǎn)換成大寫(xiě)的string.
* 不但如此,你還可以把每一種對(duì)象映射成為其他類型。對(duì)于帶泛型結(jié)果的流對(duì)象,具體的類型還要由傳遞給map的泛型方法來(lái)決定。
*/
public void useStreamMap() {
// <R> Stream<R> map(Function<? super T, ? extends R> mapper);
// map方法參數(shù)為Function函數(shù)式接口(R_String,T_String).
// 解釋:將集合元素轉(zhuǎn)為大寫(xiě)(每個(gè)元素映射到大寫(xiě))->降序排序->迭代輸出
// 不影響原來(lái)集合
stringList.stream().map(String::toUpperCase).sorted((a, b) -> b.compareTo(a)).forEach(System.out::println);
}
/**
* 匹配操作有多種不同的類型,都是用來(lái)判斷某一種規(guī)則是否與流對(duì)象相互吻合的。所有的匹配操作都是終結(jié)操作,只返回一個(gè)boolean類型的結(jié)果
*/
public void useStreamMatch() {
// boolean anyMatch(Predicate<? super T> predicate);參數(shù)為Predicate函數(shù)式接口
// 解釋:集合中是否有任一元素匹配以'a'開(kāi)頭
boolean anyStartsWithA = stringList.stream().anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA);
// boolean allMatch(Predicate<? super T> predicate);
// 解釋:集合中是否所有元素匹配以'a'開(kāi)頭
boolean allStartsWithA = stringList.stream().allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA);
// boolean noneMatch(Predicate<? super T> predicate);
// 解釋:集合中是否沒(méi)有元素匹配以'd'開(kāi)頭
boolean nonStartsWithD = stringList.stream().noneMatch((s) -> s.startsWith("d"));
System.out.println(nonStartsWithD);
}
/**
* Count是一個(gè)終結(jié)操作,它的作用是返回一個(gè)數(shù)值,用來(lái)標(biāo)識(shí)當(dāng)前流對(duì)象中包含的元素?cái)?shù)量
*/
public void useStreamCount() {
// long count();
// 解釋:返回集合中以'a'開(kāi)頭元素的數(shù)目
long startsWithACount = stringList.stream().filter((s) -> s.startsWith("a")).count();
System.out.println(startsWithACount);
System.out.println(stringList.stream().count());
}
/**
* 該操作是一個(gè)終結(jié)操作,它能夠通過(guò)某一個(gè)方法,對(duì)元素進(jìn)行削減操作。該操作的結(jié)果會(huì)放在一個(gè)Optional變量里返回。
*/
public void useStreamReduce() {
// Optional<T> reduce(BinaryOperator<T> accumulator);
// @FunctionalInterface public interface BinaryOperator<T> extends
// BiFunction<T,T,T> {
// @FunctionalInterface public interface BiFunction<T, U, R> { R apply(T
// t, U u);
Optional<String> reduced = stringList.stream().sorted().reduce((s1, s2) -> s1 + "#" + s2);
// 解釋:集合元素排序后->reduce(削減 )->將元素以#連接->生成Optional對(duì)象(其get方法返回#拼接后的值)
reduced.ifPresent(System.out::println);
System.out.println(reduced.get());
}
/**
* 使用并行流
* <p>
* 流操作可以是順序的,也可以是并行的。順序操作通過(guò)單線程執(zhí)行,而并行操作則通過(guò)多線程執(zhí)行. 可使用并行流進(jìn)行操作來(lái)提高運(yùn)行效率
*/
public void useParallelStreams() {
// 初始化一個(gè)字符串集合
int max = 1000000;
List<String> values = new ArrayList<>();
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
// 使用順序流排序
long sequenceT0 = System.nanoTime();
values.stream().sorted();
long sequenceT1 = System.nanoTime();
// 輸出:sequential sort took: 51921 ms.
System.out.format("sequential sort took: %d ms.", sequenceT1 - sequenceT0).println();
// 使用并行流排序
long parallelT0 = System.nanoTime();
// default Stream<E> parallelStream() {
// parallelStream為Collection接口的一個(gè)默認(rèn)方法
values.parallelStream().sorted();
long parallelT1 = System.nanoTime();
// 輸出:parallel sort took: 21432 ms.
System.out.format("parallel sort took: %d ms.", parallelT1 - parallelT0).println();
// 從輸出可以看出:并行排序快了一倍多
}
public static void main(String[] args) {
StreamUtilExample example = new StreamUtilExample();
example.useStreamFilter();
example.useStreamMap();
example.useStreamMatch();
example.useStreamCount();
example.useStreamReduce();
example.useParallelStreams();
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
/**
* java.util.Stream使用例子
*
* <pre>
* java.util.Stream表示了某一種元素的序列,在這些元素上可以進(jìn)行各種操作。Stream操作可以是中間操作,也可以是完結(jié)操作。
* 完結(jié)操作會(huì)返回一個(gè)某種類型的值,而中間操作會(huì)返回流對(duì)象本身,并且你可以通過(guò)多次調(diào)用同一個(gè)流操作方法來(lái)將操作結(jié)果串起來(lái)。
* Stream是在一個(gè)源的基礎(chǔ)上創(chuàng)建出來(lái)的,例如java.util.Collection中的list或者set(map不能作為Stream的源)。
* Stream操作往往可以通過(guò)順序或者并行兩種方式來(lái)執(zhí)行。
* </pre>
*
* public interface Stream<T> extends BaseStream<T, Stream<T>> {
* <p>
* 可以看到Stream是一個(gè)接口,其是1.8引入
*
* <p>
* Java 8中的Collections類的功能已經(jīng)有所增強(qiáng),你可以之直接通過(guò)調(diào)用Collections.stream()或者Collection.
* parallelStream()方法來(lái)創(chuàng)建一個(gè)流對(duì)象
*
* @author landon
* @since 1.8.0_25
*/
public class StreamUtilExample {
private List<String> stringList = new ArrayList<>();
public StreamUtilExample() {
init();
}
private void init() {
initStringList();
}
/**
* 初始化字符串列表
*/
private void initStringList() {
stringList.add("zzz1");
stringList.add("aaa2");
stringList.add("bbb2");
stringList.add("fff1");
stringList.add("fff2");
stringList.add("aaa1");
stringList.add("bbb1");
stringList.add("zzz2");
}
/**
* Filter接受一個(gè)predicate接口類型的變量,并將所有流對(duì)象中的元素進(jìn)行過(guò)濾。該操作是一個(gè)中間操作,
* 因此它允許我們?cè)诜祷亟Y(jié)果的基礎(chǔ)上再進(jìn)行其他的流操作
* (forEach)。ForEach接受一個(gè)function接口類型的變量,用來(lái)執(zhí)行對(duì)每一個(gè)元素的操作
* 。ForEach是一個(gè)中止操作。它不返回流,所以我們不能再調(diào)用其他的流操作
*/
public void useStreamFilter() {
// stream()方法是Collection接口的一個(gè)默認(rèn)方法
// Stream<T> filter(Predicate<? super T>
// predicate);filter方法參數(shù)是一個(gè)Predicate函數(shù)式接口并繼續(xù)返回Stream接口
// void forEach(Consumer<? super T> action);foreach方法參數(shù)是一個(gè)Consumer函數(shù)式接口
// 解釋:從字符串序列中過(guò)濾出以字符a開(kāi)頭的字符串并迭代打印輸出
stringList.stream().filter((s) -> s.startsWith("a")).forEach(System.out::println);
}
/**
* Sorted是一個(gè)中間操作,能夠返回一個(gè)排過(guò)序的流對(duì)象的視圖。流對(duì)象中的元素會(huì)默認(rèn)按照自然順序進(jìn)行排序,
* 除非你自己指定一個(gè)Comparator接口來(lái)改變排序規(guī)則.
*
* <p>
* 一定要記住,sorted只是創(chuàng)建一個(gè)流對(duì)象排序的視圖,而不會(huì)改變?cè)瓉?lái)集合中元素的順序。原來(lái)string集合中的元素順序是沒(méi)有改變的
*/
public void useStreamSort() {
// Stream<T> sorted();返回Stream接口
// 另外還有一個(gè) Stream<T> sorted(Comparator<? super T>
// comparator);帶Comparator接口的參數(shù)
stringList.stream().sorted().filter((s) -> s.startsWith("a")).forEach(System.out::println);
// 輸出原始集合元素,sorted只是創(chuàng)建排序視圖,不影響原來(lái)集合順序
stringList.stream().forEach(System.out::println);
}
/**
* map是一個(gè)對(duì)于流對(duì)象的中間操作,通過(guò)給定的方法,它能夠把流對(duì)象中的每一個(gè)元素對(duì)應(yīng)到另外一個(gè)對(duì)象上。
* 下面的例子就演示了如何把每個(gè)string都轉(zhuǎn)換成大寫(xiě)的string.
* 不但如此,你還可以把每一種對(duì)象映射成為其他類型。對(duì)于帶泛型結(jié)果的流對(duì)象,具體的類型還要由傳遞給map的泛型方法來(lái)決定。
*/
public void useStreamMap() {
// <R> Stream<R> map(Function<? super T, ? extends R> mapper);
// map方法參數(shù)為Function函數(shù)式接口(R_String,T_String).
// 解釋:將集合元素轉(zhuǎn)為大寫(xiě)(每個(gè)元素映射到大寫(xiě))->降序排序->迭代輸出
// 不影響原來(lái)集合
stringList.stream().map(String::toUpperCase).sorted((a, b) -> b.compareTo(a)).forEach(System.out::println);
}
/**
* 匹配操作有多種不同的類型,都是用來(lái)判斷某一種規(guī)則是否與流對(duì)象相互吻合的。所有的匹配操作都是終結(jié)操作,只返回一個(gè)boolean類型的結(jié)果
*/
public void useStreamMatch() {
// boolean anyMatch(Predicate<? super T> predicate);參數(shù)為Predicate函數(shù)式接口
// 解釋:集合中是否有任一元素匹配以'a'開(kāi)頭
boolean anyStartsWithA = stringList.stream().anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA);
// boolean allMatch(Predicate<? super T> predicate);
// 解釋:集合中是否所有元素匹配以'a'開(kāi)頭
boolean allStartsWithA = stringList.stream().allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA);
// boolean noneMatch(Predicate<? super T> predicate);
// 解釋:集合中是否沒(méi)有元素匹配以'd'開(kāi)頭
boolean nonStartsWithD = stringList.stream().noneMatch((s) -> s.startsWith("d"));
System.out.println(nonStartsWithD);
}
/**
* Count是一個(gè)終結(jié)操作,它的作用是返回一個(gè)數(shù)值,用來(lái)標(biāo)識(shí)當(dāng)前流對(duì)象中包含的元素?cái)?shù)量
*/
public void useStreamCount() {
// long count();
// 解釋:返回集合中以'a'開(kāi)頭元素的數(shù)目
long startsWithACount = stringList.stream().filter((s) -> s.startsWith("a")).count();
System.out.println(startsWithACount);
System.out.println(stringList.stream().count());
}
/**
* 該操作是一個(gè)終結(jié)操作,它能夠通過(guò)某一個(gè)方法,對(duì)元素進(jìn)行削減操作。該操作的結(jié)果會(huì)放在一個(gè)Optional變量里返回。
*/
public void useStreamReduce() {
// Optional<T> reduce(BinaryOperator<T> accumulator);
// @FunctionalInterface public interface BinaryOperator<T> extends
// BiFunction<T,T,T> {
// @FunctionalInterface public interface BiFunction<T, U, R> { R apply(T
// t, U u);
Optional<String> reduced = stringList.stream().sorted().reduce((s1, s2) -> s1 + "#" + s2);
// 解釋:集合元素排序后->reduce(削減 )->將元素以#連接->生成Optional對(duì)象(其get方法返回#拼接后的值)
reduced.ifPresent(System.out::println);
System.out.println(reduced.get());
}
/**
* 使用并行流
* <p>
* 流操作可以是順序的,也可以是并行的。順序操作通過(guò)單線程執(zhí)行,而并行操作則通過(guò)多線程執(zhí)行. 可使用并行流進(jìn)行操作來(lái)提高運(yùn)行效率
*/
public void useParallelStreams() {
// 初始化一個(gè)字符串集合
int max = 1000000;
List<String> values = new ArrayList<>();
for (int i = 0; i < max; i++) {
UUID uuid = UUID.randomUUID();
values.add(uuid.toString());
}
// 使用順序流排序
long sequenceT0 = System.nanoTime();
values.stream().sorted();
long sequenceT1 = System.nanoTime();
// 輸出:sequential sort took: 51921 ms.
System.out.format("sequential sort took: %d ms.", sequenceT1 - sequenceT0).println();
// 使用并行流排序
long parallelT0 = System.nanoTime();
// default Stream<E> parallelStream() {
// parallelStream為Collection接口的一個(gè)默認(rèn)方法
values.parallelStream().sorted();
long parallelT1 = System.nanoTime();
// 輸出:parallel sort took: 21432 ms.
System.out.format("parallel sort took: %d ms.", parallelT1 - parallelT0).println();
// 從輸出可以看出:并行排序快了一倍多
}
public static void main(String[] args) {
StreamUtilExample example = new StreamUtilExample();
example.useStreamFilter();
example.useStreamMap();
example.useStreamMatch();
example.useStreamCount();
example.useStreamReduce();
example.useParallelStreams();
}
}
2.Map接口中新的默認(rèn)方法示例
package com.mavsplus.java8.turtorial.streams;
import java.util.HashMap;
import java.util.Map;
/**
* map是不支持流操作的。而更新后的map現(xiàn)在則支持多種實(shí)用的新方法,來(lái)完成常規(guī)的任務(wù)
*
* @author landon
* @since 1.8.0_25
*/
public class MapUtilExample {
private Map<Integer, String> map = new HashMap<>();
public MapUtilExample() {
initPut();
}
/**
* 使用更新后的map進(jìn)行putIfAbsent
*/
private void initPut() {
// putIfAbsent為Map接口中新增的一個(gè)默認(rèn)方法
/**
* <code>
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
</code>
*/
// 如果map中有對(duì)應(yīng)K映射的V且不為null則直接返回;否則執(zhí)行put
for (int i = 0; i < 10; i++) {
map.putIfAbsent(i, "value" + i);
}
// 放入了一個(gè)null元素
map.putIfAbsent(10, null);
// 替換null
map.putIfAbsent(10, "value10");
// 因?yàn)镵-10有映射且不為null則忽略V-value11
map.putIfAbsent(10, "value11");
}
/**
* 使用更新后的map進(jìn)行for-each
*/
public void forEach() {
// default void forEach(BiConsumer<? super K, ? super V> action)
// Map接口中新增的默認(rèn)方法
// @FunctionalInterface public interface BiConsumer<T, U> {void accept(T
// t, U u);
map.forEach((id, val) -> System.out.println(val));
}
/**
* 使用更新后的map進(jìn)行compute——->重映射
*/
public void compute() {
// default V computeIfPresent(K key,BiFunction<? super K, ? super V, ?
// extends V> remappingFunction)
// Map接口中新增的默認(rèn)方法
// @FunctionalInterface public interface BiFunction<T, U, R> {R apply(T
// t, U u);
// --> V apply(K k,V v)
// ifPresent會(huì)判斷key對(duì)應(yīng)的v是否是null,不會(huì)null才會(huì)compute->否則直接返回null
// 解釋:將K-3映射的value->compute->"value3" + 3 = value33
map.computeIfPresent(3, (key, val) -> val + key);
System.out.println(map.get(3));
// 解釋:這里將K-3映射的value進(jìn)行重映射->null
// 該方法源碼實(shí)現(xiàn)會(huì)判斷如果newValue為null則會(huì)執(zhí)行remove(key)方法,將移除key
map.computeIfPresent(9, (key, val) -> null);
// 從上面的解釋中得到,輸出為false,因?yàn)橐呀?jīng)被移除了
System.out.println(map.containsKey(9));
// default V computeIfAbsent(K key,Function<? super K, ? extends V>
// mappingFunction)
// 解釋:代碼實(shí)現(xiàn)上看,如果K-15映射的值為null,即不存在或者為null,則執(zhí)行映射->所以本例來(lái)看(沒(méi)有15的key),該方法相當(dāng)于插入一個(gè)新值
map.computeIfAbsent(15, (key) -> "val" + key);
System.out.println(map.containsKey(15));
// 因?yàn)镵-4映射的值存在,所以直接返回,即不會(huì)重映射,所以輸出依然會(huì)是value4
map.computeIfAbsent(4, key -> "bam");
System.out.println(map.get(4));
}
/**
* 使用更新后的map進(jìn)行remove
*/
public void remove() {
// default boolean remove(Object key, Object value) {
// Map接口中新增的默認(rèn)方法
// 其源碼實(shí)現(xiàn)是
// 1.當(dāng)前key對(duì)應(yīng)的值和傳入的參數(shù)不一致時(shí)則直接返回,移除失敗(用的是Objects.equals方法)
// 2.當(dāng)前key對(duì)應(yīng)的值為null且!containsKey(key),移除失敗(即當(dāng)前map中根本不存在這個(gè)key_【因?yàn)橛幸环N情況是有這個(gè)key但是key映射的值為null】)
// ->否則執(zhí)行移除
/**
* <code>
* 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;
}
* </code>
*/
map.remove(3, "value4");
System.out.println(map.get(3));
// key和v匹配時(shí)則移除成功
map.remove(3, "value33");
System.out.println(map.get(3));
}
/**
* getOrDefault是一個(gè)有用的方法
*/
public void getOrDefault() {
// default V getOrDefault(Object key, V defaultValue) {
// Map接口中新增的默認(rèn)方法
/**
* <code>
* default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
* </code>
*/
// 源碼實(shí)現(xiàn):
// 1.如果對(duì)應(yīng)的key有value且不為null,則直接返回value;如果為null且包含該key,則返回null(總之即必須要有該key)
// 2.如果沒(méi)有該key,則用默認(rèn)值
String retV = map.getOrDefault("20", "not found");
System.out.println(retV);
// 加入一個(gè)null
map.putIfAbsent(30, null);
// 輸出null
System.out.println(map.get(30));
// 輸出null
System.out.println(map.getOrDefault(30, "value30"));
}
/**
* 合并
*/
public void merge() {
// default V merge(K key, V value,BiFunction<? super V, ? super V, ?
// extends V> remappingFunction)
// @FunctionalInterface public interface BiFunction<T, U, R> { R apply(T
// t, U u);
// merge為Map接口新增的默認(rèn)方法
/**
* <code>
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;
}
* </code>
*/
// 其源碼實(shí)現(xiàn):
// 1.分別檢查參數(shù)remappingFunction和value是否為null(調(diào)用Objects.requireNonNull).->為null則拋出空指針
// 2.判斷oldValue是否為null,如果為null則將傳入的newValue賦值;如果oldValue不為null則執(zhí)行merge函數(shù)
// --->apply(oldValue, value)
// 3.判斷newValue->如果為null則執(zhí)行移除;否則執(zhí)行插入
// k-9的值在執(zhí)行compute方法的時(shí)候已經(jīng)被移除了->所以oldValue為null->所以newValue為傳入的參數(shù)value9->執(zhí)行插入
// 所以這里輸出為value9
String newValue1 = map.merge(9, "value9", (value, newValue) -> value.concat(newValue));
System.out.println(newValue1);
System.out.println(map.get(9));
// k-9的值現(xiàn)在已經(jīng)為value9了,所以執(zhí)行merge函數(shù)->"value9".concat("concat")->newValue為"value9concat"
// 執(zhí)行插入,所以這里輸出為value9concat
String newValue2 = map.merge(9, "concat", (value, newValue) -> value.concat(newValue));
System.out.println(newValue2);
System.out.println(map.get(9));
// k-8值存在為value8->執(zhí)行merge函數(shù)->直接返回"NewMerge8"->newValue為"NewMerge8"
// 執(zhí)行put->所以這里輸出"NewMerge8"
map.merge(8, "merge", (value, newValue) -> "NewMerge8");
System.out.println(map.get(8));
}
public static void main(String[] args) {
MapUtilExample example = new MapUtilExample();
example.forEach();
example.compute();
example.remove();
example.getOrDefault();
example.merge();
}
}
import java.util.HashMap;
import java.util.Map;
/**
* map是不支持流操作的。而更新后的map現(xiàn)在則支持多種實(shí)用的新方法,來(lái)完成常規(guī)的任務(wù)
*
* @author landon
* @since 1.8.0_25
*/
public class MapUtilExample {
private Map<Integer, String> map = new HashMap<>();
public MapUtilExample() {
initPut();
}
/**
* 使用更新后的map進(jìn)行putIfAbsent
*/
private void initPut() {
// putIfAbsent為Map接口中新增的一個(gè)默認(rèn)方法
/**
* <code>
default V putIfAbsent(K key, V value) {
V v = get(key);
if (v == null) {
v = put(key, value);
}
return v;
}
</code>
*/
// 如果map中有對(duì)應(yīng)K映射的V且不為null則直接返回;否則執(zhí)行put
for (int i = 0; i < 10; i++) {
map.putIfAbsent(i, "value" + i);
}
// 放入了一個(gè)null元素
map.putIfAbsent(10, null);
// 替換null
map.putIfAbsent(10, "value10");
// 因?yàn)镵-10有映射且不為null則忽略V-value11
map.putIfAbsent(10, "value11");
}
/**
* 使用更新后的map進(jìn)行for-each
*/
public void forEach() {
// default void forEach(BiConsumer<? super K, ? super V> action)
// Map接口中新增的默認(rèn)方法
// @FunctionalInterface public interface BiConsumer<T, U> {void accept(T
// t, U u);
map.forEach((id, val) -> System.out.println(val));
}
/**
* 使用更新后的map進(jìn)行compute——->重映射
*/
public void compute() {
// default V computeIfPresent(K key,BiFunction<? super K, ? super V, ?
// extends V> remappingFunction)
// Map接口中新增的默認(rèn)方法
// @FunctionalInterface public interface BiFunction<T, U, R> {R apply(T
// t, U u);
// --> V apply(K k,V v)
// ifPresent會(huì)判斷key對(duì)應(yīng)的v是否是null,不會(huì)null才會(huì)compute->否則直接返回null
// 解釋:將K-3映射的value->compute->"value3" + 3 = value33
map.computeIfPresent(3, (key, val) -> val + key);
System.out.println(map.get(3));
// 解釋:這里將K-3映射的value進(jìn)行重映射->null
// 該方法源碼實(shí)現(xiàn)會(huì)判斷如果newValue為null則會(huì)執(zhí)行remove(key)方法,將移除key
map.computeIfPresent(9, (key, val) -> null);
// 從上面的解釋中得到,輸出為false,因?yàn)橐呀?jīng)被移除了
System.out.println(map.containsKey(9));
// default V computeIfAbsent(K key,Function<? super K, ? extends V>
// mappingFunction)
// 解釋:代碼實(shí)現(xiàn)上看,如果K-15映射的值為null,即不存在或者為null,則執(zhí)行映射->所以本例來(lái)看(沒(méi)有15的key),該方法相當(dāng)于插入一個(gè)新值
map.computeIfAbsent(15, (key) -> "val" + key);
System.out.println(map.containsKey(15));
// 因?yàn)镵-4映射的值存在,所以直接返回,即不會(huì)重映射,所以輸出依然會(huì)是value4
map.computeIfAbsent(4, key -> "bam");
System.out.println(map.get(4));
}
/**
* 使用更新后的map進(jìn)行remove
*/
public void remove() {
// default boolean remove(Object key, Object value) {
// Map接口中新增的默認(rèn)方法
// 其源碼實(shí)現(xiàn)是
// 1.當(dāng)前key對(duì)應(yīng)的值和傳入的參數(shù)不一致時(shí)則直接返回,移除失敗(用的是Objects.equals方法)
// 2.當(dāng)前key對(duì)應(yīng)的值為null且!containsKey(key),移除失敗(即當(dāng)前map中根本不存在這個(gè)key_【因?yàn)橛幸环N情況是有這個(gè)key但是key映射的值為null】)
// ->否則執(zhí)行移除
/**
* <code>
* 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;
}
* </code>
*/
map.remove(3, "value4");
System.out.println(map.get(3));
// key和v匹配時(shí)則移除成功
map.remove(3, "value33");
System.out.println(map.get(3));
}
/**
* getOrDefault是一個(gè)有用的方法
*/
public void getOrDefault() {
// default V getOrDefault(Object key, V defaultValue) {
// Map接口中新增的默認(rèn)方法
/**
* <code>
* default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
* </code>
*/
// 源碼實(shí)現(xiàn):
// 1.如果對(duì)應(yīng)的key有value且不為null,則直接返回value;如果為null且包含該key,則返回null(總之即必須要有該key)
// 2.如果沒(méi)有該key,則用默認(rèn)值
String retV = map.getOrDefault("20", "not found");
System.out.println(retV);
// 加入一個(gè)null
map.putIfAbsent(30, null);
// 輸出null
System.out.println(map.get(30));
// 輸出null
System.out.println(map.getOrDefault(30, "value30"));
}
/**
* 合并
*/
public void merge() {
// default V merge(K key, V value,BiFunction<? super V, ? super V, ?
// extends V> remappingFunction)
// @FunctionalInterface public interface BiFunction<T, U, R> { R apply(T
// t, U u);
// merge為Map接口新增的默認(rèn)方法
/**
* <code>
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;
}
* </code>
*/
// 其源碼實(shí)現(xiàn):
// 1.分別檢查參數(shù)remappingFunction和value是否為null(調(diào)用Objects.requireNonNull).->為null則拋出空指針
// 2.判斷oldValue是否為null,如果為null則將傳入的newValue賦值;如果oldValue不為null則執(zhí)行merge函數(shù)
// --->apply(oldValue, value)
// 3.判斷newValue->如果為null則執(zhí)行移除;否則執(zhí)行插入
// k-9的值在執(zhí)行compute方法的時(shí)候已經(jīng)被移除了->所以oldValue為null->所以newValue為傳入的參數(shù)value9->執(zhí)行插入
// 所以這里輸出為value9
String newValue1 = map.merge(9, "value9", (value, newValue) -> value.concat(newValue));
System.out.println(newValue1);
System.out.println(map.get(9));
// k-9的值現(xiàn)在已經(jīng)為value9了,所以執(zhí)行merge函數(shù)->"value9".concat("concat")->newValue為"value9concat"
// 執(zhí)行插入,所以這里輸出為value9concat
String newValue2 = map.merge(9, "concat", (value, newValue) -> value.concat(newValue));
System.out.println(newValue2);
System.out.println(map.get(9));
// k-8值存在為value8->執(zhí)行merge函數(shù)->直接返回"NewMerge8"->newValue為"NewMerge8"
// 執(zhí)行put->所以這里輸出"NewMerge8"
map.merge(8, "merge", (value, newValue) -> "NewMerge8");
System.out.println(map.get(8));
}
public static void main(String[] args) {
MapUtilExample example = new MapUtilExample();
example.forEach();
example.compute();
example.remove();
example.getOrDefault();
example.merge();
}
}