<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          感受lambda之美,推薦收藏,需要時(shí)查閱

          共 18920字,需瀏覽 38分鐘

           ·

          2021-03-31 20:18


          上一篇:3600萬中國(guó)人在抖音“上清華”

          作者:9龍

          來源:juejin.cn/post/6844903849753329678

          • 1、什么是函數(shù)式接口

            • 1.1 java8自帶的常用函數(shù)式接口。

            • 1.2 惰性求值與及早求值

          • 2、常用的流

            • 2.1 collect(Collectors.toList())

            • 2.2 filter

            • 2.3 map

            • 2.4 flatMap

            • 2.5 max和min

            • 2.6 count

            • 2.7 reduce

          • 3.1 轉(zhuǎn)換成值

          • 3.2 轉(zhuǎn)換成塊

          • 3.3 數(shù)據(jù)分組

          • 3.4 字符串拼接

          • 四、總結(jié)


          0、引言


          java8最大的特性就是引入Lambda表達(dá)式,即函數(shù)式編程,可以將行為進(jìn)行傳遞。總結(jié)就是:使用不可變值與函數(shù),函數(shù)對(duì)不可變值進(jìn)行處理,映射成另一個(gè)值。

          一、java重要的函數(shù)式接口

          1、什么是函數(shù)式接口

          函數(shù)接口是只有一個(gè)抽象方法的接口,用作 Lambda 表達(dá)式的類型。使用@FunctionalInterface注解修飾的類,編譯器會(huì)檢測(cè)該類是否只有一個(gè)抽象方法或接口,否則,會(huì)報(bào)錯(cuò)。可以有多個(gè)默認(rèn)方法,靜態(tài)方法。

          1.1 java8自帶的常用函數(shù)式接口。

          函數(shù)接口抽象方法功能參數(shù)返回類型示例
          Predicatetest(T t)判斷真假Tboolean9龍的身高大于185cm嗎?
          Consumeraccept(T t)消費(fèi)消息Tvoid輸出一個(gè)值
          FunctionR apply(T t)將T映射為R(轉(zhuǎn)換功能)TR獲得student對(duì)象的名字
          SupplierT get()生產(chǎn)消息NoneT工廠方法
          UnaryOperatorT apply(T t)一元操作TT邏輯非(!)
          BinaryOperatorapply(T t, U u)二元操作(T,T)(T)求兩個(gè)數(shù)的乘積(*)
          public class Test {
              public static void main(String[] args) {
                  Predicate<Integer> predicate = x -> x > 185;
                  Student student = new Student("9龍"23175);
                  System.out.println(
                      "9龍的身高高于185嗎?:" + predicate.test(student.getStature()));
                  Consumer<String> consumer = System.out::println;
                  consumer.accept("命運(yùn)由我不由天");
                  Function<Student, String> function = Student::getName;
                  String name = function.apply(student);
                  System.out.println(name);
                  Supplier<Integer> supplier = 
                      () -> Integer.valueOf(BigDecimal.TEN.toString());
                  System.out.println(supplier.get());
                  UnaryOperator<Boolean> unaryOperator = uglily -> !uglily;
                  Boolean apply2 = unaryOperator.apply(true);
                  System.out.println(apply2);
                  BinaryOperator<Integer> operator = (x, y) -> x * y;
                  Integer integer = operator.apply(23);
                  System.out.println(integer);
                  test(() -> "歡迎關(guān)注互聯(lián)網(wǎng)架構(gòu)師公眾號(hào)");
              }
              /**
               * 演示自定義函數(shù)式接口使用
               *
               * @param worker
               */

              public static void test(Worker worker) {
                  String work = worker.work();
                  System.out.println(work);
              }
              public interface Worker {
                  String work();
              }
          }
          //9龍的身高高于185嗎?:false
          //命運(yùn)由我不由天
          //9龍
          //10
          //false
          //6
          //我是一個(gè)演示的函數(shù)式接口

          以上演示了lambda接口的使用及自定義一個(gè)函數(shù)式接口并使用。下面,我們看看java8將函數(shù)式接口封裝到流中如何高效的幫助我們處理集合。

          注意:Student::getName例子中這種編寫lambda表達(dá)式的方式稱為方法引用。格式為ClassNmae::methodName。是不是很神奇,java8就是這么迷人。

          示例:本篇所有示例都基于以下三個(gè)類。OutstandingClass:班級(jí);Student:學(xué)生;SpecialityEnum:特長(zhǎng)。

          1.2 惰性求值與及早求值

          **惰性求值:只描述Stream,操作的結(jié)果也是Stream,這樣的操作稱為惰性求值。**惰性求值可以像建造者模式一樣鏈?zhǔn)绞褂茫詈笤偈褂眉霸缜笾档玫阶罱K結(jié)果。

          及早求值:得到最終的結(jié)果而不是Stream,這樣的操作稱為及早求值。


          2、常用的流

          2.1 collect(Collectors.toList())

          將流轉(zhuǎn)換為list。還有toSet(),toMap()等。及早求值

          public class TestCase {
              public static void main(String[] args) {
                  List<Student> studentList = Stream.of(new Student("路飛"22175),
                          new Student("紅發(fā)"40180),
                          new Student("白胡子"50185)).collect(Collectors.toList());
                  System.out.println(studentList);
              }
          }
          //輸出結(jié)果
          //[Student{name='路飛', age=22, stature=175, specialities=null}, 
          //Student{name='紅發(fā)', age=40, stature=180, specialities=null}, 
          //Student{name='白胡子', age=50, stature=185, specialities=null}]

          2.2 filter

          顧名思義,起過濾篩選的作用。內(nèi)部就是Predicate接口。惰性求值。

          在公眾號(hào)互聯(lián)網(wǎng)架構(gòu)師后臺(tái)回復(fù)“2T”,獲取一份驚喜禮包。

          比如我們篩選出出身高小于180的同學(xué)。

          public class TestCase {
              public static void main(String[] args) {
                  List<Student> students = new ArrayList<>(3);
                  students.add(new Student("路飛"22175));
                  students.add(new Student("紅發(fā)"40180));
                  students.add(new Student("白胡子"50185));
                  List<Student> list = students.stream()
                      .filter(stu -> stu.getStature() < 180)
                      .collect(Collectors.toList());
                  System.out.println(list);
              }
          }
          //輸出結(jié)果
          //[Student{name='路飛', age=22, stature=175, specialities=null}]

          2.3 map

          轉(zhuǎn)換功能,內(nèi)部就是Function接口。惰性求值

          img
          public class TestCase {
              public static void main(String[] args) {
                  List<Student> students = new ArrayList<>(3);
                  students.add(new Student("路飛"22175));
                  students.add(new Student("紅發(fā)"40180));
                  students.add(new Student("白胡子"50185));
                  List<String> names = students.stream().map(student -> student.getName())
                          .collect(Collectors.toList());
                  System.out.println(names);
              }
          }
          //輸出結(jié)果
          //[路飛, 紅發(fā), 白胡子]

          例子中將student對(duì)象轉(zhuǎn)換為String對(duì)象,獲取student的名字。

          2.4 flatMap

          將多個(gè)Stream合并為一個(gè)Stream。惰性求值

          img
          public class TestCase {
              public static void main(String[] args) {
                  List<Student> students = new ArrayList<>(3);
                  students.add(new Student("路飛"22175));
                  students.add(new Student("紅發(fā)"40180));
                  students.add(new Student("白胡子"50185));
                  List<Student> studentList = Stream.of(students,
                          asList(new Student("艾斯"25183),
                                  new Student("雷利"48176)))
                          .flatMap(students1 -> students1.stream()).collect(Collectors.toList());
                  System.out.println(studentList);
              }
          }
          //輸出結(jié)果
          //[Student{name='路飛', age=22, stature=175, specialities=null}, 
          //Student{name='紅發(fā)', age=40, stature=180, specialities=null}, 
          //Student{name='白胡子', age=50, stature=185, specialities=null}, 
          //Student{name='艾斯', age=25, stature=183, specialities=null},
          //Student{name='雷利', age=48, stature=176, specialities=null}]

          調(diào)用Stream.of的靜態(tài)方法將兩個(gè)list轉(zhuǎn)換為Stream,再通過flatMap將兩個(gè)流合并為一個(gè)。

          2.5 max和min

          我們經(jīng)常會(huì)在集合中求最大或最小值,使用流就很方便。及早求值。

          public class TestCase {
              public static void main(String[] args) {
                  List<Student> students = new ArrayList<>(3);
                  students.add(new Student("路飛"22175));
                  students.add(new Student("紅發(fā)"40180));
                  students.add(new Student("白胡子"50185));
                  Optional<Student> max = students.stream()
                      .max(Comparator.comparing(stu -> stu.getAge()));
                  Optional<Student> min = students.stream()
                      .min(Comparator.comparing(stu -> stu.getAge()));
                  //判斷是否有值
                  if (max.isPresent()) {
                      System.out.println(max.get());
                  }
                  if (min.isPresent()) {
                      System.out.println(min.get());
                  }
              }
          }
          //輸出結(jié)果
          //Student{name='白胡子', age=50, stature=185, specialities=null}
          //Student{name='路飛', age=22, stature=175, specialities=null}

          max、min接收一個(gè)Comparator(例子中使用java8自帶的靜態(tài)函數(shù),只需要傳進(jìn)需要比較值即可。)并且返回一個(gè)Optional對(duì)象,該對(duì)象是java8新增的類,專門為了防止null引發(fā)的空指針異常。可以使用max.isPresent()判斷是否有值;可以使用max.orElse(new Student()),當(dāng)值為null時(shí)就使用給定值;也可以使用max.orElseGet(() -> new Student());這需要傳入一個(gè)Supplier的lambda表達(dá)式。

          在公眾號(hào)互聯(lián)網(wǎng)架構(gòu)師后臺(tái)回復(fù)“2T”,獲取一份驚喜禮包。

          2.6 count

          統(tǒng)計(jì)功能,一般都是結(jié)合filter使用,因?yàn)橄群Y選出我們需要的再統(tǒng)計(jì)即可。及早求值

          public class TestCase {
              public static void main(String[] args) {
                  List<Student> students = new ArrayList<>(3);
                  students.add(new Student("路飛"22175));
                  students.add(new Student("紅發(fā)"40180));
                  students.add(new Student("白胡子"50185));
                  long count = students.stream().filter(s1 -> s1.getAge() < 45).count();
                  System.out.println("年齡小于45歲的人數(shù)是:" + count);
              }
          }
          //輸出結(jié)果
          //年齡小于45歲的人數(shù)是:2

          2.7 reduce

          reduce 操作可以實(shí)現(xiàn)從一組值中生成一個(gè)值。在上述例子中用到的 count 、 min 和 max 方 法,因?yàn)槌S枚患{入標(biāo)準(zhǔn)庫(kù)中。事實(shí)上,這些方法都是 reduce 操作。及早求值。

          public class TestCase {
              public static void main(String[] args) {
                  Integer reduce = Stream.of(1234).reduce(0, (acc, x) -> acc+ x);
                  System.out.println(reduce);
              }
          }
          //輸出結(jié)果
          //10

          我們看得reduce接收了一個(gè)初始值為0的累加器,依次取出值與累加器相加,最后累加器的值就是最終的結(jié)果。


          三、高級(jí)集合類及收集器

          3.1 轉(zhuǎn)換成值

          **收集器,一種通用的、從流生成復(fù)雜值的結(jié)構(gòu)。**只要將它傳給 collect 方法,所有 的流就都可以使用它了。標(biāo)準(zhǔn)類庫(kù)已經(jīng)提供了一些有用的收集器,以下示例代碼中的收集器都是從 java.util.stream.Collectors 類中靜態(tài)導(dǎo)入的。

          public class CollectorsTest {
              public static void main(String[] args) {
                  List<Student> students1 = new ArrayList<>(3);
                  students1.add(new Student("路飛"23175));
                  students1.add(new Student("紅發(fā)"40180));
                  students1.add(new Student("白胡子"50185));
                  OutstandingClass ostClass1 = new OutstandingClass("一班", students1);
                  //復(fù)制students1,并移除一個(gè)學(xué)生
                  List<Student> students2 = new ArrayList<>(students1);
                  students2.remove(1);
                  OutstandingClass ostClass2 = new OutstandingClass("二班", students2);
                  //將ostClass1、ostClass2轉(zhuǎn)換為Stream
                  Stream<OutstandingClass> classStream = Stream.of(ostClass1, ostClass2);
                  OutstandingClass outstandingClass = biggestGroup(classStream);
                  System.out.println("人數(shù)最多的班級(jí)是:" + outstandingClass.getName());
                  System.out.println("一班平均年齡是:" + averageNumberOfStudent(students1));
              }
              /**
               * 獲取人數(shù)最多的班級(jí)
               */

              private static OutstandingClass biggestGroup(Stream<OutstandingClass> outstandingClasses) {
                  return outstandingClasses.collect(
                          maxBy(comparing(ostClass -> ostClass.getStudents().size())))
                          .orElseGet(OutstandingClass::new);
              }
              /**
               * 計(jì)算平均年齡
               */

              private static double averageNumberOfStudent(List<Student> students) {
                  return students.stream().collect(averagingInt(Student::getAge));
              }
          }
          //輸出結(jié)果
          //人數(shù)最多的班級(jí)是:一班
          //一班平均年齡是:37.666666666666664

          maxBy或者minBy就是求最大值與最小值。

          3.2 轉(zhuǎn)換成塊

          常用的流操作是將其分解成兩個(gè)集合,Collectors.partitioningBy幫我們實(shí)現(xiàn)了,接收一個(gè)Predicate函數(shù)式接口。

          將示例學(xué)生分為會(huì)唱歌與不會(huì)唱歌的兩個(gè)集合。

          public class PartitioningByTest {
              public static void main(String[] args) {
                  //省略List<student> students的初始化
                  Map<Boolean, List<Student>> listMap = students.stream().collect(
                      Collectors.partitioningBy(student -> student.getSpecialities().
                                                contains(SpecialityEnum.SING)));
              }
          }

          3.3 數(shù)據(jù)分組

          數(shù)據(jù)分組是一種更自然的分割數(shù)據(jù)操作,與將數(shù)據(jù)分成 ture 和 false 兩部分不同,可以使用任意值對(duì)數(shù)據(jù)分組。Collectors.groupingBy接收一個(gè)Function做轉(zhuǎn)換。

          如圖,我們使用groupingBy將根據(jù)進(jìn)行分組為圓形一組,三角形一組,正方形一組。

          例子:根據(jù)學(xué)生第一個(gè)特長(zhǎng)進(jìn)行分組

          public class GroupingByTest {
              public static void main(String[] args) {
                  //省略List<student> students的初始化
                   Map<SpecialityEnum, List<Student>> listMap = 
                       students.stream().collect(
                       Collectors.groupingBy(student -> student.getSpecialities().get(0)));
              }
          }

          Collectors.groupingBy與SQL 中的 group by 操作是一樣的。

          3.4 字符串拼接

          如果將所有學(xué)生的名字拼接起來,怎么做呢?通常只能創(chuàng)建一個(gè)StringBuilder,循環(huán)拼接。使用Stream,使用Collectors.joining()簡(jiǎn)單容易。

          public class JoiningTest {
              public static void main(String[] args) {
                  List<Student> students = new ArrayList<>(3);
                  students.add(new Student("路飛"22175));
                  students.add(new Student("紅發(fā)"40180));
                  students.add(new Student("白胡子"50185));
                   String names = students.stream()
                       .map(Student::getName).collect(Collectors.joining(",","[","]"));
                  System.out.println(names);
              }
          }
          //輸出結(jié)果
          //[路飛,紅發(fā),白胡子]

          joining接收三個(gè)參數(shù),第一個(gè)是分界符,第二個(gè)是前綴符,第三個(gè)是結(jié)束符。也可以不傳入?yún)?shù)Collectors.joining(),這樣就是直接拼接。


          四、總結(jié)


          本篇主要從實(shí)際使用講述了常用的方法及流,使用java8可以很清晰表達(dá)你要做什么,代碼也很簡(jiǎn)潔。本篇例子主要是為了講解較為簡(jiǎn)單,大家可以去使用java8重構(gòu)自己現(xiàn)有的代碼,自行領(lǐng)會(huì)lambda的奧妙。本文說的Stream要組合使用才會(huì)發(fā)揮更大的功能,鏈?zhǔn)秸{(diào)用很迷人,根據(jù)自己的業(yè)務(wù)去做吧。


          看完這篇文章,你有什么收獲?歡迎在留言區(qū)與10w+Java開發(fā)者一起討論~

          關(guān)注微信公眾號(hào):互聯(lián)網(wǎng)架構(gòu)師,在后臺(tái)回復(fù):2T,可以獲取我整理的教程,都是干貨。


          猜你喜歡

          1、GitHub 標(biāo)星 3.2w!史上最全技術(shù)人員面試手冊(cè)!FackBoo發(fā)起和總結(jié)

          2、如何才能成為優(yōu)秀的架構(gòu)師?

          3、從零開始搭建創(chuàng)業(yè)公司后臺(tái)技術(shù)棧

          4、程序員一般可以從什么平臺(tái)接私活?

          5、37歲程序員被裁,120天沒找到工作,無奈去小公司,結(jié)果懵了...

          6、滴滴業(yè)務(wù)中臺(tái)構(gòu)建實(shí)踐,首次曝光

          7、不認(rèn)命,從10年流水線工人,到谷歌上班的程序媛,一位湖南妹子的勵(lì)志故事

          8、15張圖看懂瞎忙和高效的區(qū)別

          9、2T架構(gòu)師學(xué)習(xí)資料干貨分享


          瀏覽 55
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  女人18毛片AAA片水真多 女人18片毛片90分钟免费 | 毛片9| 欧美天天干天天女人 | 777精品视频在线 | 青青草成人手机在线视频 |