HashMap 的 7 種遍歷方式與性能分析扛伍!一篇文章搞定

隨著 JDK 1.8 Streams API 的發(fā)布,使得 HashMap 擁有了更多的遍歷的方式词裤,但應該選擇那種遍歷方式刺洒?反而成了一個問題鳖宾。

本文先從 HashMap 的遍歷方法講起,然后再從性能逆航、原理以及安全性等方面鼎文,來分析 HashMap 各種遍歷方式的優(yōu)勢與不足,本文主要內(nèi)容如下圖所示:

HashMap 遍歷

HashMap遍歷從大的方向來說因俐,可分為以下 4 類

1.迭代器(Iterator)方式遍歷拇惋;

2.For Each 方式遍歷;

3.Lambda 表達式遍歷(JDK 1.8+);

4.Streams API 遍歷(JDK 1.8+)抹剩。

但每種類型下又有不同的實現(xiàn)方式蚤假,因此具體的遍歷方式又可以分為以下 7 種:

1.使用迭代器(Iterator)EntrySet?的方式進行遍歷;

2.使用迭代器(Iterator)KeySet 的方式進行遍歷吧兔;

3.使用 For Each EntrySet 的方式進行遍歷;

4.使用 For Each KeySet 的方式進行遍歷袍嬉;

5.使用 Lambda 表達式的方式進行遍歷境蔼;

6.使用 Streams API 單線程的方式進行遍歷;

7.使用 Streams API 多線程的方式進行遍歷伺通。

接下來我們來看每種遍歷方式的具體實現(xiàn)代碼箍土。

1.迭代器?EntrySet

publicclassHashMapTest{

?publicstaticvoidmain(String[] args){

// 創(chuàng)建并賦值

HashMapMap map =newHashMap();

map.put(1,"Java");

map.put(2,"JDK");

map.put(3,"Spring Framework");

map.put(4,"MyBatis framework");

map.put(5,"Java中文社群");

// 遍歷

Iterator> iterator = map.entrySet().iterator();

while(iterator.hasNext()) {

Map.Entry entry = iterator.next();

System.out.println(entry.getKey());

System.out.println(entry.getValue());

}

}

}

以上程序的執(zhí)行結(jié)果為:

1

Java

2

JDK

3

Spring Framework

4

MyBatis framework

5

Java中文社群

2.迭代器 KeySet

publicclassHashMapTest{

publicstaticvoidmain(String[] args){

// 創(chuàng)建并賦值

HashMapMap map =newHashMap()

?map.put(1,"Java");? ? ? ?

map.put(2,"JDK");? ? ? ?

map.put(3,"Spring Framework");? ? ? ?

map.put(4,"MyBatis framework");? ? ? ?

map.put(5,"Java中文社群");

// 遍歷

Iterator iterator = map.keySet().iterator();

while(iterator.hasNext()) {? ? ? ? ? ?

Integer key = iterator.next();? ? ? ? ? ?

System.out.println(key);? ? ? ? ? ?

System.out.println(map.get(key));? ? ?

? }? ?

}

}

以上程序的執(zhí)行結(jié)果為:

1

Java

2

JDK

3

Spring Framework

4

MyBatis framework

5

Java中文社群

3.ForEach?EntrySet

publicclassHashMapTest{

publicstaticvoidmain(String[] args){

// 創(chuàng)建并賦值

HashMapMap map =newHashMap();? ? ? ?

map.put(1,"Java");? ? ? ?

map.put(2,"JDK");? ? ? ?

map.put(3,"Spring Framework");? ? ? ?

map.put(4,"MyBatis framework");? ? ? ?

map.put(5,"Java中文社群");

// 遍歷

for(Map.Entry entry : map.entrySet()) {? ? ? ? ? ?

System.out.println(entry.getKey());? ? ? ? ? ?

System.out.println(entry.getValue());? ? ? ?

}? ?

}

}

以上程序的執(zhí)行結(jié)果為:

1

Java

2

JDK

3

Spring Framework

4

MyBatis framework

5

Java中文社群

4.ForEach KeySet

