Java8新特性

简介: 北京时间2018年9月26日,Oracle官方发布Java 11。既然版本都更新到11了,现在才来学8是不是太晚了?其实不是的,目前应该大部分都还是使用的Java 7和Java 8,这两个应该还是主流。而Java 8 又有一些激动人心的新特性,所以还是值得学习的。

一、Lambada表达式:


1、什么是lambda?


Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。


2、了解新操作符:


Java 8引入了新的操作符,->,叫箭头操作符或者叫lambda操作符。当使用lambda表达式时就需要使用这个操作符。


3、lambda表达式语法:


箭头操作符将lambda表达式分成了两部分:


  • 左侧:lambda表达式的参数列表(接口中抽象方法的参数列表)
  • 右侧:lambda表达式中所需执行的功能(lambda体,对抽象方法的实现)

语法有如下几种格式:

  • 语法格式一(无参数无返回值):  () -> 具体实现
  • 语法格式二(有一个参数无返回值): (x) -> 具体实现 或  x -> 具体实现
  • 语法格式三(有多个参数,有返回值,并且lambda体中有多条语句):(x,y) -> {具体实现}
  • 语法格式四:若方法体只有一条语句,那么大括号和return都可以省略
    注:lambda表达式的参数列表的参数类型可以省略不写,可以进行类型推断。


看几个例子:


例一:

@Test
public void test1(){
     // 实现一个线程
     int num = 0;//jdk1.8以前,这个必须定义为final,下面才能用,1.8后默认就为final
     Runnable runnable = new Runnable() {
         @Override
         public void run() {
             System.out.println("hello world"+ num);
         }
     };
     runnable.run();
}


创建一个线程,重写run方法,在run方法里面打印一句话。我们想要的就是System.out.println("hello world"+ num);这行代码,但是为了实现这行代码,不得不多写了好多行。lambda就可以解决这一点,看看用lambda如何实现:

Runnable runnable1 = () -> System.out.println("hello world"+num);
runnable1.run();


用lambda这样就搞定了。首先还是Runnable runnable1 =,但是不用new了,右边就用lambda实现。我们要使用的是该接口的run方法,run方法不需要参数,所以lambda表达式左边就是(),lambda表达式右边是抽象方法的实现,也就是第一种方式中run方法的方法体写到lambda表达式右边就可以了。


例二:

Comparator<Integer> comparator = new Comparator<Integer>() {
     @Override
     public int compare(Integer o1, Integer o2) {
         return Integer.compare(o1,o2);//就这一行关键代码
     }
};


以前写一个比较器就要像上面那样写,先new比较器类,然后在其compare方法里写核心代码。用lambda实现:

Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);


compare方法需要两个参数,所以箭头操作符左边写(x,y),右边是compare方法的实现,所以应该写return Integer.compare(o1,o2);,但是根据上面的语法格式四可知,return可以省略,因此就写成了上面那样。


通过这两个例子可以感受到lambda表达式的简洁,但是问题来了:我们说lambda表达式就是一个匿名函数,我们只需要指定参数和lambda体即可,那么它是如何判断重写的是哪个方法呢?比如一个接口中有多个方法,如果使用lambda表达式来写,那么如何判断我们使用的是该接口的哪个方法?其实是不能判断的!通过上面两个例子可以发现,Runnable接口和Comparator接口都是只有一个方法的接口,所以可以使用lambda。


二、函数式接口:


1、什么是函数式接口?


像Runnable和Comparator这样只有一个方法的接口,称为函数式接口。也可以在接口上加上@FunctionalInterface注解,如果编译通过,则该接口就是函数式接口。

lambda表达式就需要函数式接口的支持。


2、看一个需求:


需求:需要对两个数进行加减乘除等运算,怎么实现?


  • 传统做法:传统做法中,需要进行几种运算,我们就要写几个方法。一种运算对应一个方法。
  • lambda做法:首先要定义一个函数式接口,接口中只有一个方法,接收两个参数。

@FunctionalInterface
public interface MyInterface {
    public Integer getValue(Integer num1,Integer num2);
}


