lambda表達(dá)式

導(dǎo)圖

這里寫圖片描述

文章最后有源碼

簡介

學(xué)習(xí)lambda表達(dá)式就要先知道函數(shù)式接口是什么鹿鳖?


函數(shù)式接口(Functional Interfaces):如果一個接口定義個唯一一個抽象方法呛讲,那么這個接口就成為函數(shù)式接口。同時(shí),引入了一個新的注解:@FunctionalInterface∩介希可以把他它放在一個接口前,表示這個接口是一個函數(shù)式接口舍悯。這個注解是非必須的航棱,只要接口只包含一個方法的接口睡雇,虛擬機(jī)會自動判斷,不過最好在接口上使用注解 @FunctionalInterface 進(jìn)行聲明饮醇。在接口中添加了 @FunctionalInterface 的接口它抱,只允許有一個抽象方法,否則編譯器也會報(bào)錯朴艰。


示例:

 /**
  * 函數(shù)式接口
  */
    @FunctionalInterface
    interface Sum{
        int add(int value);
    }

Lambda表達(dá)式:可以讓你的代碼更加的簡潔观蓄。ambda無法單獨(dú)出現(xiàn),需要一個函數(shù)式接口來盛放呵晚,可以說lambda表達(dá)式方法體是函數(shù)式接口的實(shí)現(xiàn)蜘腌,lambda實(shí)例化函數(shù)式接口沫屡,可以將函數(shù)作為方法參數(shù)饵隙,或者將代碼作為數(shù)據(jù)對待。


主要優(yōu)點(diǎn):

1.代碼變得更加簡潔緊湊
2.可讀性強(qiáng)沮脖,
3.并行操作大集合變得很方便金矛,可以充分發(fā)揮多核cpu的優(yōu)勢,更加便于多核處理器編寫代碼等勺届,

語法

Lambda語法
(parameters)->expression 或者 (parameters)->{statements;}
Lambda表達(dá)式由三部分組成:
1.parameters:類似方法中的形參列表驶俊,這里的參數(shù)是函數(shù)式接口里的參數(shù)。這里的參數(shù)類型可以明確的聲明也可不聲明而由JVM隱含的推斷免姿,當(dāng)只有一個推斷類型時(shí)可以省略掉圓括號饼酿。
2.-> :可以理解為“被用于”的意思
3.方法體:可以是表達(dá)式也可以是代碼塊,實(shí)現(xiàn)函數(shù)式接口中的方法胚膊。這個方法體可以有返回值也可以沒有返回值

示例:

1.不接受參數(shù)故俐,直接返回1
    ()->1
2.接受兩個int類型的參數(shù),返回這兩個參數(shù)的和
    (int x,int y )-> x+y
3.接受x,y兩個參數(shù)紊婉,JVM根據(jù)上下文推斷參數(shù)的類型药版,返回兩個參數(shù)的和
    (x,y)->x+y
4.接受一個字符串,打印該字符串喻犁,沒有返回值
    (String name)->System.out.println(name)
5.接受一個參數(shù)槽片,JVM根據(jù)上下文推斷參數(shù)的類型,打印該參數(shù)肢础,沒有返回值,只有一個參數(shù)可以省略圓括號
   name->System.out.prinln(name)
6.接受兩個String類型參數(shù)还栓,分別輸出,沒有返回值
    (String name,String sex)->{System.out.println(name);System.out.println(sex)}
7.接受呀一個參數(shù)传轰,返回它本身的2倍
    x->2*x
傳統(tǒng)寫法與Lambda寫法的比較

首先定義一個函數(shù)式接口

/**
 * 函數(shù)式接口
 * @param <A>
 * @param <B>
 */
@FunctionalInterface
interface Transform<A,B>{
    B transform(A a);
}

兩種寫法的對比

 //傳統(tǒng)方式使用接口
    Transform<String ,Integer> transform1 = new Transform<String, Integer>() {
        @Override
        public Integer transform(String s) {
            return Integer.valueOf(s);
        }
    } ;

    //Lambda方式使用接口,就是這么簡單粗暴剩盒,沒脾氣
    Transform<String,Integer> transform2 = (s)-> Integer.valueOf(s);

訪問權(quán)限