publicclassHashMapTest{

publicstaticvoidmain(String[] args){

// 創(chuàng)建并賦值

HashMapMap map =newHashMap();? ? ? ?

map.put(1,"Java");? ? ? ?

map.put(2,"JDK");? ? ? ?

map.put(3,"Spring Framework");? ? ? ?

map.put(4,"MyBatis framework");? ? ? ?

map.put(5,"Java中文社群");

// 遍歷

for(Integer key : map.keySet()) {? ? ? ? ? ?

System.out.println(key);? ? ? ? ? ?

System.out.println(map.get(key));? ? ? ?

}? ?

}

}

以上程序的執(zhí)行結(jié)果為:

1

Java

2

JDK

3

Spring Framework

4

MyBatis framework

5

Java中文社群

5.Lambda

publicclassHashMapTest{

publicstaticvoidmain(String[] args){

// 創(chuàng)建并賦值

HashMapMap map =newHashMap();? ? ? ?

map.put(1,"Java");? ? ? ?

map.put(2,"JDK");? ? ? ?

map.put(3,"Spring Framework");? ? ? ?

map.put(4,"MyBatis framework");? ? ? ?

map.put(5,"Java中文社群");

// 遍歷

map.forEach((key, value) -> {? ? ? ? ? ?

System.out.println(key);? ? ? ? ? ?

System.out.println(value);? ? ?

? });?

? }

}

以上程序的執(zhí)行結(jié)果為:

1

Java

2

JDK

3

Spring Framework

4

MyBatis framework

5

Java中文社群

6.Streams API 單線程

publicclassHashMapTest{

publicstaticvoidmain(String[] args){

// 創(chuàng)建并賦值

HashMapMap map =newHashMap();? ? ? ?

map.put(1,"Java");? ? ? ?

map.put(2,"JDK");? ? ? ?

map.put(3,"Spring Framework");? ? ? ?

map.put(4,"MyBatis framework");? ? ? ?

map.put(5,"Java中文社群");

// 遍歷

map.entrySet().stream().forEach((entry) -> {? ? ? ? ? ?

System.out.println(entry.getKey());? ? ? ? ? ?

System.out.println(entry.getValue());? ? ? ?

});? ?

}

}

以上程序的執(zhí)行結(jié)果為:

1

Java

2

JDK

3

Spring Framework

4

MyBatis framework

5

Java中文社群

7.Streams API 多線程

publicclassHashMapTest{

publicstaticvoidmain(String[] args){

// 創(chuàng)建并賦值

HashMapMap map =newHashMap();? ? ? ?

map.put(1,"Java");? ? ? ?

map.put(2,"JDK");? ? ? ?

map.put(3,"Spring Framework");? ? ?

? map.put(4,"MyBatis framework");? ? ? ?

map.put(5,"Java中文社群");

// 遍歷

map.entrySet().parallelStream().forEach((entry) -> {? ? ? ? ? ?

System.out.println(entry.getKey());? ? ? ? ? ?

System.out.println(entry.getValue());? ? ? ?

});? ?

}

}

以上程序的執(zhí)行結(jié)果為:

4

MyBatis framework

5

Java中文社群

1

Java

2

JDK

3

Spring Framework

性能測試

接下來我們使用 Oracle 官方提供的性能測試工具 JMH(Java Microbenchmark Harness,JAVA 微基準測試套件)來測試一下這 7 種循環(huán)的性能罐监。

首先吴藻,我們先要引入 JMH 框架,在pom.xml文件中添加如下配置:

<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core -->

<dependency>

? ? <groupId>org.openjdk.jmh</groupId>

? ? <artifactId>jmh-core</artifactId>

? ? <version>1.23</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-generator-annprocess -->

<dependency>

? ? <groupId>org.openjdk.jmh</groupId>

? ? <artifactId>jmh-generator-annprocess</artifactId>

? ? <version>1.23</version>

? ? <scope>provided</scope>

</dependency>

然后編寫測試代碼弓柱,如下所示:

@BenchmarkMode(Mode.AverageTime) // 測試完成時間

@OutputTimeUnit(TimeUnit.NANOSECONDS)

@Warmup(iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS) // 預熱 2 輪沟堡,每次 1s

@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) // 測試 5 輪矢空,每次 3s

