Lambda

Lambda

Lambda是一個(gè)匿名函數(shù)宰闰,我們可以把Lambda表達(dá)式理解為是一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣傳遞)衔瓮。可以寫出更簡(jiǎn)潔槐沼、更靈活的代碼。作為一種更緊湊的代碼風(fēng)格,使Java的語(yǔ)言表達(dá)能力得到提升

體驗(yàn)

/**
 * lambda 初體驗(yàn)
 */
public class lambdaTest {
    @Test
    public void test() {
        // 匿名內(nèi)部類
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };

        TreeSet<Integer> treeSet = new TreeSet<>(comparator);

        // lambda
        Comparator<Integer> comparator1 = (x, y) -> Integer.compare(x, y);

        TreeSet<Integer> treeSet1 = new TreeSet<>(comparator1);
    }
}

演變

原始做法

有這么一個(gè)需求母赵,求一個(gè)班級(jí)中年齡大于16歲的同學(xué)逸爵;

public class Student {

    private String name;

    private Integer age;

    private Integer scope;

    public Student() {
    }

    public Student(String name, Integer age, Integer scope) {
        this.name = name;
        this.age = age;
        this.scope = scope;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Integer getScope() {
        return scope;
    }

    public void setScope(Integer scope) {
        this.scope = scope;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", scope=" + scope +
                '}';
    }
}
        List<Student> students = Arrays.asList(
            new Student("張三", 18, 90),
            new Student("李四", 14, 95),
            new Student("王五", 16, 98),
            new Student("牛二", 18, 95),
            new Student("趙六", 15, 96)
    );

    // 年齡大于16
    @Test
    public void test01() {
        List<Student> stus = new ArrayList<>();

        for (Student student : students) {
            if (student.getAge() > 16) {
                stus.add(student);
            }
        }

        for (Student student : stus) {
            System.out.println(student);
        }
    }

需求變更:求班級(jí)中分?jǐn)?shù)大于95的同學(xué)

        // 分?jǐn)?shù)大于95
    @Test
    public void test02() {
        List<Student> stus = new ArrayList<>();

        for (Student student : students) {
            if (student.getScope() > 95) {
                stus.add(student);
            }
        }

        for (Student student : stus) {
            System.out.println(student);
        }
    }

可以看出,有效代碼只有if判斷中的條件凹嘲,這樣情況下师倔,隨著需求的變更,我們會(huì)書寫很多重復(fù)性代碼

優(yōu)化方式一:策略設(shè)計(jì)模式

需求:年齡大于16

  // 定義過濾接口
  public interface MyPredicate<T> {
      public boolean test(T t);
  }
  // 年齡過濾
  public class AgePredicate implements MyPredicate<Student> {
      @Override
      public boolean test(Student student) {
          return student.getAge() > 16;
      }
  }
      public List<Student> filterStu(List<Student> students, MyPredicate myPredicate) {
        List<Student> list = new ArrayList<>();
        for (Student student : students) {
            if (myPredicate.test(student)) {
                list.add(student);
            }
        }
        return list;
    }

    // 年齡大于16
    @Test
    public void test03() {
        List<Student> students = filterStu(this.students, new AgePredicate());
        for (Student student : students) {
            System.out.println(student);
        }
    }

需求變更:分?jǐn)?shù)大于95

// 分?jǐn)?shù)過濾
public class ScopePredicate implements MyPredicate<Student> {
    @Override
    public boolean test(Student student) {
        return student.getScope() > 95;
    }
}
      public List<Student> filterStu(List<Student> students, MyPredicate myPredicate) {
        List<Student> list = new ArrayList<>();
        for (Student student : students) {
            if (myPredicate.test(student)) {
                list.add(student);
            }
        }
        return list;
    }

        // 分?jǐn)?shù)大于95
    @Test
    public void test04() {
        List<Student> students = filterStu(this.students, new ScopePredicate());
        for (Student student : students) {
            System.out.println(student);
        }
    }

此時(shí)周蹭,根據(jù)需求的不同趋艘,我們只需要定義MyPredicate的實(shí)現(xiàn)類來編寫過濾條件即可,不要修改原有的邏輯代碼

優(yōu)化方式二:匿名內(nèi)部類