在Lambda表達(dá)式使用中,Lambda表達(dá)式外面的局部變量會被JVM隱式的編譯成final類型路召,Lambda表達(dá)式內(nèi)部只能訪問勃刨,不能修改
Lambda表達(dá)式內(nèi)部對靜態(tài)變量和成員變量是可讀可寫的
Lambda不能訪問函數(shù)接口的默認(rèn)方法波材,在函數(shù)接口中可以添加default關(guān)鍵字定義默認(rèn)的方法

局部變量示例:

 public static void main(String[] args) {
        int num = 6;//局部變量
        Sum sum = value -> {
//            num = 8; 這里會編譯出錯
            return num + value;
        };
        sum.add(8);
    }

    /**
     * 函數(shù)式接口
     */
    @FunctionalInterface
    interface Sum{
        int add(int value);
    }

靜態(tài)變量和成員變量示例:

 public int num1 = 6;
    public static int num2 = 8;
    private int getSum(){
        Sum sum = value -> {
            num1 = 10;
            num2 = 10;
            return  num1 + num2;
        };
        return sum.add(1);
    }

    /**
     * 函數(shù)式接口
     */
    @FunctionalInterface
    interface Sum{
        int add(int value);
    }

方法引用

在lambda表達(dá)式中,方法引用是一種簡化寫法身隐,引用的方法就是Lambda表達(dá)式的方法體的實(shí)現(xiàn)
語法結(jié)構(gòu):ObjectRef:: methodName
左邊是類名或者實(shí)例名廷区,中間的“::”是方法引用符號,右邊是相應(yīng)的方法名
方法引用一般分為三類:
靜態(tài)方法引用贾铝,實(shí)例方法引用隙轻,構(gòu)造方法引用

靜態(tài)方法引用示例:

public static void main(String[] args){
        //傳統(tǒng)方式
        Transform<String ,Integer> transform1 = new Transform<String, Integer>() {
            @Override
            public Integer transform(String s) {
                return C_方法引用之靜態(tài)方法引用.strToInt(s);
            }
        };
        int result1 = transform1.transform("100");

        //Lambda方式
        Transform<String,Integer> transform2 = C_方法引用之靜態(tài)方法引用 ::strToInt;
        int result2 = transform2.transform("200");
    }

    static int strToInt(String str){
        return Integer.valueOf(str);
    }

    /**
     * 函數(shù)式接口
     * @param <A>
     * @param <B>
     */
    @FunctionalInterface
    interface Transform<A,B>{
        B transform(A a);
    }

實(shí)例方法引用示例:

public static void main(String[] args){
        //傳統(tǒng)方式
        Transform<String ,Integer> transform1 = new Transform<String, Integer>() {
            @Override
            public Integer transform(String s) {
                return new Obj().strToInt(s);
            }
        };
        int result1 = transform1.transform("100");
        //Lambda方式
        Obj obj = new Obj();
        Transform<String,Integer> transform2 = obj::strToInt;
        int result2 = transform2.transform("200");
    }
    /**
     * 函數(shù)式接口
     * @param <A>
     * @param <B>
     */
    interface Transform<A,B>{
        B transform(A a);
    }
    /**
     * 實(shí)例對象類
     */
    static class Obj{
        public int strToInt(String str){
            return Integer.valueOf(str);
        }
    }

構(gòu)造方法引用示例:

 //傳統(tǒng)方式
        Factory factory1 = new Factory() {
            @Override
            public Parent create(String name, int age) {
                return new Boy(name,age);
            }
        };
        Boy boy = (Boy) factory1.create("小明",18);
        factory1 = new Factory() {
            @Override
            public Parent create(String name, int age) {
                return new Girl(name,age);
            }
        };
        Girl girl = (Girl) factory1.create("小紅",18);
        //Lambda方式
        Factory<Boy> boyFactory = Boy::new;
        Boy boy1 = boyFactory.create("小明",18);
        Factory<Girl> girlFactory = Girl::new;
        Girl girl1 = girlFactory.create("小紅",18);

其他類和接口:

//工廠類接口
public interface Factory<T extends Parent> {
    T create(String name,int age);
}

//父類
public class Parent {
    private String name ;
    private int age;
    public Parent(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void doSome(){

    }
}
//男孩類
public class Boy extends Parent {
    public Boy(String name, int age) {
        super(name, age);
    }

    @Override
    public void doSome() {
        System.out.println("我是個男孩");
    }
}
//女孩類
public class Girl extends Parent {
    public Girl(String name, int age) {
        super(name, age);
    }