@Fork(1) // fork 1 個線程

@State(Scope.Thread) // 每個測試線程一個實例

public class HashMapCycleTest {

? ? static Map<Integer, String> map = new HashMap() {{

? ? ? ? // 添加數(shù)據(jù)

? ? ? ? for (int i = 0; i < 100; i++) {

? ? ? ? ? ? put(i, "val:" + i);

? ? ? ? }

? ? }};

? ? public static void main(String[] args) throws RunnerException {

? ? ? ? // 啟動基準測試

? ? ? ? Options opt = new OptionsBuilder()

? ? ? ? ? ? ? ? .include(HashMapCycle.class.getSimpleName()) // 要導入的測試類

? ? ? ? ? ? ? ? .output("/Users/admin/Desktop/jmh-map.log") // 輸出測試結(jié)果的文件

? ? ? ? ? ? ? ? .build();

? ? ? ? new Runner(opt).run(); // 執(zhí)行測試

? ? }

? ? @Benchmark

? ? public void entrySet() {

? ? ? ? // 遍歷

? ? ? ? Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();

? ? ? ? while (iterator.hasNext()) {

? ? ? ? ? ? Map.Entry<Integer, String> entry = iterator.next();

? ? ? ? ? ? Integer k = entry.getKey();

? ? ? ? ? ? String v = entry.getValue();

? ? ? ? }

? ? }

? ? @Benchmark

? ? public void forEachEntrySet() {

? ? ? ? // 遍歷

? ? ? ? for (Map.Entry<Integer, String> entry : map.entrySet()) {

? ? ? ? ? ? Integer k = entry.getKey();

? ? ? ? ? ? String v = entry.getValue();

? ? ? ? }

? ? }

? ? @Benchmark

? ? public void keySet() {

? ? ? ? // 遍歷

? ? ? ? Iterator<Integer> iterator = map.keySet().iterator();

? ? ? ? while (iterator.hasNext()) {

? ? ? ? ? ? Integer k = iterator.next();

? ? ? ? ? ? String v = map.get(k);

? ? ? ? }

? ? }

? ? @Benchmark

? ? public void forEachKeySet() {

? ? ? ? // 遍歷

? ? ? ? for (Integer key : map.keySet()) {

? ? ? ? ? ? Integer k = key;

? ? ? ? ? ? String v = map.get(k);

? ? ? ? }

? ? }

? ? @Benchmark

? ? public void lambda() {

? ? ? ? // 遍歷

? ? ? ? map.forEach((key, value) -> {

? ? ? ? ? ? Integer k = key;

? ? ? ? ? ? String v = map.get(k);

? ? ? ? });

? ? }

? ? @Benchmark

? ? public void streamApi() {

? ? ? ? // 單線程遍歷

? ? ? ? map.entrySet().stream().forEach((entry) -> {

? ? ? ? ? ? Integer k = entry.getKey();

? ? ? ? ? ? String v = entry.getValue();

? ? ? ? });

? ? }

? ? public void parallelStreamApi() {

? ? ? ? // 多線程遍歷

? ? ? ? map.entrySet().parallelStream().forEach((entry) -> {

? ? ? ? ? ? Integer k = entry.getKey();

? ? ? ? ? ? String v = entry.getValue();

? ? ? ? });

? ? }

}

所有被添加了@Benchmark注解的方法都會被測試航罗,因為 parallelStream 為多線程版本性能一定是最好的,所以就不參與測試了屁药,其他 6 個方法的測試結(jié)果如下:

其中 Score 列表示平均執(zhí)行時間粥血,±符號表示誤差。從以上結(jié)果可以看出酿箭,兩個entrySet的性能相近复亏,并且執(zhí)行速度最快,接下來是stream缭嫡,然后是兩個keySet缔御,性能最差的是lambda表達式。

注:以上結(jié)果基于測試環(huán)境:JDK 1.8 / Mac mini (2018) / Idea 2020.1

小結(jié)

因此我們應該盡量使用迭代器或 for 循環(huán)的 entrySet 遍歷械巡,或者是stream的方式刹淌。

性能原理分析