然后就可以使用了:

@Test
public void test5(){
      MyInterface myInterface = (x,y) -> x*y;//乘法运算
      MyInterface myInterface1 = (x,y) -> x+y;//加法运算
      Integer result1 = myInterface.getValue(100,200);
      Integer result2 = myInterface1.getValue(1024,2048);
      System.out.println(result1);
      System.out.println(result2);
}


所以用lambda的话,只需要定义一个函数式接口,不管进行什么操作,都可以用lambda解决,不用再一种运算对应一个方法。但是,还需要自己定义函数式接口,好像也没简单很多。Java考虑到这点了,所以内置了函数式接口。


3、四大内置函数式接口:


为了不需要我们自己定义函数式接口,Java内置了四大函数式接口,这四大接口加上它们的子类,完全满足我们的使用了。四大函数式接口是:


  • Consumer<T>:消费型接口(void accept(T t)),接收一个参数,无返回值。
  • Supplier<T>:供给型接口(T get()),无参数,有返回值。
  • Function<T,R>:函数型接口(R apply(T t)),接收一个参数,有返回值。
  • Predicate<T>:断言型接口(boolean test(T t)),接收一个参数,返回Boolean值。


4、四大函数式接口的使用:


接下来看看具体如何使用这四大函数式接口。


消费型接口的使用:

Consumer consumer = (x) -> System.out.println("消费了"+x+"元");
 consumer.accept(100);


供给型接口的使用:

Supplier<Integer> supplier = () -> (int)(Math.random() * 100);//生成随机数
System.out.println(supplier.get());


函数型接口的使用:

Function<String,String> function = str -> str.toUpperCase();//将传入的字符串转成大写
String s = function.apply("adcdefggffs");
System.out.println(s);


断言型接口的使用:

//需求:将满足条件的字符串添加到集合中去
  public List<String> filterString(List<String> strings, Predicate<String> predicate){
      List<String> stringList = new ArrayList<>();
      for (String string : strings) {
          if (predicate.test(string)){
              stringList.add(string);
          }
      }
      return stringList;
 }
//测试
@Test
 public void test4(){
      List<String> list = Arrays.asList("hello","world","niu","bi");
      List<String> newList = filterString(list,str -> str.length() > 3);//选出长度大于3的字符串
      newList.forEach(System.out::println);
 }


三、方法引用与构造器引用:


当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用。不过实现抽象方法的参数列表,必须与引用方法的参数列表保持一致。


1、方法引用语法:


  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法


2、方法引用具体用法:


说了那么多可能还不清楚到底什么意思,一起来看几个例子。


语法一例子:

Consumer<String> consumer = x -> System.out.println(x);//传统写法
Consumer<String> consumer = System.out::println;//使用方法引用


println方法和Consumer的accept方法都是无返回值,接收一个参数,所以可以这样写。


语法二例子:

Comparator<Integer> comparator = (x,y) -> Integer.compare(x,y);
//因为compare方法已经被Integer实现了,且是静态的,所以这样用就行。
Comparator<Integer> comparator1 = Integer::compare;


语法三例子:

BiPredicate<String,String> biPredicate = (x,y) -> x.equals(y);
 //可以改成如下写法
 //不过要满足:第一个参数是实例方法的调用者,第二个参数是实例方法的参数时,就可以这样用
 BiPredicate<String,String> biPredicate1 = String::equals;


3、构造器引用:

Supplier<Employee> supplier = () -> new Employee();
//可以改写成这样
//注意:需要调用的构造器的参数列表要与函数接口中抽象方法的参数列表一致
Supplier<Employee> supplier1 = Employee::new;
Employee employee = supplier.get();


四、Stream API:


Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。


简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。


1、理解Stream:


Stream被称作流,是用来处理集合以及数组的数据的。它有如下特点:


  • Stream 自己不会存储元素。
  • Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
  • Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。


2、使用Stream的三个步骤:


  • 创建Stream:一个数据源(如:集合、数组),获取一个流
  • 中间操作:一个中间操作链,对数据源的数据进行处理
  • 终止操作:一个终止操作,执行中间操作链,并产生结果


