Java代碼寫的很丑?那你得看看這篇——代碼精簡之道

古語有云:

道為術(shù)之靈圃泡,術(shù)為道之體碟案;以道統(tǒng)術(shù),以術(shù)得道颇蜡。

其中:“道”指“規(guī)律价说、道理辆亏、理論”,“術(shù)”指“方法鳖目、技巧扮叨、技術(shù)”。意思是:“道”是“術(shù)”的靈魂领迈,“術(shù)”是“道”的肉體彻磁;可以用“道”來統(tǒng)管“術(shù)”,也可以從“術(shù)”中獲得“道”狸捅。

在拜讀大佬“孤盡”的文章《Code Review是苦澀但有意思的修行》時(shí)衷蜓,感受最深的一句話就是:“優(yōu)質(zhì)的代碼一定是少即是多的精兵原則”,這就是大佬的代碼精簡之“道”尘喝。

工匠追求“術(shù)”到極致恍箭,其實(shí)就是在尋“道”,且離悟“道”也就不遠(yuǎn)了瞧省,亦或是已經(jīng)得道扯夭,這就是“工匠精神”——一種追求“以術(shù)得道”的精神。如果一個(gè)工匠只滿足于“術(shù)”鞍匾,不能追求“術(shù)”到極致去悟“道”交洗,那只是一個(gè)靠“術(shù)”養(yǎng)家糊口的工匠而已。作者根據(jù)多年來的實(shí)踐探索橡淑,總結(jié)了大量的 Java 代碼精簡之“術(shù)”构拳,試圖闡述出心中的 Java 代碼精簡之“道”。

利用語法

1.1.利用三元表達(dá)式

普通:

String?title;if?(isMember(phone))?{????title?=?"會(huì)員";}?else?{????title?=?"游客";}

精簡:

String?title?=?isMember(phone)???"會(huì)員"?:?"游客";

注意:對于包裝類型的算術(shù)計(jì)算梁棠,需要注意避免拆包時(shí)的空指針問題置森。

1.2.利用 for-each 語句

從 Java 5 起,提供了 for-each 循環(huán)符糊,簡化了數(shù)組和集合的循環(huán)遍歷凫海。 for-each 循環(huán)允許你無需保持傳統(tǒng) for 循環(huán)中的索引就可以遍歷數(shù)組,或在使用迭代器時(shí)無需在 while 循環(huán)中調(diào)用 hasNext 方法和 next 方法就可以遍歷集合男娄。

普通:

double[] values = ...;

for(int i = 0; i < values.length; i++) {

double value = values[i];

// TODO: 處理value

}

List valueList = ...;

Iterator iterator = valueList.iterator();