要理解性能測試的結(jié)果饶氏,我們需要把所有遍歷代碼通過javac,編譯成字節(jié)碼來看具體的原因有勾,編譯之后我們使用 Idea 打開字節(jié)碼信息疹启,內(nèi)容如下:

//

// Source code recreated from a .class file by IntelliJ IDEA

// (powered by Fernflower decompiler)

//

package com.example;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.Map.Entry;

public class HashMapTest {

? ? static Map<Integer, String> map = new HashMap() {

? ? ? ? {

? ? ? ? ? ? for(int var1 = 0; var1 < 2; ++var1) {

? ? ? ? ? ? ? ? this.put(var1, "val:" + var1);

? ? ? ? ? ? }

? ? ? ? }

? ? };

? ? public HashMapTest() {

? ? }

? ? public static void main(String[] var0) {

? ? ? ? entrySet();

? ? ? ? keySet();

? ? ? ? forEachEntrySet();

? ? ? ? forEachKeySet();

? ? ? ? lambda();

? ? ? ? streamApi();

? ? ? ? parallelStreamApi();

? ? }

? ? public static void entrySet() {

? ? ? ? Iterator var0 = map.entrySet().iterator();

? ? ? ? while(var0.hasNext()) {

? ? ? ? ? ? Entry var1 = (Entry)var0.next();

? ? ? ? ? ? System.out.println(var1.getKey());

? ? ? ? ? ? System.out.println((String)var1.getValue());

? ? ? ? }

? ? }

? ? public static void keySet() {

? ? ? ? Iterator var0 = map.keySet().iterator();

? ? ? ? while(var0.hasNext()) {

? ? ? ? ? ? Integer var1 = (Integer)var0.next();

? ? ? ? ? ? System.out.println(var1);

? ? ? ? ? ? System.out.println((String)map.get(var1));

? ? ? ? }

? ? }

? ? public static void forEachEntrySet() {

? ? ? ? Iterator var0 = map.entrySet().iterator();

? ? ? ? while(var0.hasNext()) {

? ? ? ? ? ? Entry var1 = (Entry)var0.next();

? ? ? ? ? ? System.out.println(var1.getKey());

? ? ? ? ? ? System.out.println((String)var1.getValue());

? ? ? ? }

? ? }

? ? public static void forEachKeySet() {

? ? ? ? Iterator var0 = map.keySet().iterator();

? ? ? ? while(var0.hasNext()) {

? ? ? ? ? ? Integer var1 = (Integer)var0.next();

? ? ? ? ? ? System.out.println(var1);

? ? ? ? ? ? System.out.println((String)map.get(var1));

? ? ? ? }

? ? }

? ? public static void lambda() {

? ? ? ? map.forEach((var0, var1) -> {

? ? ? ? ? ? System.out.println(var0);

? ? ? ? ? ? System.out.println(var1);

? ? ? ? });

? ? }

? ? public static void streamApi() {

? ? ? ? map.entrySet().stream().forEach((var0) -> {

? ? ? ? ? ? System.out.println(var0.getKey());

? ? ? ? ? ? System.out.println((String)var0.getValue());

? ? ? ? });

? ? }

? ? public static void parallelStreamApi() {

? ? ? ? map.entrySet().parallelStream().forEach((var0) -> {

? ? ? ? ? ? System.out.println(var0.getKey());

? ? ? ? ? ? System.out.println((String)var0.getValue());

? ? ? ? });

? ? }

}

從結(jié)果可以看出,除了 Lambda 和 Streams API 之外蔼卡,通過迭代器循環(huán)和for循環(huán)的遍歷的EntrySet最終生成的代碼是一樣的喊崖,他們都是在循環(huán)中創(chuàng)建了一個遍歷對象Entry,如下所示:

public static void entrySet() {

? ? Iterator var0 = map.entrySet().iterator();

? ? while(var0.hasNext()) {

? ? ? ? Entry var1 = (Entry)var0.next();

? ? ? ? System.out.println(var1.getKey());

? ? ? ? System.out.println((String)var1.getValue());

? ? }

}