    @Override
    public void doSome() {
        System.out.println("我是個女孩");
    }
}

四個常用的接口

Predicate接口
/**
 * Predicate接口:輸入一個參數(shù),返回一個boolean值垢揩,內(nèi)置了許多用于邏輯判斷的默認(rèn)方法
 */
public class F_實(shí)踐之Predicate {
    public void predicateTest(){
        Predicate<String> predicateStr = s -> s.length()>8;
        boolean testResult = predicateStr.test("test");//需要api 24
        testResult = predicateStr.negate().test("test");//取反玖绿,也就是s.length<=8

        Predicate<Object> predicateObj = Objects::nonNull;
        Object obj = null;
        testResult = predicateObj.test(obj);//判斷是否為空
    }
}
Consumer接口
/**
 * consumer接口:對輸入的參數(shù)進(jìn)行操作。有輸入沒輸出
 */
  private static void consumerTest(){
        Consumer<Integer> add5 = (p) -> {
            System.out.println("old value:" + p);
            p = p + 5;
            System.out.println("new value:" + p);
        };
        add5.accept(10);
    }
Function接口
/**
 * Function接口:接受一個參數(shù)叁巨,返回單一的結(jié)果斑匪。默認(rèn)的方法(andThen)可將多個函數(shù)串在一起,形成復(fù)合Funtion(有輸入锋勺,有輸出)結(jié)果
 */
  public static void functionTest(){
        Function<String, Integer> toInteger = Integer::valueOf;
        //toInteger的執(zhí)行結(jié)果作為第二個backToString的輸入
        Function<String, String> backToString = toInteger.andThen(String::valueOf);
        String result = backToString.apply("1234");
        System.out.println(result);

        Function<Integer, Integer> add = (i) -> {
            System.out.println("frist input:" + i);
            return i * 2;
        };
        Function<Integer, Integer> zero = add.andThen((i) -> {
            System.out.println("second input:" + i);
            return i * 0;
        });

        Integer res = zero.apply(8);
        System.out.println(res);
    }
Supplier接口
/**
 * Supplier接口:返回一個給定類型的結(jié)果蚀瘸。不需要輸入?yún)?shù),無輸入有輸出
 */
   private static void supplierTest(){
        Supplier<String> supplier = () -> "我就是輸出";
        String s = supplier.get();
        System.out.println(s);
    }

串行stream操作

Lambda為java8帶來了閉包庶橱,支持對集合對象的stream進(jìn)行函數(shù)式操作贮勃, stream api被集成進(jìn)了collection api ,允許對集合對象進(jìn)行批量操作苏章。
Stream表示數(shù)據(jù)流寂嘉,它沒有數(shù)據(jù)結(jié)構(gòu),本身也不存儲元素枫绅,其操作也不會改變源Stream泉孩,而是生成新Stream.作為一種操作數(shù)據(jù)的接口,它提供了過濾撑瞧、排序棵譬、映射、規(guī)約等多種操作方法预伺,
這些方法按照返回類型被分為兩類:凡是返回Stream類型的方法订咸,稱之為中間方法(中間操作),其余的都是完結(jié)方法(完結(jié)操作)酬诀。完結(jié)方法返回一個某種類型的值脏嚷,而中間方法則返回新的Stream。
中間方法的調(diào)用通常是鏈?zhǔn)降穆饔撨^程會形成一個管道父叙,當(dāng)完結(jié)方法被調(diào)用時(shí)會導(dǎo)致立即從管道中消費(fèi)值,這里我們要記住:Stream的操作盡可能以“延遲”的方式運(yùn)行趾唱,也就是我們常說的“懶操作”涌乳,
這樣有助于減少資源占用,提高性能甜癞。對于所有的中間操作(除sorted外)都是運(yùn)行在延遲模式下夕晓。

Stream不但提供了強(qiáng)大的數(shù)據(jù)操作能力,更重要的是Stream既支持串行也支持并行悠咱,并行使得Stream在多核處理器上有著更好的性能蒸辆。

Stream的使用過程有著固定的模式:

1.創(chuàng)建Stream
2.通過中間操作,對原始Stream進(jìn)行“變化”并生成新的Stream
3.使用完結(jié)操作析既,生成最終結(jié)果

 //創(chuàng)建一個集合
        List<String> list = new ArrayList<>();
        list.add("a1");list.add("a2");list.add("a3");list.add("b1");list.add("b2");list.add("b3");

中間操作方法

過濾(filter)