3、创建Stream:


直接看代码:

//1、通过集合提供的stream方法或parallelStream()方法创建
List<String> list = new ArrayList<>();
Stream<String> stringStream = list.stream();
//2、通过Arrays中的静态方法stream获取数组流
Employee[] employees = new Employee[10];
Stream<Employee> stream = Arrays.stream(employees);
//3、通过Stream类的静态方法of()创建流
Stream<String> stream1 = Stream.of("aa","bb","cc");
//4、创建无限流
//迭代方式创建无限流
//从0开始,每次加2,生成无限个
Stream<Integer> stream2 = Stream.iterate(0,(x) -> x+2);
//生成10个
stream2.limit(10).forEach(System.out::println);
//生成方式创建无限流
Stream.generate(() -> Math.random())
                .limit(5)
                .forEach(System.out::println);


上面介绍了集合、数组创建流的几种方式,都有对应的注解。


4、中间操作:


筛选与切片:


  • filter -- 接收lambda,从流中排除某些数据。
  • limit -- 截断流,使其元素不超过给定数量。
  • skip(n) -- 跳过元素,返回一个扔掉了前n个元素的流,若不足n个元素,则返回空流。
  • distinct -- 筛选,通过流所生成元素的hashCode()和equals()去除重复元素,所以对象必须重新hashCode方法和equals方法。


看代码:

employees.stream()//已有employees集合
         .filter((e) -> e.getAge() > 18)//中间操作(选出年龄大于18的)
         .limit(1)//中间操作(只返回一个)
         .forEach(System.out::println);//终止操作


映射:


  • map -- 接收lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • flatMap -- 接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所以流连接成一个流。


看例子:

List<String> list = Arrays.asList("aa","bb","cc","dd");
list.stream()
    .map(str -> str.toUpperCase())//将所有的转成大写
    .forEach(System.out::println);


排序:


  • sorted() -- 自然排序(按照Comparable来排序)。
  • sorted(Comparator com) -- 定制排序(按照Comparator来排序)。


看例子:

List<String> list = Arrays.asList("ccc","bbb","aaa","ddd");
list.stream()
    .sorted()//自然排序
    .forEach(System.out::print);//aaa,bbb,ccc,ddd
//定制排序
employees.stream()//employees是一个存有多名员工的集合
      .sorted((e1, e2) -> {
          if (e1.getAge().equals(e2.getAge())){ //如果年龄一样
               return e1.getName().compareTo(e2.getName());//就比较姓名
          }else {
               return e1.getAge().compareTo(e2.getAge());//年龄不一样就比较年龄
          }
      }).forEach(System.out::println);


5、终止操作:


查找与匹配:


  • allMatch -- 检查是否匹配所有元素。
  • anyMatch -- 检查是否至少匹配一个元素。
  • noneMatch -- 检查是否没有匹配所有元素。
  • findFirst -- 返回第一个元素。
  • findAny -- 返回当前流中任意元素。
  • count -- 返回流中元素总个数。
  • max -- 返回流中最大值。
  • min -- 返回流中最小值。

//看看employee集合中是不是所有都是男的
boolean b = employees.stream()
                     .allMatch(e -> e.getGender().equals("男"));
System.out.println(b);


规约:


  • reduce(T identity,BinaryOperator) -- 可以将流中元素反复结合起来,得到一个值。

//规约求和
List<Integer> list = Arrays.asList(1,3,5,4,4,3);
Integer sum = list.stream()
                 .reduce(0,(x,y) -> x+y);//首先把0作为x,把1作为y,进行加法运算得到1,把1再作为x,把3作为y,以此类推
System.out.println(sum);
//获取工资总和
Optional<Double> optional = employees.stream()
                .map(Employee::getSalary)//提取工资
                .reduce(Double::sum);//求工资总和
System.out.println(optional2.get());


收集:


  • collect -- 将流转换为其他形式。接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。