public static void forEachEntrySet() {

? ? Iterator var0 = map.entrySet().iterator();

? ? while(var0.hasNext()) {

? ? ? ? Entry var1 = (Entry)var0.next();

? ? ? ? System.out.println(var1.getKey());

? ? ? ? System.out.println((String)var1.getValue());

? ? }

}

而通過迭代器和for循環(huán)遍歷的KeySet代碼也是一樣的雇逞,如下所示:

public static void keySet() {

? ? Iterator var0 = map.keySet().iterator();

? ? while(var0.hasNext()) {

? ? ? ? Integer var1 = (Integer)var0.next();

? ? ? ? System.out.println(var1);

? ? ? ? System.out.println((String)map.get(var1));

? ? }

}

public static void forEachKeySet() {

? ? Iterator var0 = map.keySet().iterator();

? ? while(var0.hasNext()) {

? ? ? ? Integer var1 = (Integer)var0.next();

? ? ? ? System.out.println(var1);

? ? ? ? System.out.println((String)map.get(var1));

? ? }

}

可以看出KeySet在循環(huán)中創(chuàng)建了一個Integer的局部變量荤懂,并且值是從map對象中直接獲取的。

所以通過上面測試結(jié)果可以看出塘砸,無論是通過迭代器方式還是 for 循環(huán)方式节仿,最終的測試結(jié)果EntrySet的兩個方法的性能都是相似的,而KeySet也是同理掉蔬。

安全性測試

從上面的性能測試結(jié)果和原理分析廊宪,我想大家應該選用那種遍歷方式,已經(jīng)心中有數(shù)的女轿,而接下來我們就從「安全」的角度入手箭启,來分析那種遍歷方式更安全。

我們把以上遍歷劃分為四類進行測試:迭代器方式蛉迹、For 循環(huán)方式傅寡、Lambda 方式和 Stream 方式,測試代碼如下北救。

1.迭代器方式

Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();

while (iterator.hasNext()) {

? ? Map.Entry<Integer, String> entry = iterator.next();

? ? if (entry.getKey() == 1) {

? ? ? ? // 刪除

? ? ? ? System.out.println("del:" + entry.getKey());

? ? ? ? iterator.remove();

? ? } else {

? ? ? ? System.out.println("show:" + entry.getKey());

? ? }

}

以上程序的執(zhí)行結(jié)果:

show:0

del:1

show:2

測試結(jié)果:迭代器中循環(huán)刪除數(shù)據(jù)安全荐操。

2.For 循環(huán)方式

