lombok深度指南

Contents

介紹

Project Lombok是一個(gè)java庫(kù)码倦,它可以自動(dòng)插入你的編輯器并構(gòu)建工具,增強(qiáng)你的java代碼。
永遠(yuǎn)不要再寫另一個(gè)getter或equals方法催植,使用一個(gè)注解榨呆,您的類具有一個(gè)功能齊全的構(gòu)建器凡纳,自動(dòng)化您的日志記錄變量等等:

Image illustrating the availability of new methods on a data class in Eclipse.

安裝

idea 安裝lombok

Jetbrains的IntelliJ IDEA的編輯與lombok兼容录肯。

添加Lombok IntelliJ插件以添加對(duì)IntelliJ的lombok支持:

  • File > Settings > Plugins
  • 點(diǎn)擊 Browse repositories...
  • 搜索 Lombok Plugin
  • 點(diǎn)擊 Install plugin
  • 重啟IntelliJ IDEA

Lombok 注解

典型的Java項(xiàng)目將數(shù)百行代碼用于定義簡(jiǎn)單數(shù)據(jù)類所需的樣板文件并不罕見(jiàn)屏鳍。這些類通常包含這些字段的若干字段溉仑,getter和setter挖函,以及equals和 hashCode實(shí)施方式。在最簡(jiǎn)單的場(chǎng)景中浊竟,Lombok項(xiàng)目可以將這些類減少到必需的字段和單個(gè)@Data注解怨喘。

當(dāng)然,最簡(jiǎn)單的場(chǎng)景不一定是開發(fā)人員日常所面臨的場(chǎng)景逐沙。出于這個(gè)原因哲思,Project Lombok中有許多注解允許對(duì)類的結(jié)構(gòu)和行為進(jìn)行更細(xì)粒度的控制。

@Getter and @Setter

@Getter@Setter注解分別為字段生成getter和setter吩案。生成的getter方法正確地遵循了布爾屬性的約定棚赔,從而為任何布爾字段foo生成一個(gè)isFoo getter方法名,而不是getFoo徘郭。

需要注意的是靠益,如果帶注解字段所屬的類包含與要生成的getter或setter同名的方法,無(wú)論參數(shù)或返回類型如何残揉,都不會(huì)生成相應(yīng)的方法胧后。

@Getter@Setter注解都采用一個(gè)可選參數(shù)來(lái)指定生成方法的訪問(wèn)級(jí)別。

Lombok注解代碼:

@Getter @Setter private boolean employed = true;
@Setter(AccessLevel.PROTECTED) private String name;

等效的Java源代碼:

private boolean employed = true;
private String name;

public boolean isEmployed() {
    return employed;
}

public void setEmployed(final boolean employed) {
    this.employed = employed;
}

protected void setName(final String name) {
    this.name = name;
}

@NonNull

@NonNull注釋用于指示對(duì)對(duì)應(yīng)成員進(jìn)行快速失敗null檢查的需要抱环。當(dāng)放置在Lombok正在為其生成setter方法的字段上時(shí)壳快,將生成null檢查纸巷,如果提供了null值,將導(dǎo)致NullPointerException眶痰。此外瘤旨,如果Lombok正在為擁有的類生成構(gòu)造函數(shù),那么字段將被添加到構(gòu)造函數(shù)簽名中竖伯,null檢查將包含在生成的構(gòu)造函數(shù)代碼中存哲。

IntelliJ IDEA和FindBugs等中的 注解鏡像@NotNull@NonNull注解。對(duì)于主題的這些變化七婴,Lombok是注解不可知的祟偷。如果Lombok遇到任何使用該名稱的注解注解的成員,@NotNull或者@NonNull它將通過(guò)生成適當(dāng)?shù)南鄳?yīng)代碼來(lái)遵守它打厘。Project Lombok的作者進(jìn)一步評(píng)論說(shuō)修肠,如果將此類型的注解添加到Java,則Lombok版本將被刪除婚惫。