//把公司中所有员工的姓名提取出来并收集到一个集合中去
List<String> stringList = employees.stream()
                .map(Employee::getName)//提取员工姓名
                //.collect(Collectors.toList());//收集到list集合
                //.collect(Collectors.toSet());//收集到set集合
                .collect(Collectors.toCollection(LinkedList::new));//这种方式可收集到任意集合
stringList.forEach(System.out::println);//遍历集合
//计算工资平均值
Double avgSalary = employees.stream()
                .collect(Collectors.averagingDouble(Employee::getSalary));
System.out.println(avgSalary);
//根据年龄分组
Map<Integer,List<Employee>> map = employees.stream()
                .collect(Collectors.groupingBy(Employee::getAge));
System.out.println(map);
//先按性别分组,性别一样时按年龄分组
Map<String,Map<Integer,List<Employee>>> map1 = employees.stream()       
 .collect(Collectors.groupingBy(Employee::getGender,Collectors.groupingBy(Employee::getAge)));
System.out.println(map1);
//分区,满足条件的一个区,不满足的另一个区
Map<Boolean,List<Employee>> map2 = employees.stream()
         .collect(Collectors.partitioningBy(e -> e.getSalary() > 6000));//工资大于6000的为true区,否则为false区
System.out.println(map2);
//获取工资的总额、平均值等
DoubleSummaryStatistics dss = employees.stream()
           .collect(Collectors.summarizingDouble(Employee::getSalary));
System.out.println(dss.getSum());
System.out.println(dss.getAverage());
System.out.println(dss.getMax());


五、并行流与串行流:


1、fork/join框架:


此框架就是在必要的情况下,将一个大任务,进行拆分(fork)成若干个小任务(拆到不可再拆时),再将一个个的小任务运算的结果进行 join 汇总。


image.png


2、并行流与串行流:


通过上面的图可以知道,使用fork/join框架可以提高效率(运算量越大越明显,运算量可能反而更慢,因为拆分也需要时间),但是在Java 8之前需要自己实现fork/join,还是挺麻烦的,Java 8就方便多了,因为提供了并行流,底层就是使用了fork/join。Stream API 可以声明性地通过 parallel() 与 sequential() 在并行流与顺序流之间进行切换。

@Test
public void test(){
      Instant start = Instant.now();
      //普通做法求0加到10000000000的和
      LongStream.rangeClosed(0,100000000000L)
              .reduce(0,Long::sum);
      Instant end = Instant.now();
      System.out.println("耗费"+ Duration.between(end ,start) + "秒");//55秒
}
@Test
public void test2(){
     Instant start = Instant.now();
     //并行流求0加到10000000000的和
     LongStream.rangeClosed(0,100000000000L)
             .parallel()//使用并行流
             .reduce(0,Long::sum);
     Instant end = Instant.now();
     System.out.println("耗费"+ Duration.between(end ,start) + "秒");//30秒
}


通过运行上面的程序可以明显感受到并行流的高效。


六、新时间日期API:


Java 8之前的Date和Calendar都是线程不安全的,而且使用起来比较麻烦,Java 8提供了全新的时间日期API,LocalDate(日期)、LocalTime(时间)、LocalDateTime(时间和日期) 、Instant (时间戳)、Duration(用于计算两个“时间”间隔)、Period(用于计算两个“日期”间隔)等。


1、LocalDate、LocalTime、LocalDateTime:


这三个用法一样。

//获取当前系统时间
LocalDateTime localDateTime = LocalDateTime.now();//当前时间日期
LocalDateTime localDateTime2 = localDateTime.plusYears(2);//加两年
System.out.println(localDateTime.getMonth());
System.out.println(localDateTime);
System.out.println(localDateTime2);
//指定时间
LocalDateTime localDateTime1 = LocalDateTime.of(2018,12,13,21,8);
System.out.println(localDateTime1);


2、Instant 时间戳:


时间戳就是计算机读的时间,它是以Unix元年(传统 的设定为UTC时区1970年1月1日午夜时分)开始算起的。