結(jié)合Predicate接口躬贡,F(xiàn)ilter對流對象中的所有元素進(jìn)行過濾,該操作是一個中間操作,這意味著你可以在操作返回結(jié)果的基礎(chǔ)上進(jìn)行其他操作

 public static void sreamFilterTest(List<String> lists){ //要明確這list的泛型類型眼坏,否則jvm不能根據(jù)上下文確定參數(shù)類型
        lists.stream().filter((s -> s.startsWith("a"))).forEach(System.out::println);//將開頭是a的過濾出來

        //等價(jià)于以上操作
        Predicate<String> predicate = (s) -> s.startsWith("a");//將開頭是a的過濾出來
        lists.stream().filter(predicate).forEach(System.out::println);

        //連續(xù)過濾
        Predicate<String> predicate1 = (s -> s.endsWith("1"));//將開頭是a拂玻,并且結(jié)尾是1的過濾出來
        lists.stream().filter(predicate).filter(predicate1).forEach(System.out::println);
    }
排序(sorted)

結(jié)合Comparator,該操作返回一個排序過后的流的視圖,原始流的順序不會改變空骚。通過Comparator來指定排序規(guī)則纺讲,默認(rèn)是自然排序

 private static void streamSortedTest(List<String> list){
        //默認(rèn)排序
        list.stream().filter(s -> s.startsWith("a")).forEach(System.out::println);
        System.out.println("- - - - - - - - -");
        //自定義排序
        list.stream().sorted(((s, t1) -> t1.compareTo(s))).filter(s -> s.startsWith("a")).forEach(System.out::println);
    }
映射(map)

結(jié)合Function接口,該操作能將流對象中的每一個元素映射為另一個元素囤屹,實(shí)現(xiàn)元素類型的轉(zhuǎn)換。

 private static void streamMapTest(List<String> list){
        list.stream().map(String::toUpperCase).sorted((s, t1) -> t1.compareTo(s)).forEach(System.out::println);
        System.out.println("- - - - - - ");
        //自定義映射規(guī)則
        Function<String,String> function = s -> {return  s + ".map3";};
        list.stream().map(function).forEach(System.out::println);
    }

完結(jié)操作方法

匹配(match)

用來判斷某個predicate是否和流對象相匹配逢渔,最終返回boolean類型的結(jié)果

 private static void streamMatchTest(List<String> list){
        //流對象中只要有一個元素匹配就返回true
        boolean anyStartWithA = list.stream().anyMatch(s -> s.startsWith("a"));
        System.out.println("集合中是否有以'a'來頭:"+ anyStartWithA);
        //流對象中每一個元素都匹配才返回true
        boolean allStartWithA = list.stream().allMatch(s -> s.startsWith("a"));
        System.out.println("集合中每一個都是以'a'開頭:"+ allStartWithA);
        //流對象中沒有匹配時(shí)返回true
        boolean noneStartWithA = list.stream().noneMatch(s -> s.startsWith("c"));
        System.out.println("集合中沒有以'c'開頭:"+ noneStartWithA);
    }
收集(collect)

在對經(jīng)過變換后肋坚,將變換的stream元素收集,比如將這些元素存在集合中肃廓,可以使用stream提供的collect方法

 private static void streamCollectTest(List<String> list){
        List<String> listNew = list.stream().filter(s -> s.startsWith("b")).sorted().collect(Collectors.toList());
        System.out.println(listNew );
    }
規(guī)約(reduce)

允許我們用自己的方式計(jì)算元素或者將一個stream中元素以某種規(guī)律關(guān)聯(lián)

private static void streamReduceTest(List<String> list){
        Optional<String> optional = list.stream().sorted().reduce((s, s2) -> {
            System.out.println(s+"-"+s2);
            return s+"-"+s2;
        });
    }
計(jì)數(shù)(count)

用來統(tǒng)計(jì)流中元素的總數(shù)

private static void streamCountTest(List<String> list){
        long count = list.stream().filter(s -> s.startsWith("b")).count();
        System.out.println("以'b'開頭的數(shù)量:"+ count);
    }

并行操作stream

