常见面试题:java8有什么新特性?

常见面试题:java8有什么新特性?

主要有以下这些新特性:

  • lambda 表达式,经常配合函数式接口使用,可以有效减少代码量

    • Runnable 是一个函数式接口,下面展示了创建线程三种写法,显然最后一种最简洁:

      class OldWay implements Runnable {
          @Override
          public void run() {
              System.out.println("最原始的方法");
          }
      }
      
      public class Test {
          public static void main(String[] args) {
      
              new Thread(new OldWay()).start();
      
              new Thread(new Runnable() {
                  @Override
                  public void run() {
                      System.out.println("匿名内部类");
                  }
              }).start();
      
              new Thread(() -> {
                  System.out.println("lambda表达式");
              }).start();
      
          }
      }
      
      
    • 在 new 一个 Thread 时需要传入一个 Runnable 接口的实现类

      • 第一种是最原始的做法,先创建一个 class 来实现 Runnable 接口,然后在创建线程时传入这个实现类,太麻烦了
      • 第二种是匿名内部类的写法,把实现类的名字给省略掉了,稍微方便点,但 run 这个方法名其实也有点冗余,因为 Runnable 里面就这么一个方法,不写出来应该也没关系啊
      • 第三种是 lambda 表达式的写法,把方法名也省略掉了,最简洁,但注意,如果接口里有多个方法,那么只能采用前两种方法了
    • 更直观的感受一下 lambda 表达式和函数式接口之间的关系:

      public class Test {
          public static void main(String[] args) { 
              Runnable runnable = () -> {
                  System.out.println("nb");
              };
          }
      }
      
      
    • 另一个常见应用就是集合类的 forEach 方法,需要一个 Consumer 参数,这也是一个函数式接口,里面的 accept 方法需要一个参数并且没有返回值(不用记,在 IDEA 里点进去看就行),一个例子如下,它遍历 list 中的每个元素,加一后输出:

      public class Test {
          public static void main(String[] args) {
              ArrayList<Integer> list = new ArrayList<>();
              list.add(1);
              list.add(2);
              list.add(3);
              //2 3 4
              list.forEach((Integer num) -> {
                  num = num + 1;
                  System.out.println(num);
              });
          }
      }
      
      
    • lambda 表达式还有些小细节,比如参数列表中参数的类型其实可以省略,如果代码块里只有一条语句那么花括号也可以省略,如果参数列表里只有一个参数那么圆括号也可以省略,但其实就算不省略也足够简洁了,我觉得没必要省略

  • 方法引用,感觉有点说不清,可以看个例子,就比如前面遍历 list,如果我就是想遍历一次 list 然后输出,可以用到方法引用:

    public class Test {
        public static void main(String[] args) {
    
            ArrayList<Integer> list = new ArrayList<>();
            list.add(1);
            list.add(2);
            list.add(3);
    
            list.forEach((Integer num) -> {
                System.out.println(num);
            });
    
            list.forEach(System.out::println);
    
        }
    }
    
    
    • 首先,forEach 是需要一个 Consumer 参数的,这个函数式接口的 accept 方法需要一个参数并且没有返回值,我们有两个方案,一个就是自己写一个 lambda 表达式,另一个就是使用方法引用,直接引用一个已经写好了的满足条件的方法,比如这里的 System.out.println 方法就是需要一个参数的 void 方法,满足条件,当然我们也可以定制一个满足条件的方法然后用方法引用的方式来使用,如下:

      class TestReference{
          public static void myPrint(Integer num){
              System.out.println(num);
          }
      }
      public class Test {
          public static void main(String[] args) {
              ArrayList<Integer> list = new ArrayList<>();
              list.add(1);
              list.add(2);
              list.add(3);
              list.forEach(TestReference::myPrint);
          }
      }
      
      
  • 函数式接口,前面其实已经提到过了,如果一个接口里面只有一个方法,那么这就是一个函数式接口,对于函数式接口,我们可以通过 lambda 表达式或者方法引用来进行快速的实现,而不必新建一个 class 去继承或者写一个匿名内部类

  • 默认方法,意思是说,我们在写一个接口时可以通过 default 关键字为其中的方法提供默认的实现方案,使得实现类就算不覆写这个方法也没有关系:

    interface TestInterface{
        default void test(){
            System.out.println("here");
        }
    }
    
    class TestDefault implements TestInterface{
        //没有覆写test方法也没有报错
    }
    
    public class Test {
        public static void main(String[] args) {
            //here
            new TestDefault().test();
        }
    }
    
    
  • Stream API,我们可以把一个集合转换为流,在这个流上做各种操作,比如查找、排序、过滤等等

    • 主要有以下这些操作:

      • 中间操作:指操作完成后还是返回一个流对象,可以拿着这个对象继续操作下去
      • 结束操作:指操作完成后不再返回流对象,一切都结束了
      • 无状态:指元素的处理不受之前元素的影响,可以挨个处理
      • 有状态:指该操作只有拿到所有元素之后才能继续下去
      • 非短路操作:指必须处理完所有元素才能得到最终结果
      • 短路操作:指遇到某些符合条件的元素就可以得到最终结果
    • 来个案例,现在给定一个 list,想要先求出每个元素的平方,然后排序,然后找出 10 和 100 之间的那些元素,然后去除重复元素,最后输出:

      public class Test {
          public static void main(String[] args) {
              //准备我们的list
              ArrayList<Integer> list = new ArrayList<>();
              int[] ints = {4, 1, 6, 2, 8, 5, 15, 11, 9};
              for (int i : ints) {
                  list.add(i);
              }
              //转换为流
              Stream<Integer> stream = list.stream();
              //第一步,求出每个元素的平方
              stream.map((Integer origin) -> {
                  return origin * origin;
              })
                      //第二步,排序
                      .sorted()
                      //第三步,找出10和100之间的那些值
                      .filter((Integer num) -> {
                          return num >= 10 && num <= 100;
                      })
                      //第四步,去重
                      .distinct()
                      //第五步,输出
                      .forEach(System.out::println);
          }
      }
      
      
    • 从案例中可以发现,很多流操作是需要一个函数式接口作为参数的,因此一定要搭配前面的 lambda 表达式和方法引用来完成这些流操作,否则代码量是过大的

    • 至于到底需要写什么样的 lambda 表达式(几个参数,返回值是什么),一定要在 IDEA 里点进去看,直接背是不现实的

  • 新的 Date Time API,因为 java 中同时存在 java.util.Datejava.sql.Date 两个时间类,很容易让人迷惑,而且这两个包里的内容也存在诸多问题,因此 java8 中新增了 java.time 这个包来把所有时间类的 API 一网打尽

    • 直接看个案例吧,演示部分 API 的使用:

      public class Test {
          public static void main(String[] args) {
      
              //获取当前的日期时间(年月日+时分秒)
              LocalDateTime currentTime = LocalDateTime.now();
              System.out.println("当前的日期和时间: " + currentTime);
      
              //获取当前的日期(年月日)
              LocalDate date1 = currentTime.toLocalDate();
              System.out.println("date1: " + date1);
      
              //分别得到当前的月、日、秒
              Month month = currentTime.getMonth();
              int day = currentTime.getDayOfMonth();
              int seconds = currentTime.getSecond();
              System.out.println("月: " + month +", 日: " + day +", 秒: " + seconds);
      
              //把当前的日期时间中的年替换为2012,日替换为10
              LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
              System.out.println("date2: " + date2);
      
              //显式的构造出一个日期
              LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
              System.out.println("date3: " + date3);
      
              //显式的构造出一个时间
              LocalTime date4 = LocalTime.of(22, 15);
              System.out.println("date4: " + date4);
      
              //解析字符串来得到一个时间
              LocalTime date5 = LocalTime.parse("20:15:30");
              System.out.println("date5: " + date5);
          }
      }
      
      
    • 最后的输出如下:

      当前的日期和时间: 2021-08-24T22:03:43.468015700
      date1: 2021-08-24
      月: AUGUST, 日: 24, 秒: 43
      date2: 2012-08-10T22:03:43.468015700
      date3: 2014-12-12
      date4: 22:15
      date5: 20:15:30
      
      
  • Optional 类,很好的解决了 NullPointerException 的问题

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,498评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,668评论 3 406
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,857评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,305评论 1 303
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,308评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,747评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,078评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 41,080评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,649评论 1 327
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,644评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,760评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,352评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,076评论 3 341
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,490评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,651评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,353评论 3 383
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,828评论 2 367

推荐阅读更多精彩内容

  • 废话不多说,自己进入今天的主题 1、面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: - 抽象:...
    传奇内服号阅读 2,364评论 1 31
  • 什么是流式操作 Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Str...
    Java天天阅读 689评论 0 0
  • java8新特性 原创者:文思 一、特性简介 速度更快 代码更少,增加了Lambda 强大的Stream API ...
    文思li阅读 3,054评论 1 1
  • 什么是流式操作 Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Str...
    青年心路阅读 279评论 0 0
  • java8 新特性 1 Lambda表达式 lambda 是一个匿名函数, lambda 表达式基本语法: jav...
    hyperdebug阅读 343评论 0 0