//计算机读的时间:时间戳(Instant),1970年1月1日0时0分0秒到此时的毫秒值
Instant instant = Instant.now();
System.out.println(instant);//默认是美国时区,8个时差
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));//加上时差
System.out.println(offsetDateTime);
System.out.println(instant.toEpochMilli());//显示毫秒值


3、Duration 和 Period:

LocalTime localTime = LocalTime.now();
try {
    Thread.sleep(1000);
}catch (Exception e){
    e.printStackTrace();
}
LocalTime localTime1 = LocalTime.now();
System.out.println(Duration.between(localTime,localTime1).toMillis());
//获取两个日期之间的间隔
LocalDate localDate = LocalDate.of(2012,1,1);
LocalDate localDate1 = LocalDate.now();
Period period = Period.between(localDate,localDate1);
System.out.println(period);
System.out.println(period.getYears()+"年"+period.getMonths()+"月"+period.getDays()+"日");


4、时间校正器(TemporalAdjuster):

LocalDateTime localDateTime = LocalDateTime.now();
System.out.println(localDateTime);
LocalDateTime localDateTime1 = localDateTime.withDayOfMonth(1);//localDate日期中月份的1号
System.out.println(localDateTime1);
localDateTime1.with(TemporalAdjusters.firstDayOfNextMonth());//下一个月的第一天
localDateTime.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));//下周日


5、格式化日期(.DateTimeFormatter ):

@Test
public void test6(){
        //DateTimeFormatter:格式化
        //使用预设格式
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE_TIME;
        LocalDateTime localDateTime = LocalDateTime.now();
        String str = localDateTime.format(dateTimeFormatter);
        System.out.println(str);
        System.out.println("==========================");
        //自定义格式
        DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
        String str2 = localDateTime.format(dateTimeFormatter1);
        //这样格式化也可以
        String str3 = dateTimeFormatter1.format(localDateTime);
        System.out.println(str2);
        System.out.println(str3);
        //退回到解析前的格式
        LocalDateTime newDate = localDateTime.parse(str,dateTimeFormatter);
        System.out.println(newDate);
}


6、时区的处理:


Java8 中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime。

@Test
 public void test7(){
   //ZonedDate ZonedTime ZonedDateTime
   LocalDateTime dateTime = LocalDateTime.now(ZoneId.of("Europe/Tallinn"));
   System.out.println(dateTime);
}


七、接口中的默认方法和静态方法:


public interface MyInterface {
    default String test(){
        return "允许存在有具体实现的方法";
    }
    public static String test2(){
        return "接口中还可以有静态方法";
    }
}


如上所示,Java 8的接口中允许有默认方法和静态方法。如果一个类继承了一个类还实现了一个接口,而且接口中的默认方法和父类中的方法同名,这时采用类优先原则。也就是说,子类使用的是父类的方法,而不是接口中的同名方法。


八、其他新特性:



1、Optional类:


这个类是为了尽可能减少空指针异常的。就是把普通对象用Optional包起来,做了一些封装。看看其用法:

@Data
public class Man { //男人类
    private Godness godness;//女神
}

@Data
public class Godness {
    private String name;
    public Godness(String name){
        this.name = name;
    }
    public Godness(){
    }
}

//获取男人心中的女神的名字(有的人不一定有女神,也就是说女神可能为空)
    //常规做法要加很多判断
    public String getGodnessName(Man man){
        if (man != null){
            Godness godness = man.getGodness();
            if (godness != null){
                return godness.getName();
            }else{
                return "我心中没有女神";
            }
        }else {
            return "男人为空";
        }
    }


一个man类,有一个成员变量女神,女神也是一个类,有一个成员变量,名字。要获取man心中的女神,为了防止控制针异常,要做很多的判断。如果使用Optional呢?做法如下:

//新男人类
@Data
public class NewMan {
    private Optional<Godness> godness = Optional.empty();
}

//使用optional后的方法
public String getGodnessName2(Optional<NewMan> man){
    return man.orElse(new NewMan())
                .getGodness()
                .orElse(new Godness("我没有女神"))
                .getName();
}