需求:年齡大于16

        // 年齡大于16
    @Test
    public void test05() {
        List<Student> students = filterStu(this.students, new MyPredicate<Student>() {
            @Override
            public boolean test(Student stu) {
                return stu.getAge() > 16;
            }
        });
        for (Student student : students) {
            System.out.println(student);
        }
    }

需求變更:分?jǐn)?shù)大于95

    // 分?jǐn)?shù)大于95
    @Test
    public void test06() {
        List<Student> students = filterStu(this.students, new MyPredicate<Student>() {
            @Override
            public boolean test(Student stu) {
                return stu.getScope() > 95;
            }
        });
        for (Student student : students) {
            System.out.println(student);
        }
    }

通過匿名內(nèi)部類的方式實(shí)現(xiàn)過濾代碼凶朗,可以避免為每一個(gè)需求定一個(gè)實(shí)現(xiàn)類來編寫過濾代碼瓷胧;但是此時(shí)的代碼還是略顯臃腫

優(yōu)化方式三:lambda表達(dá)式

需求:年齡大于16

        @Test
    public void test07() {
        List<Student> students = filterStu(this.students, x -> x.getAge() > 16);
        students.forEach(System.out::println);
    }

需求變更:分?jǐn)?shù)大于95

    @Test
    public void test08() {
        List<Student> students = filterStu(this.students, x -> x.getScope() > 95);
        students.forEach(System.out::println);
    }

此時(shí),我們可以看出棚愤,有效代碼只有x -> x.getAge() > 16,x -> x.getScope() > 95,極大提高代碼的簡(jiǎn)潔性和可讀性

語(yǔ)法

Java8中引入了一個(gè)新的操作符->搓萧,該操作符稱為箭頭操作符或Lambda操作符,->將Lambda表達(dá)式拆分成左右兩部分

左側(cè):Lambda表達(dá)式的參數(shù)列表(對(duì)應(yīng)匿名函數(shù)宛畦,重寫方法的參數(shù)列表)

右側(cè):Lambda表達(dá)式中所執(zhí)行的功能瘸洛,即Lambda體(對(duì)應(yīng)匿名函數(shù),重寫方法的方法體)

語(yǔ)法格式一:無參數(shù)次和,無返回值

() -> System.out.println("Hello lambda");
    @Test
    public void test01() {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello world");
            }
        };
        r.run();
        System.out.println("---------------------");

        Runnable r1 = () -> System.out.println("Hello lambda");
        r1.run();
    }

語(yǔ)法格式二:有一個(gè)參數(shù)反肋,無返回值

(x) -> System.out.println(x);
// 若只有一個(gè)參數(shù),小括號(hào)可以不寫
x -> System.out.println(x);

語(yǔ)法格式三:多個(gè)參數(shù)踏施,有返回值石蔗,多條執(zhí)行語(yǔ)句

@Test
    public void test02() {
        // 匿名函數(shù)方式
        Comparator<Integer> comparator = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1, o2);
            }
        };
        System.out.println("-------------------------------");
                
        // 多條執(zhí)行語(yǔ)句
        Comparator<Integer> comparator1 = (o1, o2) -> {
            System.out.println(o1 + "--------" + o2);
            return Integer.compare(o1, o2);
        };
        System.out.println("-------------------------------");

        // 若只有一條執(zhí)行語(yǔ)句,return和大括號(hào)可以省略不寫
        Comparator<Integer> comparator2 = (o1, o2) -> Integer.compare(o1, o2);
        
    }

函數(shù)式接口

接口中只有一個(gè)抽象方法的接口畅形,稱為函數(shù)式接口养距,可以使用注解@FunctionalInterface修飾;Lambda表達(dá)式需要“函數(shù)式接口”的支持

內(nèi)置四大核心函數(shù)式接口

接口 接口說明 參數(shù)類型 返回類型 用途
Consumer<T> 消費(fèi)型接口 T void 對(duì)類型為T的對(duì)象操作日熬,方法:void accept(T t);
Supplier<T> 供給型接口 T 返回T類型對(duì)象棍厌,方法:T get();
Function<T,R> 函數(shù)型接口 T R 對(duì)T類型對(duì)象操作,并返回R類型結(jié)果碍遍;方法:R apply(T t);
Predicate<T> 斷言型接口 T boolean 確定T類型對(duì)象是否滿足某中約束,并返回boolean值阳液;方法:test(T t);