while (iterator.hasNext()) {

Double value = iterator.next();

// TODO: 處理value

精簡:

double[] values = ...;

for(double value : values) {

// TODO: 處理value

}

List valueList = ...;

for(Double value : valueList) {

// TODO: 處理value

1.3.利用 try-with-resource 語句

所有實(shí)現(xiàn) Closeable 接口的“資源”行贪,均可采用 try-with-resource 進(jìn)行簡化。

普通:

BufferedReader reader = null;

try {

reader = new BufferedReader(new FileReader("cities.csv"));

String line;

while ((line = reader.readLine()) != null) {

// TODO: 處理line

}

} catch (IOException e) {

log.error("讀取文件異常", e);

} finally {

if (reader != null) {

try {

reader.close();

} catch (IOException e) {

log.error("關(guān)閉文件異常", e);

}

}

精簡:

try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) {

String line;

while ((line = reader.readLine()) != null) {

// TODO: 處理line

}

} catch (IOException e) {

log.error("讀取文件異常", e);

1.4.利用 return 關(guān)鍵字

利用 return 關(guān)鍵字模闲,可以提前函數(shù)返回建瘫,避免定義中間變量。

普通:

public?static?boolean?hasSuper(@NonNull?List?userList)?{

boolean?hasSuper?=?false;

for?(UserDO?user?:?userList)?{

if?(Boolean.TRUE.equals(user.getIsSuper()))?{

hasSuper?=?true;

break;

}

}

return?hasSuper;

}

精簡:

public?static?boolean?hasSuper(@NonNull?List?userList)?{

for?(UserDO?user?:?userList)?{

if?(Boolean.TRUE.equals(user.getIsSuper()))?{

return?true;

}

}

return?false;

}

1.5.利用 static 關(guān)鍵字

利用 static 關(guān)鍵字尸折,可以把字段變成靜態(tài)字段啰脚,也可以把函數(shù)變?yōu)殪o態(tài)函數(shù),調(diào)用時(shí)就無需初始化類對象实夹。

普通:

public?final?class?GisHelper?{

public?double?distance(double?lng1,?double?lat1,?double?lng2,?double?lat2)?{

//?方法實(shí)現(xiàn)代碼

}

}

GisHelper?gisHelper?=?new?GisHelper();

double?distance?=?gisHelper.distance(116.178692D,?39.967115D,?116.410778D,?39.899721D);

精簡:

public?final?class?GisHelper?{

public?static?double?distance(double?lng1,?double?lat1,?double?lng2,?double?lat2)?{

//?方法實(shí)現(xiàn)代碼

}

}

double?distance?=?GisHelper.distance(116.178692D,?39.967115D,?116.410778D,?39.899721D);

1.6.利用 lambda 表達(dá)式

Java 8 發(fā)布以后橄浓,lambda 表達(dá)式大量替代匿名內(nèi)部類的使用晾咪,在簡化了代碼的同時(shí),更突出了原有匿名內(nèi)部類中真正有用的那部分代碼贮配。

普通:

new?Thread(new?Runnable()?{????public?void?run()?{????????//?線程處理代碼????}}).start();

精簡:

new?Thread(()?->?{????//?線程處理代碼}).start();

1.7.利用方法引用

方法引用(::)谍倦,可以簡化 lambda 表達(dá)式,省略變量聲明和函數(shù)調(diào)用泪勒。

普通:

Arrays.sort(nameArray,?(a,?b)?->?a.compareToIgnoreCase(b));

List?userIdList?=?userList.stream()

.map(user?->?user.getId())

.collect(Collectors.toList());

精簡:

Arrays.sort(nameArray,?String::compareToIgnoreCase);

List?userIdList?=?userList.stream()

.map(UserDO::getId)

.collect(Collectors.toList());

1.8.利用靜態(tài)導(dǎo)入

靜態(tài)導(dǎo)入(import static)昼蛀,當(dāng)程序中大量使用同一靜態(tài)常量和函數(shù)時(shí),可以簡化靜態(tài)常量和函數(shù)的引用圆存。

普通:

List?areaList?=?radiusList.stream().map(r?->?Math.PI?*?Math.pow(r,?2)).collect(Collectors.toList());

精簡:

import?static?java.lang.Math.PI;

import?static?java.lang.Math.pow;

import?static?java.util.stream.Collectors.toList;

List?areaList?=?radiusList.stream().map(r?->?PI?*?pow(r,?2)).collect(toList());

注意:靜態(tài)引入容易造成代碼閱讀困難叼旋,所以在實(shí)際項(xiàng)目中應(yīng)該警慎使用。

1.9.利用 unchecked 異常

Java 的異常分為兩類:Checked 異常和 Unchecked 異常沦辙。Unchecked 異常繼承了RuntimeException 夫植,特點(diǎn)是代碼不需要處理它們也能通過編譯,所以它們稱作 Unchecked 異常油讯。利用 Unchecked 異常详民,可以避免不必要的 try-catch 和 throws 異常處理。

普通:

@Service

public?class?UserService?{

public?void?createUser(UserCreateVO?create,?OpUserVO?user)?throws?BusinessException?{

checkOperatorUser(user);

...

}

private?void?checkOperatorUser(OpUserVO?user)?throws?BusinessException?{

if?(!hasPermission(user))?{

throw?new?BusinessException("用戶無操作權(quán)限");

}

...

}

...

}

@RestController

@RequestMapping("/user")

public?class?UserController?{

@Autowired

private?UserService?userService;

@PostMapping("/createUser")

public?Result?createUser(@RequestBody?@Valid?UserCreateVO?create,?OpUserVO?user)?throws?BusinessException?{

userService.createUser(create,?user);

return?Result.success();

}

...

}

精簡:

@Service

public?class?UserService?{

public?void?createUser(UserCreateVO?create,?OpUserVO?user)?{

checkOperatorUser(user);

...

}

private?void?checkOperatorUser(OpUserVO?user)?{

if?(!hasPermission(user))?{

throw?new?BusinessRuntimeException("用戶無操作權(quán)限");

}

...

}

...

}

@RestController

@RequestMapping("/user")

public?class?UserController?{

@Autowired

private?UserService?userService;

@PostMapping("/createUser")

public?Result?createUser(@RequestBody?@Valid?UserCreateVO?create,?OpUserVO?user)?{

userService.createUser(create,?user);

return?Result.success();

}

...

}

利用注解

2.1.利用 Lombok 注解

Lombok 提供了一組有用的注解陌兑,可以用來消除Java類中的大量樣板代碼沈跨。

普通:

public?class?UserVO?{

private?Long?id;

private?String?name;

public?Long?getId()?{

return?this.id;

}

public?void?setId(Long?id)?{

this.id?=?id;

}

public?String?getName()?{

return?this.name;

}

public?void?setName(String?name)?{

this.name?=?name;

}

...

}

精簡:

@Getter

@Setter

@ToString

public?class?UserVO?{

private?Long?id;

private?String?name;

...

}

2.2.利用 Validation 注解

普通:

@Getter@Setter@ToStringpublic?class?UserCreateVO?{

@NotBlank(message?=?"用戶名稱不能為空")

private?String?name;

@NotNull(message?=?"公司標(biāo)識(shí)不能為空")

private?Long?companyId;

...

}

@Service@Validatedpublic?class?UserService?{

public?Long?createUser(@Valid?UserCreateVO?create)?{

//?TODO:?創(chuàng)建用戶

return?null;

}

}

精簡:

@Getter

@Setter

@ToString

public?class?UserCreateVO?{

@NotBlank(message?=?"用戶名稱不能為空")

private?String?name;

@NotNull(message?=?"公司標(biāo)識(shí)不能為空")

private?Long?companyId;

...

}

@Service

@Validated

public?class?UserService?{

public?Long?createUser(@Valid?UserCreateVO?create)?{

//?TODO:?創(chuàng)建用戶

return?null;

}

}

2.3.利用 @NonNull 注解

Spring 的 @NonNull 注解,用于標(biāo)注參數(shù)或返回值非空兔综,適用于項(xiàng)目內(nèi)部團(tuán)隊(duì)協(xié)作饿凛。只要實(shí)現(xiàn)方和調(diào)用方遵循規(guī)范,可以避免不必要的空值判斷软驰,這充分體現(xiàn)了阿里的“新六脈神劍”提倡的“因?yàn)樾湃谓е希院唵巍薄?/p>

普通:

public?List?queryCompanyUser(Long?companyId)?{

//?檢查公司標(biāo)識(shí)

if?(companyId?==?null)?{

return?null;

}

//?查詢返回用戶

List?userList?=?userDAO.queryByCompanyId(companyId);

return?userList.stream().map(this::transUser).collect(Collectors.toList());

}

Long?companyId?=?1L;

List?userList?=?queryCompanyUser(companyId);

if?(CollectionUtils.isNotEmpty(userList))?{

for?(UserVO?user?:?userList)?{

//?TODO:?處理公司用戶

}

}

精簡:

public?@NonNull?List?queryCompanyUser(@NonNull?Long?companyId)?{

List?userList?=?userDAO.queryByCompanyId(companyId);

return?userList.stream().map(this::transUser).collect(Collectors.toList());

}

Long?companyId?=?1L;

List?userList?=?queryCompanyUser(companyId);

for?(UserVO?user?:?userList)?{

//?TODO:?處理公司用戶

}

2.4.利用注解特性

注解有以下特性可用于精簡注解聲明:

1、當(dāng)注解屬性值跟默認(rèn)值一致時(shí)锭亏,可以刪除該屬性賦值纠吴;

2、當(dāng)注解只有value屬性時(shí)贰镣,可以去掉value進(jìn)行簡寫呜象;

3膳凝、當(dāng)注解屬性組合等于另一個(gè)特定注解時(shí)碑隆,直接采用該特定注解。

普通:

@Lazy(true);

@Service(value?=?"userService")

@RequestMapping(path?=?"/getUser",?method?=?RequestMethod.GET)

精簡:

@Lazy

@Service("userService")

@GetMapping("/getUser")

利用泛型

3.1.泛型接口

在 Java 沒有引入泛型前蹬音,都是采用 Object 表示通用對象上煤,最大的問題就是類型無法強(qiáng)校驗(yàn)并且需要強(qiáng)制類型轉(zhuǎn)換。

普通:

public?interface?Comparable?{

public?int?compareTo(Object?other);

}

@Getter

@Setter

@ToString

public?class?UserVO?implements?Comparable?{

private?Long?id;

@Override

public?int?compareTo(Object?other)?{

UserVO?user?=?(UserVO)other;

return?Long.compare(this.id,?user.id);

}

}

精簡:

public?interface?Comparable?{

public?int?compareTo(T?other);

}

@Getter

@Setter

@ToString

public?class?UserVO?implements?Comparable?{

private?Long?id;

@Override

public?int?compareTo(UserVO?other)?{

return?Long.compare(this.id,?other.id);

}

}

3.2.泛型類

普通:

@Getter

@Setter

@ToString

public?class?IntPoint?{

private?Integer?x;

private?Integer?y;

}

@Getter

@Setter

@ToString

public?class?DoublePoint?{

private?Double?x;

private?Double?y;

}

精簡:

@Getter

@Setter

@ToString

public?class?Point?{

private?T?x;

private?T?y;

}

3.3.泛型方法

普通:

public?static?Map?newHashMap(String[]?keys,?Integer[]?values)?{

//?檢查參數(shù)非空

if?(ArrayUtils.isEmpty(keys)?||?ArrayUtils.isEmpty(values))?{

return?Collections.emptyMap();

}

//?轉(zhuǎn)化哈希映射

Map?map?=?new?HashMap<>();

int?length?=?Math.min(keys.length,?values.length);

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

map.put(keys[i],?values[i]);

}

return?map;

}

精簡:

public?static??Map?newHashMap(K[]?keys,?V[]?values)?{

//?檢查參數(shù)非空

if?(ArrayUtils.isEmpty(keys)?||?ArrayUtils.isEmpty(values))?{

return?Collections.emptyMap();

}

//?轉(zhuǎn)化哈希映射

Map?map?=?new?HashMap<>();

int?length?=?Math.min(keys.length,?values.length);

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

map.put(keys[i],?values[i]);

}

return?map;

利用自身方法

4.1.利用構(gòu)造方法

構(gòu)造方法著淆,可以簡化對象的初始化和設(shè)置屬性操作劫狠。對于屬性字段較少的類拴疤,可以自定義構(gòu)造方法。

普通:

@Getter

@Setter

@ToString

public?class?PageDataVO?{

private?Long?totalCount;

private?List?dataList;

}

PageDataVO?pageData?=?new?PageDataVO<>();

pageData.setTotalCount(totalCount);

pageData.setDataList(userList);

return?pageData;

...

精簡:

@Getter

@Setter

@ToString

@NoArgsConstructor

@AllArgsConstructor

public?class?PageDataVO?{

private?Long?totalCount;

private?List?dataList;

}

return?new?PageDataVO<>(totalCount,?userList);

注意:如果屬性字段被替換時(shí)独泞,存在構(gòu)造函數(shù)初始化賦值問題呐矾。比如把屬性字段title替換為 nickname ,由于構(gòu)造函數(shù)的參數(shù)個(gè)數(shù)和類型不變懦砂,原有構(gòu)造函數(shù)初始化語句不會(huì)報(bào)錯(cuò)蜒犯,導(dǎo)致把原title值賦值給 nickname 。如果采用 Setter 方法賦值荞膘,編譯器會(huì)提示錯(cuò)誤并要求修復(fù)罚随。

4.2.利用 Set 的 add 方法

利用 Set 的 add 方法的返回值,可以直接知道該值是否已經(jīng)存在羽资,可以避免調(diào)用 contains 方法判斷存在淘菩。

普通:

以下案例是進(jìn)行用戶去重轉(zhuǎn)化操作,需要先調(diào)用 contains 方法判斷存在屠升,后調(diào)用add方法進(jìn)行添加潮改。

Set?userIdSet?=?new?HashSet<>();

List?userVOList?=?new?ArrayList<>();

for?(UserDO?userDO?:?userDOList)?{

if?(!userIdSet.contains(userDO.getId()))?{

userIdSet.add(userDO.getId());

userVOList.add(transUser(userDO));

}

}

精簡:

Set?userIdSet?=?new?HashSet<>();

List?userVOList?=?new?ArrayList<>();

for?(UserDO?userDO?:?userDOList)?{

if?(userIdSet.add(userDO.getId()))?{

userVOList.add(transUser(userDO));

}

}

4.3.利用 Map 的 computeIfAbsent 方法

利用 Map 的 computeIfAbsent 方法,可以保證獲取到的對象非空腹暖,從而避免了不必要的空判斷和重新設(shè)置值进陡。

普通:

Map>?roleUserMap?=?new?HashMap<>();

for?(UserDO?userDO?:?userDOList)?{

Long?roleId?=?userDO.getRoleId();

List?userList?=?roleUserMap.get(roleId);

if?(Objects.isNull(userList))?{

userList?=?new?ArrayList<>();

roleUserMap.put(roleId,?userList);

}

userList.add(userDO);

}

精簡:

Map>?roleUserMap?=?new?HashMap<>();

for?(UserDO?userDO?:?userDOList)?{

roleUserMap.computeIfAbsent(userDO.getRoleId(),?key?->?new?ArrayList<>())

.add(userDO);

}

4.4.利用鏈?zhǔn)骄幊?/b>

鏈?zhǔn)骄幊蹋步屑?jí)聯(lián)式編程微服,調(diào)用對象的函數(shù)時(shí)返回一個(gè)this對象指向?qū)ο蟊旧碇壕危_(dá)到鏈?zhǔn)叫Ч梢约?jí)聯(lián)調(diào)用以蕴。鏈?zhǔn)骄幊痰膬?yōu)點(diǎn)是:編程性強(qiáng)糙麦、可讀性強(qiáng)、代碼簡潔丛肮。