Family的Lombok注解代碼:

@Getter @Setter @NonNull
private List<Person> members;

等價(jià)Java源代碼::

@NonNull
private List<Person> members;

public Family(@NonNull final List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
}
    
@NonNull
public List<Person> getMembers() {
    return members;
}

public void setMembers(@NonNull final List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
}

@ToString

此注釋生成toString方法的實(shí)現(xiàn)氛赐。默認(rèn)情況下,任何非靜態(tài)字段都將以名稱-值對(duì)的形式包含在方法的輸出中先舷。如果需要艰管,可以通過(guò)將注釋參數(shù)includeFieldNames設(shè)置為false來(lái)排除在輸出中包含屬性名。

通過(guò)在exclude 參數(shù)中包含其字段名稱蒋川,可以從生成的方法的輸出中排除特定字段牲芋。或者捺球,該of參數(shù)可用于僅列出輸出中所需的那些字段缸浦。toString通過(guò)將callSuper參數(shù) 設(shè)置為,還可以包括超類方法的輸出true氮兵。

Lombok 注解代碼:

@ToString(callSuper=true,exclude="someExcludedField")
public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
}

等價(jià)Java源代碼:

public class Foo extends Bar {
    private boolean someBoolean = true;
    private String someStringField;
    private float someExcludedField;
    
    @java.lang.Override
    public java.lang.String toString() {
        return "Foo(super=" + super.toString() +
            ", someBoolean=" + someBoolean +
            ", someStringField=" + someStringField + ")";
    }
}

@EqualsAndHashCode

這個(gè)類級(jí)注解將導(dǎo)致Lombok生成兩者 equalshashCode方法裂逐,因?yàn)檫@兩者是由hashCode契約本質(zhì)上綁定在一起的。默認(rèn)情況下泣栈,兩個(gè)方法都將考慮類中非靜態(tài)或瞬態(tài)的任何字段卜高。很像@ToStringexclude提供參數(shù)是為了防止字段包含在生成的邏輯中南片。也可以使用該 of參數(shù)僅列出應(yīng)考慮的那些字段掺涛。

同樣@ToStringcallSuper 這個(gè)注解有一個(gè)參數(shù)疼进。將其設(shè)置為true將導(dǎo)致 在考慮當(dāng)前類中的字段之前equals通過(guò)調(diào)用equals超類來(lái)驗(yàn)證相等性薪缆。對(duì)于該hashCode方法,它導(dǎo)致在hashCode計(jì)算散列時(shí)結(jié)合超類的結(jié)果伞广。設(shè)置callSuper為true時(shí)拣帽,請(qǐng)注意確保父類中的equals方法正確處理實(shí)例類型檢查疼电。如果父類檢查該類是否屬于特定類型而不僅僅是兩個(gè)對(duì)象的類相同,則可能導(dǎo)致不希望的結(jié)果减拭。如果超類使用生成的Lombok equals方法澜沟,這不是問(wèn)題。但是峡谊,其他實(shí)現(xiàn)可能無(wú)法正確處理此情況。另請(qǐng)注意刊苍,callSuper當(dāng)類僅擴(kuò)展時(shí)Object既们,無(wú)法設(shè)置 為true ,因?yàn)檫@會(huì)導(dǎo)致實(shí)例相等性檢查使字段比較短路正什。這是由于生成的方法調(diào)用了equals實(shí)現(xiàn) Object啥纸,如果被比較的兩個(gè)實(shí)例不是同一個(gè)實(shí)例,則返回false婴氮。因此斯棒,在這種情況下,Lombok將生成編譯時(shí)錯(cuò)誤主经。

Lombok 注解代碼:

@EqualsAndHashCode(callSuper=true,exclude={"address","city","state","zip"})
public class Person extends SentientBeing {
    enum Gender { Male, Female }

    @NonNull private String name;
    @NonNull private Gender gender;
    
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
}