这样就简单多了。


2、重复注解与类型注解:


Java 8 可以使用重复注解和类型注解,如下图:


image.png


总结:


本文说了一些Java 8 的新特性,重点就是lambda表达式和Stream API,可以简化很多操作。肯可能还有些文中未涉及的,在此抛砖引玉,望各位大佬指点!



image.png

相关文章
|
2月前
|
存储 安全 Java
Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
【10月更文挑战第17天】Java Map新玩法:探索HashMap和TreeMap的高级特性,让你的代码更强大!
78 2
|
2月前
|
存储 Java
深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。
【10月更文挑战第16天】本文深入探讨了Java集合框架中的HashSet和TreeSet,解析了两者在元素存储上的无序与有序特性。HashSet基于哈希表实现,添加元素时根据哈希值分布,遍历时顺序不可预测;而TreeSet利用红黑树结构,按自然顺序或自定义顺序存储元素,确保遍历时有序输出。文章还提供了示例代码,帮助读者更好地理解这两种集合类型的使用场景和内部机制。
48 3
|
2月前
|
存储 Java 数据处理
Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位
【10月更文挑战第16天】Java Set接口凭借其独特的“不重复”特性,在集合框架中占据重要地位。本文通过快速去重和高效查找两个案例,展示了Set如何简化数据处理流程,提升代码效率。使用HashSet可轻松实现数据去重,而contains方法则提供了快速查找的功能,彰显了Set在处理大量数据时的优势。
37 2
|
2月前
|
存储 算法 Java
Java Set因其“无重复”特性在集合框架中独树一帜
【10月更文挑战第14天】Java Set因其“无重复”特性在集合框架中独树一帜。本文深入解析Set接口及其主要实现类(如HashSet、TreeSet)如何通过特定的数据结构(哈希表、红黑树)确保元素唯一性,并提供最佳实践建议,包括选择合适的Set实现类和正确实现自定义对象的`hashCode()`与`equals()`方法。
36 3
|
2月前
|
安全 Java API
Java 17新特性让你的代码起飞!
【10月更文挑战第4天】自Java 8发布以来,Java语言经历了多次重大更新,每一次都引入了令人兴奋的新特性,极大地提升了开发效率和代码质量。本文将带你从Java 8一路走到Java 17,探索那些能让你的代码起飞的关键特性。
93 1
|
2月前
|
编解码 Oracle Java
java9到java17的新特性学习--github新项目
本文宣布了一个名为"JavaLearnNote"的新GitHub项目,该项目旨在帮助Java开发者深入理解和掌握从Java 9到Java 17的每个版本的关键新特性,并通过实战演示、社区支持和持续更新来促进学习。
90 3
|
14天前
|
存储 Java 开发者
什么是java的Compact Strings特性,什么情况下使用
Java 9引入了紧凑字符串特性,优化了字符串的内存使用。它通过将字符串从UTF-16字符数组改为字节数组存储,根据内容选择更节省内存的编码方式,通常能节省10%至15%的内存。
|
24天前
|
存储 Java 数据挖掘
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
40 6
|
1月前
|
分布式计算 Java API
Java 8引入了流处理和函数式编程两大新特性
Java 8引入了流处理和函数式编程两大新特性。流处理提供了一种声明式的数据处理方式,使代码更简洁易读;函数式编程通过Lambda表达式和函数式接口,简化了代码书写,提高了灵活性。此外,Java 8还引入了Optional类、新的日期时间API等,进一步增强了编程能力。这些新特性使开发者能够编写更高效、更清晰的代码。
33 4
|
2月前
|
存储 Java API
优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。
【10月更文挑战第19天】本文介绍了如何优雅地使用Java Map,通过掌握其高级特性和技巧,让代码更简洁。内容包括Map的初始化、使用Stream API处理Map、利用merge方法、使用ComputeIfAbsent和ComputeIfPresent,以及Map的默认方法。这些技巧不仅提高了代码的可读性和维护性,还提升了开发效率。
99 3