并行Stream:基于Fork-join并行分解框架實(shí)現(xiàn)智厌,將大數(shù)據(jù)集合切分為多個小數(shù)據(jù)結(jié)合交給不同的線程去處理,這樣在多核處理情況下盲赊,性能會得到很大的提高铣鹏。
這和MapReduce的設(shè)計(jì)理念一致:大任務(wù)化小,小任務(wù)再分配到不同的機(jī)器執(zhí)行哀蘑。只不過這里的小任務(wù)是交給不同的處理器诚卸。
結(jié)果是性能提高50%,單核下還是串行流性能比較好绘迁,并行流的使用場景是多核+大數(shù)據(jù)

 //創(chuàng)建一個大集合
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 10000000; i++) {
            UUID uuid = UUID.randomUUID();
            list.add(uuid.toString());
        }
 //并行stream
    private static void parallelStreamSortedTest(List<String> list){
        long startTime = System.nanoTime();//返回最準(zhǔn)確的可用系統(tǒng)計(jì)時(shí)器的當(dāng)前值合溺,以毫微秒為單位。
        long count = list.parallelStream().sorted().count();
        long endTime = System.nanoTime();
        long millis = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
        System.out.printf("并行排序花費(fèi)時(shí)間:%d ms",millis);
    }
    //串行stream
    private static void streamSortedTest(List<String> list){
        long startTime = System.nanoTime();//返回最準(zhǔn)確的可用系統(tǒng)計(jì)時(shí)器的當(dāng)前值缀台,以毫微秒為單位棠赛。
        long count = list.stream().sorted().count();
        long endTime = System.nanoTime();
        long millis = TimeUnit.NANOSECONDS.toMillis(endTime - startTime);
        System.out.printf("串行排序花費(fèi)時(shí)間:%d ms",millis);
    }

運(yùn)行結(jié)果:

并行排序花費(fèi)時(shí)間:4362 ms
串行排序花費(fèi)時(shí)間:9847 ms
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子睛约,更是在濱河造成了極大的恐慌鼎俘,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辩涝,死亡現(xiàn)場離奇詭異而芥,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)膀值,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進(jìn)店門棍丐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沧踏,你說我怎么就攤上這事歌逢。” “怎么了翘狱?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵秘案,是天一觀的道長。 經(jīng)常有香客問我潦匈,道長阱高,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任茬缩,我火速辦了婚禮赤惊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凰锡。我一直安慰自己未舟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布掂为。 她就那樣靜靜地躺著裕膀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勇哗。 梳的紋絲不亂的頭發(fā)上昼扛,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天,我揣著相機(jī)與錄音欲诺,去河邊找鬼抄谐。 笑死,一個胖子當(dāng)著我的面吹牛瞧栗,可吹牛的內(nèi)容都是我干的斯稳。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼迹恐,長吁一口氣:“原來是場噩夢啊……” “哼挣惰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤憎茂,失蹤者是張志新(化名)和其女友劉穎珍语,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竖幔,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡板乙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拳氢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片募逞。...
    茶點(diǎn)故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖馋评,靈堂內(nèi)的尸體忽然破棺而出放接,到底是詐尸還是另有隱情,我是刑警寧澤留特,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布纠脾,位于F島的核電站,受9級特大地震影響蜕青,放射性物質(zhì)發(fā)生泄漏苟蹈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一右核、第九天 我趴在偏房一處隱蔽的房頂上張望慧脱。 院中可真熱鬧,春花似錦蒙兰、人聲如沸磷瘤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至针炉,卻和暖如春挠他,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背篡帕。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工殖侵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人镰烧。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓拢军,卻偏偏與公主長得像,于是被迫代替她去往敵國和親怔鳖。 傳聞我的和親對象是個殘疾皇子茉唉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 原文http://www.codeceo.com/article/learn-java-lambda.html L...
    與我常在1053閱讀 1,121評論 1 7
  • Java 8 lambda表達(dá)式示例 轉(zhuǎn)自importNew 原文鏈接 例1、用lambda表達(dá)式實(shí)現(xiàn)Runnab...
    低至一折起閱讀 1,363評論 0 3
  • Life brings tears, smiles and memories. The tears will dr...
    笨蛋的豬豬閱讀 348評論 0 0
  • 現(xiàn)在是2026年,嚴(yán)成冉把房間的門關(guān)好度陆,然后打開衣柜把自己完完整整的裝進(jìn)去艾凯。她的衣柜不大,里面雖沒有多少件衣服...
    廿小闕閱讀 220評論 1 1
  • 前幾天回家看望母親懂傀,因?yàn)樗恢谎劬ψ隽税變?nèi)障手術(shù)趾诗。 現(xiàn)在的技術(shù),白內(nèi)障手術(shù)是小手術(shù)蹬蚁,很成熟很安...
    濕度為零閱讀 420評論 0 0