等價(jià)Java源代碼::

public class Person extends SentientBeing {
    
    enum Gender {
        /*public static final*/ Male /* = new Gender() */,
        /*public static final*/ Female /* = new Gender() */;
    }
    @NonNull
    private String name;
    @NonNull
    private Gender gender;
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
    
    @java.lang.Override
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        if (!super.equals(o)) return false;
        final Person other = (Person)o;
        if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
        if (this.gender == null ? other.gender != null : !this.gender.equals(other.gender)) return false;
        if (this.ssn == null ? other.ssn != null : !this.ssn.equals(other.ssn)) return false;
        return true;
    }
    
    @java.lang.Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + super.hashCode();
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.gender == null ? 0 : this.gender.hashCode());
        result = result * PRIME + (this.ssn == null ? 0 : this.ssn.hashCode());
        return result;
    }
}

@Data

@Data注解很可能在項(xiàng)目lombok工具箱中最常用的注解荣暮。它結(jié)合的功能@ToString@EqualsAndHashCode罩驻,@Getter@Setter穗酥。本質(zhì)上,使用 @Data的一類是一樣的帶有默認(rèn)注解類@ToString@EqualsAndHashCode 以及與兩個(gè)注解每個(gè)字段@Getter 和@Setter惠遏。對(duì)類進(jìn)行注解@Data 也會(huì)觸發(fā)Lombok的構(gòu)造函數(shù)生成砾跃。這會(huì)添加一個(gè)公共構(gòu)造函數(shù),它將任何@NonNullfinal 字段作為參數(shù)节吮。這提供了普通舊Java對(duì)象(PO??JO)所需的一切抽高。

雖然@Data非常有用,但它不提供與其他Lombok注解相同的控制粒度透绩。要覆蓋默認(rèn)方法生成行為翘骂,請(qǐng)使用其他Lombok注解之一注解類,字段或方法渺贤,并指定必要的參數(shù)值以實(shí)現(xiàn)所需的效果雏胃。

@Data確實(shí)提供了一個(gè)可用于生成靜態(tài)工廠方法的參數(shù)選項(xiàng)。將staticConstructor參數(shù)的值設(shè)置為 所需的方法名稱將導(dǎo)致Lombok將生成的構(gòu)造函數(shù)設(shè)置為private志鞍,并公開給定名稱的靜態(tài)工廠方法瞭亮。

Lombok 注解代碼:

@Data(staticConstructor="of")
public class Company {
    private final Person founder;
    private String name;
    private List<Person> employees;
}

等價(jià)Java源代碼:

public class Company {
    private final Person founder;
    private String name;
    private List<Person> employees;
    
    private Company(final Person founder) {
        this.founder = founder;
    }
    
    public static Company of(final Person founder) {
        return new Company(founder);
    }
    
    public Person getFounder() {
        return founder;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(final String name) {
        this.name = name;
    }
    
    public List<Person> getEmployees() {
        return employees;
    }
    
    public void setEmployees(final List<Person> employees) {
        this.employees = employees;
    }
    
    @java.lang.Override
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        final Company other = (Company)o;
        if (this.founder == null ? other.founder != null : !this.founder.equals(other.founder)) return false;
        if (this.name == null ? other.name != null : !this.name.equals(other.name)) return false;
        if (this.employees == null ? other.employees != null : !this.employees.equals(other.employees)) return false;
        return true;
    }
    
    @java.lang.Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;
        result = result * PRIME + (this.founder == null ? 0 : this.founder.hashCode());
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.employees == null ? 0 : this.employees.hashCode());
        return result;
    }
    
    @java.lang.Override
    public java.lang.String toString() {
        return "Company(founder=" + founder + ", name=" + name + ", employees=" + employees + ")";
    }
}

@Cleanup