擴(kuò)展接口

接口 參數(shù)類型 返回類型 用途
BiFunction<T, U, R> T, U R 對(duì)類型為T, U參數(shù)應(yīng)用操作怕敬,返回R類型的結(jié)果;方法 R apply(T t, U u);
UnaryOpetator<T> (Function子接口) T T 對(duì)類型為T的對(duì)象進(jìn)行一元運(yùn)算帘皿,并返回T類型的結(jié)果东跪;方法:T apply(T t);
BinaryOperator<T> (BiFunction子接口) T, T T 對(duì)類型為T的對(duì)象進(jìn)行二元運(yùn)算,并返回T類型的結(jié)果;方法:T apply(T t1, T t2);
BiConsumer(T, U) T, U void 對(duì)類型為T, U參數(shù)應(yīng)用操作虽填;方法:void accept(T t, U u)
ToIntFunction<T><br />ToLongFunction<T><br />ToDoubleFunction<T> T int<br />long<br />double 分別計(jì)算int, long, double值的函數(shù)
IntFunction<R><br />LongFunction<R><br />DoubleFunction<R> int<br />long<br />double R 參數(shù)分別為int, long, double 類型的函數(shù)

方法引用

若Lambda體中的內(nèi)容有方法已經(jīng)實(shí)現(xiàn)丁恭,我們可以使用方法引用方法引用可以理解為是Lambda表達(dá)式的另外一種表現(xiàn)形式

對(duì)象::實(shí)例方法名

注意:Lambda 體中調(diào)用方法的參數(shù)列表和返回值類型斋日,要與函數(shù)式接口中抽象方法的參數(shù)列表和返回值類型保持一致

    public void test01() {
        // 方式一
        Consumer<String> c1 = (x) -> System.out.println(x);

        // 方式二
        PrintStream out1 = System.out;
        Consumer<String> c2 = (x) -> out1.println(x);
        
        // 方式三
        PrintStream out2 = System.out;
        Consumer<String> c3 = out2::println;
        
        // 方式四
        Consumer<String> c4 = System.out::println;
    }

類名::靜態(tài)方法名

注意:Lambda 體中調(diào)用方法的參數(shù)列表和返回值類型牲览,要與函數(shù)式接口中抽象方法的參數(shù)列表和返回值類型保持一致

    public void test02() {
        // 方式一
        Comparator<Integer> comparator1 = (x, y) -> Integer.compare(x, y);
        
        // 方式二
        Comparator<Integer> comparator2 = Integer::compare;
    }

類名::實(shí)例方法名

注意:Lambda表達(dá)式參數(shù)列表中第一參數(shù)是實(shí)例方法的調(diào)用者,第二個(gè)參數(shù)是實(shí)例方法的參數(shù)時(shí)恶守,可以使用ClassName::Method

    @Test
    public void test03() {
        // 方式一
        BiPredicate<String, String> predicate01 = (x, y) -> x.equals(y);
        
        // 方式二
        BiPredicate<String,String> predicate02 = String::equals;
    }

構(gòu)造器引用

格式: ClassName::new

注意:Lambda體中需要調(diào)用構(gòu)造器的參數(shù)列表要與函數(shù)式接口中抽象方法的參數(shù)列表保持一致

    @Test
    public void test04() {
        // 無參
        Supplier<Date> s1 = () -> new Date();
        Supplier<Date> s2 = Date::new;
        
        // 一個(gè)參數(shù)
        Function<Long, Date> s3 = (x) -> new Date(x);
        Function<Long, Date> s4 = Date::new;
    }

數(shù)組引用

格式:Type[] ::new

    @Test
    public void test05() {
        // 方式一
        Function<Integer, String[]> f1 = (x) -> new String[x];
        
        // 方式二
        Function<Integer, String[]> f2 = String[]::new;
    }
最后編輯于
?著作權(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)離奇詭異飒赃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)科侈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門载佳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人兑徘,你說我怎么就攤上這事刚盈。” “怎么了挂脑?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵藕漱,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我崭闲,道長(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)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼哑了!你這毒婦竟也來了赘方?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤弱左,失蹤者是張志新(化名)和其女友劉穎窄陡,沒想到半個(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
  • 我被黑心中介騙來泰國(guó)打工考蕾, 沒想到剛下飛機(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