普通:

StringBuilder?builder?=?new?StringBuilder(96);

builder.append("select?id,?name?from?");

builder.append(T_USER);

builder.append("?where?id?=?");

builder.append(userId);

builder.append(";");

精簡:

StringBuilder?builder?=?new?StringBuilder(96);

builder.append("select?id,?name?from?")

.append(T_USER)

.append("?where?id?=?")

.append(userId)

.append(";");

利用工具方法

5.1.避免空值判斷

普通:

if?(userList?!=?null?&&?!userList.isEmpty())?{????//?TODO:?處理代碼}

精簡:

if?(CollectionUtils.isNotEmpty(userList))?{????//?TODO:?處理代碼}

5.2.避免條件判斷

普通:

double?result;if?(value?<=?MIN_LIMIT)?{????result?=?MIN_LIMIT;}?else?{????result?=?value;}

精簡:

double?result?=?Math.max(MIN_LIMIT,?value);

5.3.簡化賦值語句

普通:

public?static?final?List?ANIMAL_LIST;

static?{

List?animalList?=?new?ArrayList<>();

animalList.add("dog");

animalList.add("cat");

animalList.add("tiger");

ANIMAL_LIST?=?Collections.unmodifiableList(animalList);

}

精簡:

//?JDK流派

public?static?final?List?ANIMAL_LIST?=?Arrays.asList("dog",?"cat",?"tiger");

//?Guava流派

public?static?final?List?ANIMAL_LIST?=?ImmutableList.of("dog",?"cat",?"tiger");

注意:Arrays.asList 返回的 List 并不是 ArrayList 赡磅,不支持 add 等變更操作。

5.4.簡化數(shù)據(jù)拷貝

普通:

UserVO?userVO?=?new?UserVO();

userVO.setId(userDO.getId());

userVO.setName(userDO.getName());

...

userVO.setDescription(userDO.getDescription());

userVOList.add(userVO);

精簡:

UserVO?userVO?=?new?UserVO();

BeanUtils.copyProperties(userDO,?userVO);

userVOList.add(userVO);

反例:

List<UserVO>?userVOList?=?JSON.parseArray(JSON.toJSONString(userDOList),?UserVO.class);

精簡代碼宝与,但不能以過大的性能損失為代價(jià)焚廊。例子是淺層拷貝,用不著 JSON 這樣重量級(jí)的武器习劫。

5.5.簡化異常斷言

普通:

if?(Objects.isNull(userId))?{????throw?new?IllegalArgumentException("用戶標(biāo)識(shí)不能為空");}

精簡:

Assert.notNull(userId,?"用戶標(biāo)識(shí)不能為空");

注意:可能有些插件不認(rèn)同這種判斷咆瘟,導(dǎo)致使用該對象時(shí)會(huì)有空指針警告。

5.6.簡化測試用例

把測試用例數(shù)據(jù)以 JSON 格式存入文件中诽里,通過 JSON 的 parseObject 和 parseArray 方法解析成對象袒餐。雖然執(zhí)行效率上有所下降,但可以減少大量的賦值語句,從而精簡了測試代碼灸眼。

普通:

@Test

public?void?testCreateUser()?{

UserCreateVO?userCreate?=?new?UserCreateVO();

userCreate.setName("Changyi");

userCreate.setTitle("Developer");

userCreate.setCompany("AMAP");

...

Long?userId??=?userService.createUser(OPERATOR,?userCreate);

Assert.assertNotNull(userId,?"創(chuàng)建用戶失敗");

精簡:

@Test

public?void?testCreateUser()?{

String?jsonText?=?ResourceHelper.getResourceAsString(getClass(),?"createUser.json");

UserCreateVO?userCreate?=?JSON.parseObject(jsonText,?UserCreateVO.class);

Long?userId??=?userService.createUser(OPERATOR,?userCreate);

Assert.assertNotNull(userId,?"創(chuàng)建用戶失敗");

}

建議:JSON 文件名最好以被測試的方法命名卧檐,如果有多個(gè)版本可以用數(shù)字后綴表示。

5.7.簡化算法實(shí)現(xiàn)

一些常規(guī)算法焰宣,已有現(xiàn)成的工具方法霉囚,我們就沒有必要自己實(shí)現(xiàn)了。

普通:

int?totalSize?=?valueList.size();

List>?partitionList?=?new?ArrayList<>();

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

partitionList.add(valueList.subList(i,?Math.min(i?+?PARTITION_SIZE,?totalSize)));

}

精簡:

List<List<Integer>>?partitionList?=?ListUtils.partition(valueList,?PARTITION_SIZE);

5.8.封裝工具方法

一些特殊算法匕积,沒有現(xiàn)成的工具方法佛嬉,我們就只好自己親自實(shí)現(xiàn)了。

普通:

比如闸天,SQL 設(shè)置參數(shù)值的方法就比較難用暖呕,setLong 方法不能設(shè)置參數(shù)值為 null 。

//?設(shè)置參數(shù)值

if?(Objects.nonNull(user.getId()))?{

statement.setLong(1,?user.getId());

}?else?{

statement.setNull(1,?Types.BIGINT);

}

...

精簡:

我們可以封裝為一個(gè)工具類 SqlHelper 苞氮,簡化設(shè)置參數(shù)值的代碼湾揽。

/**?SQL輔助類?*/

public?final?class?SqlHelper?{

/**?設(shè)置長整數(shù)值?*/

public?static?void?setLong(PreparedStatement?statement,?int?index,?Long?value)?throws?SQLException?{

if?(Objects.nonNull(value))?{

statement.setLong(index,?value.longValue());

}?else?{

statement.setNull(index,?Types.BIGINT);

}

}

...

}

//?設(shè)置參數(shù)值

SqlHelper.setLong(statement,?1,?user.getId());

最后:

建議默認(rèn)編寫出可讀和簡單的代碼。如果你真的發(fā)現(xiàn)存在性能問題并已經(jīng)找出它的位置笼吟,那么仍然有很多選擇來對此進(jìn)行處理而不必為了追求快速而寫出復(fù)雜的代碼库物。不到萬不得已不要為了性能而犧牲簡潔性,同時(shí)要學(xué)會(huì)始終用分析工具來處理性能問題贷帮。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末戚揭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子撵枢,更是在濱河造成了極大的恐慌民晒,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锄禽,死亡現(xiàn)場離奇詭異潜必,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)沃但,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門磁滚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人宵晚,你說我怎么就攤上這事垂攘。” “怎么了淤刃?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵晒他,是天一觀的道長。 經(jīng)常有香客問我钝凶,道長仪芒,這世上最難降的妖魔是什么唁影? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任耕陷,我火速辦了婚禮掂名,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘哟沫。我一直安慰自己饺蔑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布嗜诀。 她就那樣靜靜地躺著猾警,像睡著了一般。 火紅的嫁衣襯著肌膚如雪隆敢。 梳的紋絲不亂的頭發(fā)上发皿,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音拂蝎,去河邊找鬼穴墅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛温自,可吹牛的內(nèi)容都是我干的玄货。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼悼泌,長吁一口氣:“原來是場噩夢啊……” “哼松捉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起馆里,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對情侶失蹤隘世,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后鸠踪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體以舒,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年慢哈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔓钟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卵贱,死狀恐怖滥沫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情键俱,我是刑警寧澤兰绣,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站编振,受9級(jí)特大地震影響缀辩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一臀玄、第九天 我趴在偏房一處隱蔽的房頂上張望瓢阴。 院中可真熱鬧,春花似錦健无、人聲如沸荣恐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叠穆。三九已至,卻和暖如春臼膏,著一層夾襖步出監(jiān)牢的瞬間硼被,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國打工渗磅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嚷硫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓夺溢,卻偏偏與公主長得像论巍,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子风响,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345