@Cleanup注解可以用來(lái)保證分配的資源被釋放。當(dāng)使用帶注解的局部變量時(shí)@Cleanup固棚,任何后續(xù)代碼都包含在一個(gè) try/finally塊中统翩,該塊保證在當(dāng)前作用域的末尾調(diào)用cleanup方法仙蚜。默認(rèn)情況下,@Cleanup 假設(shè)清理方法命名為“close”厂汗,與輸入和輸出流一樣委粉。但是,可以為注解的value參數(shù)提供不同的方法名稱娶桦。只有不帶參數(shù)的清理方法才能與此注解一起使用贾节。

使用@Cleanup注解時(shí)還需要注意一點(diǎn)。如果清理方法拋出異常衷畦,它將搶占方法體中引發(fā)的任何異常栗涂。這可能導(dǎo)致問(wèn)題的實(shí)際原因被掩蓋,并且在選擇使用Project Lombok的資源管理時(shí)應(yīng)該考慮到這一點(diǎn)祈争。此外斤程,隨著Java 7中的自動(dòng)資源管理,這個(gè)特定的注解可能相對(duì)短暫菩混。

Lombok注解代碼:

public void testCleanUp() {
    try {
        @Cleanup ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(new byte[] {'Y','e','s'});
        System.out.println(baos.toString());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

等價(jià)Java源代碼:

public void testCleanUp() {
    try {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            baos.write(new byte[]{'Y', 'e', 's'});
            System.out.println(baos.toString());
        } finally {
            baos.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Synchronized

在一個(gè)方法上使用synchronized關(guān)鍵字可能會(huì)導(dǎo)致不好的結(jié)果忿墅,任何一個(gè)開發(fā)多線程軟件的開發(fā)人員都可以證明這一點(diǎn)。synchronized關(guān)鍵字在實(shí)例方法或靜態(tài)方法的類對(duì)象中會(huì)鎖定當(dāng)前對(duì)象沮峡。這意味著開發(fā)人員控制之外的代碼有可能鎖定同一個(gè)對(duì)象疚脐,從而導(dǎo)致死鎖。通常建議在單獨(dú)的對(duì)象上顯式鎖定邢疙,該對(duì)象專門用于此目的亮曹,而不是以允許非請(qǐng)求鎖定的方式公開。Project Lombok正是為此目的提供了@Synchronized注解秘症。

@Synchronized注解一個(gè)實(shí)例方法將提示Lombok生成一個(gè)名為lock的私有鎖定字段照卦,該方法將在執(zhí)行之前鎖定該字段。類似地乡摹,以相同的方式注解靜態(tài)方法將為靜態(tài)方法生成一個(gè)名為`LOCK`的私有靜態(tài)對(duì)象役耕,以便以相同的方式使用〈狭可以通過(guò)為注解的值參數(shù)提供字段名來(lái)指定不同的鎖定對(duì)象瞬痘。當(dāng)提供字段名時(shí),開發(fā)人員必須定義該屬性板熊,因?yàn)長(zhǎng)ombok不會(huì)生成它框全。

Lombok注解代碼:

private final java.lang.Object $ lock = new java.lang.Object [0];
private DateFormat format = new SimpleDateFormat(“MM-dd-YYYY”);

public String synchronizedFormat(Date date){
    synchronized($ lock){
        return format.format(date);
    }
}

@SneakyThrows

@SneakyThrows可能是具有最多批評(píng)者的項(xiàng)目lombok注解,因?yàn)樗菍?duì)已檢查異常的直接攻擊干签。關(guān)于使用已檢查異常的問(wèn)題存在很多分歧津辩,大量開發(fā)人員認(rèn)為這是一個(gè)失敗的實(shí)驗(yàn)。這些開發(fā)人員會(huì)喜歡@SneakyThrows。在已檢查/未檢查的異常欄的另一側(cè)的那些開發(fā)人員很可能將此視為隱藏潛在問(wèn)題喘沿。

IllegalAccessException如果IllegalAccessException或某些父類未在throws子句中列出闸度,則 拋出通常會(huì)生成“未處理的異常”錯(cuò)誤:

Screenshot of Eclipse generating an error message regarding unhandled exceptions.

當(dāng)用@ sneakythrow注解時(shí)蚜印,錯(cuò)誤就消失了.

Screenshot of a method annotated with @SneakyThrows and generating no error in Eclipse.

默認(rèn)情況下莺禁,@SneakyThrows將允許拋出任何已檢查的異常而不在 throws子句中聲明。通過(guò)向注解Class<? extends Throwable>value參數(shù)提供一個(gè)throwable classes()數(shù)組窄赋,可以將其限制為一組特定的異常 .

Lombok 注解代碼:

@SneakyThrows
public void testSneakyThrows() {
    throw new IllegalAccessException();
}

等價(jià)Java源代碼:

public void testSneakyThrows() {
    try {
        throw new IllegalAccessException();
    } catch (java.lang.Throwable $ex) {
        throw lombok.Lombok.sneakyThrow($ex);
    }
}

看一下上面的代碼和簽名 Lombok.sneakyThrow(Throwable)會(huì)讓大多數(shù)人認(rèn)為異常被包裝在一個(gè)RuntimeException 并重新拋出哟冬,但事實(shí)并非如此。該sneakyThrow 方法永遠(yuǎn)不會(huì)正常返回忆绰,而是將提供的throwable完全保持不變柒傻。

成本和收益

與任何技術(shù)選擇一樣,使用Project Lombok也會(huì)產(chǎn)生正面和負(fù)面影響较木。將Lombok的注解合并到項(xiàng)目中可以大大減少在IDE中生成或手工編寫的樣板代碼行數(shù)。這樣可以減少維護(hù)開銷青柄,減少錯(cuò)誤并提高可讀性伐债。

這并不是說(shuō)在項(xiàng)目中使用Project Lombok注解沒(méi)有缺點(diǎn)。Lombok項(xiàng)目主要旨在填補(bǔ)Java語(yǔ)言的空白致开。因此峰锁,可能會(huì)發(fā)生對(duì)語(yǔ)言的更改,從而妨礙使用Lombok的注解双戳,例如添加第一類屬性支持虹蒋。此外,當(dāng)與基于注解的對(duì)象關(guān)系映射(ORM)框架結(jié)合使用時(shí)飒货,數(shù)據(jù)類上的注解數(shù)量可能開始變得難以處理魄衅。這在很大程度上被Lombok注解取代的代碼量所抵消。但是塘辅,那些避免經(jīng)常使用注解的人可能會(huì)選擇另一種方式晃虫。

缺什么?

Project Lombok提供了delombok用等效源代碼替換Lombok注解的實(shí)用程序】鄱眨可以通過(guò)命令行對(duì)整個(gè)源目錄執(zhí)行此操作

java -jar lombok.jar delombok src -d src-delomboked

或者哲银,提供Ant任務(wù)以結(jié)合到構(gòu)建過(guò)程中。

<target name="delombok">
    <taskdef classname="lombok.delombok.ant.DelombokTask"
        classpath="WebRoot/WEB-INF/lib/lombok.jar" name="delombok" />
    <mkdir dir="src-delomboked" />
    <delombok verbose="true" encoding="UTF-8" to="src-delomboked"
        from="src" />
</target>

兩者delombok和相應(yīng)的Ant任務(wù)都打包在核心lombok.jar下載中呻惕。除了允許Lombok注解在使用Google Web Toolkit(GWT)或其他不兼容的框架構(gòu)建的應(yīng)用程序中有用之外荆责,delombok在Person類上運(yùn)行 還可以輕松地將使用Lombok注解編寫的類與包含等效樣板內(nèi)聯(lián)的代碼進(jìn)行對(duì)比。

package com.ociweb.jnb.lombok;

import java.util.Date;

import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NonNull;

@Data
@EqualsAndHashCode(exclude={"address","city","state","zip"})
public class Person {
    enum Gender { Male, Female }

    @NonNull private String firstName;
    @NonNull private String lastName;
    @NonNull private final Gender gender;
    @NonNull private final Date dateOfBirth;
    
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
}

使用Project Lombok注解的代碼比包含樣板的等效類更簡(jiǎn)潔亚脆。

package com.ociweb.jnb.lombok;

import java.util.Date;
import lombok.NonNull;

public class Person {
    
    enum Gender {
        /*public static final*/ Male /* = new Gender() */,
        /*public static final*/ Female /* = new Gender() */;
    }
    @NonNull
    private String firstName;
    @NonNull
    private String lastName;
    @NonNull
    private final Gender gender;
    @NonNull
    private final Date dateOfBirth;
    private String ssn;
    private String address;
    private String city;
    private String state;
    private String zip;
    
    public Person(@NonNull final String firstName, @NonNull final String lastName,
            @NonNull final Gender gender, @NonNull final Date dateOfBirth) {
        if (firstName == null)
            throw new java.lang.NullPointerException("firstName");
        if (lastName == null)
            throw new java.lang.NullPointerException("lastName");
        if (gender == null)
            throw new java.lang.NullPointerException("gender");
        if (dateOfBirth == null)
            throw new java.lang.NullPointerException("dateOfBirth");
        this.firstName = firstName;
        this.lastName = lastName;
        this.gender = gender;
        this.dateOfBirth = dateOfBirth;
    }
    
    @NonNull
    public String getFirstName() {
        return firstName;
    }
    
    public void setFirstName(@NonNull final String firstName) {
        if (firstName == null)
            throw new java.lang.NullPointerException("firstName");
        this.firstName = firstName;
    }
    
    @NonNull
    public String getLastName() {
        return lastName;
    }
    
    public void setLastName(@NonNull final String lastName) {
        if (lastName == null)
            throw new java.lang.NullPointerException("lastName");
        this.lastName = lastName;
    }
    
    @NonNull
    public Gender getGender() {
        return gender;
    }
    
    @NonNull
    public Date getDateOfBirth() {
        return dateOfBirth;
    }
    
    public String getSsn() {
        return ssn;
    }
    
    public void setSsn(final String ssn) {
        this.ssn = ssn;
    }
    
    public String getAddress() {
        return address;
    }
    
    public void setAddress(final String address) {
        this.address = address
   }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末做院,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌山憨,老刑警劉巖查乒,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異郁竟,居然都是意外死亡玛迄,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門棚亩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蓖议,“玉大人,你說(shuō)我怎么就攤上這事讥蟆±障海” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵瘸彤,是天一觀的道長(zhǎng)修然。 經(jīng)常有香客問(wèn)我,道長(zhǎng)质况,這世上最難降的妖魔是什么愕宋? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮结榄,結(jié)果婚禮上中贝,老公的妹妹穿的比我還像新娘。我一直安慰自己臼朗,他們只是感情好邻寿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著视哑,像睡著了一般绣否。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上挡毅,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天枝秤,我揣著相機(jī)與錄音,去河邊找鬼慷嗜。 笑死淀弹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的庆械。 我是一名探鬼主播薇溃,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼缭乘!你這毒婦竟也來(lái)了沐序?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎策幼,沒(méi)想到半個(gè)月后邑时,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡特姐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年晶丘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唐含。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浅浮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捷枯,到底是詐尸還是另有隱情滚秩,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布淮捆,位于F島的核電站郁油,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏攀痊。R本人自食惡果不足惜桐腌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蚕苇。 院中可真熱鬧,春花似錦凿叠、人聲如沸涩笤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蹬碧。三九已至,卻和暖如春炒刁,著一層夾襖步出監(jiān)牢的瞬間恩沽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工翔始, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罗心,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓城瞎,卻偏偏與公主長(zhǎng)得像渤闷,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子脖镀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354