for(Map.Entry entry : map.entrySet()) {if(entry.getKey() ==1) {// 刪除System.out.println("del:"+ entry.getKey());? ? ? ? map.remove(entry.getKey());? ? }else{? ? ? ? System.out.println("show:"+ entry.getKey());? ? }}復制代碼

以上程序的執(zhí)行結(jié)果:

測試結(jié)果:For 循環(huán)中刪除數(shù)據(jù)非安全

3.Lambda 方式

map.forEach((key, value) -> {

? ? if (key == 1) {

? ? ? ? System.out.println("del:" + key);

? ? ? ? map.remove(key);

? ? } else {

? ? ? ? System.out.println("show:" + key);

? ? }

});

以上程序的執(zhí)行結(jié)果:

測試結(jié)果:Lambda 循環(huán)中刪除數(shù)據(jù)非安全扭倾。

Lambda 刪除的正確方式

// 根據(jù) map 中的 key 去判斷刪除

map.keySet().removeIf(key -> key == 1);

map.forEach((key, value) -> {

? ? System.out.println("show:" + key);

});

以上程序的執(zhí)行結(jié)果:

show:0

show:2

從上面的代碼可以看出淀零,可以先使用Lambda的removeIf刪除多余的數(shù)據(jù),再進行循環(huán)是一種正確操作集合的方式膛壹。

4.Stream 方式

map.entrySet().stream().forEach((entry) -> {if(entry.getKey() ==1) {? ? ? ? System.out.println("del:"+ entry.getKey());? ? ? ? map.remove(entry.getKey());? ? }else{? ? ? ? System.out.println("show:"+ entry.getKey());? ? }});復制代碼

以上程序的執(zhí)行結(jié)果:

測試結(jié)果:Stream 循環(huán)中刪除數(shù)據(jù)非安全驾中。

Stream 循環(huán)的正確方式

map.entrySet().stream().filter(m -> 1 != m.getKey()).forEach((entry) -> {

? ? if (entry.getKey() == 1) {

? ? ? ? System.out.println("del:" + entry.getKey());

? ? } else {

? ? ? ? System.out.println("show:" + entry.getKey());

? ? }

});

以上程序的執(zhí)行結(jié)果:

show:0

show:2

從上面的代碼可以看出,可以使用Stream中的filter過濾掉無用的數(shù)據(jù)模聋,再進行遍歷也是一種安全的操作集合的方式肩民。

小結(jié)

我們不能在遍歷中使用集合map.remove()來刪除數(shù)據(jù),這是非安全的操作方式链方,但我們可以使用迭代器的iterator.remove()的方法來刪除數(shù)據(jù)持痰,這是安全的刪除集合的方式。同樣的我們也可以使用 Lambda 中的removeIf來提前刪除數(shù)據(jù)祟蚀,或者是使用 Stream 中的filter過濾掉要刪除的數(shù)據(jù)進行循環(huán)工窍,這樣都是安全的割卖,當然我們也可以在for循環(huán)前刪除數(shù)據(jù)在遍歷也是線程安全的。

總結(jié)

本文我們講了 HashMap 4 種遍歷方式:迭代器患雏、for鹏溯、lambda、stream淹仑,以及具體的 7 種遍歷方法丙挽,綜合性能和安全性來看,我們應該盡量使用迭代器entrySet的遍歷方式匀借,或者是stream filter的方式來遍歷 HashMap颜阐。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吓肋,隨后出現(xiàn)的幾起案子凳怨,更是在濱河造成了極大的恐慌,老刑警劉巖是鬼,帶你破解...
    沈念sama閱讀 216,324評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件猿棉,死亡現(xiàn)場離奇詭異,居然都是意外死亡屑咳,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評論 3 392
  • 文/潘曉璐 我一進店門弊琴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來兆龙,“玉大人,你說我怎么就攤上這事敲董∽匣剩” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評論 0 353
  • 文/不壞的土叔 我叫張陵腋寨,是天一觀的道長聪铺。 經(jīng)常有香客問我,道長萄窜,這世上最難降的妖魔是什么铃剔? 我笑而不...
    開封第一講書人閱讀 58,147評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮查刻,結(jié)果婚禮上键兜,老公的妹妹穿的比我還像新娘。我一直安慰自己穗泵,他們只是感情好普气,可當我...
    茶點故事閱讀 67,160評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著佃延,像睡著了一般现诀。 火紅的嫁衣襯著肌膚如雪夷磕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,115評論 1 296
  • 那天仔沿,我揣著相機與錄音坐桩,去河邊找鬼。 笑死于未,一個胖子當著我的面吹牛撕攒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播烘浦,決...
    沈念sama閱讀 40,025評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼抖坪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了闷叉?” 一聲冷哼從身側(cè)響起擦俐,我...
    開封第一講書人閱讀 38,867評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎握侧,沒想到半個月后蚯瞧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡品擎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,528評論 2 332
  • 正文 我和宋清朗相戀三年埋合,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萄传。...
    茶點故事閱讀 39,688評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡甚颂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秀菱,到底是詐尸還是另有隱情振诬,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評論 5 343
  • 正文 年R本政府宣布衍菱,位于F島的核電站赶么,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏脊串。R本人自食惡果不足惜辫呻,卻給世界環(huán)境...
    茶點故事閱讀 41,001評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琼锋。 院中可真熱鬧印屁,春花似錦、人聲如沸斩例。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至础钠,卻和暖如春恰力,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背旗吁。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評論 1 268
  • 我被黑心中介騙來泰國打工踩萎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人很钓。 一個月前我還...
    沈念sama閱讀 47,685評論 2 368
  • 正文 我出身青樓香府,卻偏偏與公主長得像,于是被迫代替她去往敵國和親码倦。 傳聞我的和親對象是個殘疾皇子企孩,可洞房花燭夜當晚...
    茶點故事閱讀 44,573評論 2 353