栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JDK1.8新特性

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JDK1.8新特性

目录

1.Lambda表达式

2.添加默认方法

3.Stream操作

4.Optional 类

5.Java时间API


Java8(又称为 jdk 1.8) 是 Java 语言开发迄今为止的一个最主要和用户最多的一个版本。Java8是Oracle公司于2014年3月18日发布 ,它不仅支持函数式编程,而且还拥有新的日期 API,Stream API 等操作,下面胖虎带领大家一探究竟Java 8的一些新特性。

1.Lambda表达式

Lambda 允许把函数作为一个方法的参数,使用Lambda表达式可以使代码变的更加简洁紧凑、简洁表达。

lambda表达式的语法:

(parameters) -> expression
或
(parameters) ->{ statements; }

(x)->{system.out.prinln} //直接打印x参数; 

lambda表达式简单例子:

public class Java8TestLambda {

    public static  void main(String [] args){
        CacualtePriceService cacualteAddPriceService=(x1,x2)->(x1+x2);
        CacualtePriceService cacualteSubPriceService=(x1,x2)->(x1-x2)
        
        System.out.println(cacualteAddPriceService.cacluatePrice(1.2f,2.2f));//3.4
        System.out.println(cacualteSubPriceService.cacluatePrice(3.2f,1.2f));//2.0
        System.out.println("------------------使用策略模式----------------------");
        System.out.println(operate(1.2f,2.2f,(x1,x2)->(x1+x2)));//3.4
        System.out.println(operate(3.2f,1.2f,(x1,x2)->(x1-x2)));//2.0
    }
    
    interface CacualtePriceService{
        Float cacluatePrice(Float x1,Float x3);
    }

    static Float operate(float x1, float x2, CacualtePriceService cacualtePriceService){
       return cacualtePriceService.cacluatePrice(x1,x2);
    }
}

打印结果:

3.4
2.0
------------------使用策略模式----------------------
3.4
2.0

由上面的例子可知,Lambda可以简化函数接口(接口中只有一个方法,例如上述例子中CacualtePriceService接口)的实现方法。

lambda表达式的重要特征:

可选类型声明:不需要声明参数类型,编译器可以统一识别参数值((x1,x2))。可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。可选的大括号:如果函数主体包含了一个语句,就不需要使用大括号。可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回一个数值。lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义,详细见如下案例)

  // static final float num=1.1f;
    public static  void main(String [] args){
        float num=1.1f;
        CacualtePriceService cacualteAddPriceService=(x1,x2)->(x1+x2+num);
        CacualtePriceService cacualteSubPriceService=(x1,x2)->(x1-x2+num);
        num=2;

    }
console://当修改num=2 时候会报错:
Error:(14, 70) java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量

当修改num=2 时候会报错:从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量。

2.添加默认方法

java 8添加了接口的默认方法,简单说,默认方法就是接口可以有实现方法,而且不需要实现类去实现的方法。

我们只需在方法名前面加个 default 关键字即为默认方法。

为什么要有这个特性?

之前的接口,当需要修改接口时候,需要修改全部实现该接口的类,然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法,目的是为了解决接口的修改与现有的实现不兼容的问题。

默认方法案例如下:

public class DafaultMethod {

    interface Car {
        static void staticRun() {
            System.out.println("测试汽车静态接口");
        }
        default void defaultRun() {
            System.out.println("测试汽车默认接口");
        }
        void run();
    }
    static class QicheCar implements Car {

        @Override
        public void run() {
            System.out.println("测试汽车实现接口");
            defaultRun();
            Car.staticRun();
        }
    }
    public static void main(String[] args) {
        QicheCar car = new QicheCar();
        car.run();
    }
}

输出内容:

测试汽车实现接口
测试汽车默认接口
测试汽车静态接口

由上述案例可知,接口直接可以调用静态方法以及默认方法。

3.Stream操作

(1)Stream基本操作

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选,排序,聚合等操作。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。Java中的Stream并不会存储元素,而是按需计算。

数据源中流的来源 可以是集合,数组,I/O channel, 产生器generator 等。

stream的filter过滤操作

List strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());//过滤不为空的元素组成一个新的list,结果为["abc", "bc", "efg", "abcd", "jkl"]

stream的foreach过滤操作

Map foreach
 Map ageMap=new HashMap<>();
        ageMap.put("胖虎",4);
        ageMap.put("二蛋",5);
        ageMap.put("富贵",6);
        ageMap.forEach((name,age)->{System.out.println("名字:"+name+", 年龄:"+age);});

输出:
名字:富贵, 年龄:6
名字:二蛋, 年龄:5
名字:胖虎, 年龄:4

随机数 foreach
Random random = new Random();
random.ints().limit(10).forEach(System.out::println);//输出10个随机数

List name = Arrays.asList("胖虎", "二蛋", "富贵");
name.forEach((catName)->{System.out.println(catName);});//"胖虎", "二蛋", "富贵"

System.out.println("---------------------------------");//"胖虎", "二蛋", "富贵"
name.forEach(System.out::println);

胖虎
二蛋
富贵
---------------------------------
胖虎
二蛋
富贵

map操作

方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:

List numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
// 获取对应的平方数
List squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());

limit操作

limit 方法用于获取指定数量的流。 以下代码片段使用 limit 方法打印出 10 条数据:

Random random = new Random();
random.ints().limit(10).forEach(System.out::println);

sorted操作

sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:

Random random = new Random();
random.ints().limit(10).sorted().forEach(System.out::println);

Collectors操作

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。

Collectors 可用于返回列表或字符串:

Liststrings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
List filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
 
System.out.println("筛选列表: " + filtered);//["abc", "", "bc", "efg", "abcd","", "jkl"]
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);//abc,bc,efg,abcd,jkl

另外,一些产生统计结果的收集器也非常有用,主要用于int、double、long等基本类型上,可以用来产生类似如下的统计结果。

List numbers = Arrays.asList(3.2, 2.3, 2.3, 3.1, 7.4, 3.4, 5.0);
DoubleSummaryStatistics SummaryStatistic  = numbers.stream().mapToDouble((x) -> x).summaryStatistics();
// IntSummaryStatistics SummaryStatistic  = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("列表中最大的数 : " + SummaryStatistic.getMax());
System.out.println("列表中最小的数 : " + SummaryStatistic.getMin());
System.out.println("所有数之和 : " + SummaryStatistic.getSum());
System.out.println("平均数 : " + SummaryStatistic.getAverage());
        
列表中最大的数 : 7.4
列表中最小的数 : 2.3
所有数之和 : 26.700000000000003
平均数 : 3.8142857142857145

(2)Stream的创建

Collection 提供了两个方法 stream() 与 parallelStream()

List list=new ArrayList<>();
Stream(String) stream=list.stream();
Stream parallelStream=list.parallelStream();

通过 Arrays 中的 stream() 获取一个数组流

Integer[] nums = new Integer[10];
  Stream stream1 = Arrays.stream(nums);

通过 Stream 类中静态方法 of()

 Stream stream2 = Stream.of(1,2,3,4,5,6);

(3)Stream的中间操作

List emps = Arrays.asList(
   new Employee(102, "李四", 59, 6666.66),
   new Employee(101, "张三", 18, 9999.99),
   new Employee(103, "王五", 28, 3333.33),
   new Employee(104, "赵六", 8, 7777.77),
   new Employee(104, "赵六", 8, 7777.77),
   new Employee(104, "赵六", 8, 7777.77),
   new Employee(105, "田七", 38, 5555.55)
 );

筛选与切片

filter——接收 Lambda , 从流中排除某些元素。limit——截断流,使其元素不超过给定数量。skip(n) —— 跳过元素,返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个,则返回一个空流,与 limit(n) 互补。distinct——筛选,通过流所生成元素的 hashCode() 和 equals() 去除重复元素。

//所有的中间操作不会做任何的处理
Stream stream = emps.stream()
 .filter((e) -> {
  System.out.println("测试中间操作");
  return e.getAge() <= 35; //打印小于等于35岁的Employee信息
 });

emps.stream()
 .filter((e) -> {
  return e.getSalary() >= 5000;
 }).limit(3)
 .forEach(System.out::println); //循环打印工资大于等于5000的三条的Employee信息

(4)并行流parallelStream

parallelStream提供了流的并行处理,它是Stream的另一重要特性,其底层使用Fork/Join框架实现,简单理解就是多线程异步任务的一种实现。

List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); 
numbers.parallelStream().forEach(num->System.out.println(num));

输出:3 4 2 6 7 9 8 1 5

使用parallelStream后,结果并不按照集合原有顺序输出。为了进一步证明该操作是并行的,打印出线程信息。

 List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); 
   numbers.parallelStream() .forEach(num-
     >System.out.println(Thread.currentThread().getName()+">>"+num)); 

输出:

main>>6 
ForkJoinPool.commonPool-worker-2>>8 
main>>5 ForkJoinPool.commonPool-worker-2>>9 
ForkJoinPool.commonPool-worker-1>>3 
ForkJoinPool.commonPool-worker-3>>2 
ForkJoinPool.commonPool-worker-1>>1 
ForkJoinPool.commonPool-worker-2>>7 
main>>4

通过以上述案例可以看出,parallelStream是利用多线程进行,可以很大程度简化并发操作。

关于并行流的陷阱,可以参考此文 https://blog.csdn.net/yy1098029419/article/details/89452380

4.Optional 类

Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

    public static void main(String[] args) {
        DafaultMethod java8Tester = new DafaultMethod();
        Integer value1 = null;
        Integer value2 = new Integer(10);

        // Optional.ofNullable - 允许传递为 null 参数
        Optional a = Optional.ofNullable(value1);

        // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
        Optional b = Optional.of(value2);
       // Optional c = Optional.of(value1); //Exception in thread "main" java.lang.NullPointerException
       
        System.out.println(java8Tester.sum(a,b));
    }
    public Integer sum(Optional a, Optional b){

        // Optional.isPresent - 判断值是否存在

        System.out.println("第一个参数值存在: " + a.isPresent());//false
        System.out.println("第二个参数值存在: " + b.isPresent());//true

        // Optional.orElse - 如果值存在,返回它,否则返回默认值
        Integer value1 = a.orElse(new Integer(0));

        //Optional.get - 获取值,值需要存在
        Integer value2 = b.get();
        return value1 + value2;
    }

5.Java时间API

Java 8 在 java.time 包下提供了很多新的 API 。两个比较重要的 API:Local(本地) − 简化了日期时间的处理,没有时区的问题。Zoned(时区) − 通过制定的时区处理日期时间。

具体案例参考如下:

 public void testLocalDateTime(){
        // 获取当前时间
        LocalDateTime ldt = LocalDateTime.now();
        System.out.println(ldt);//2021-06-29T16:27:58.543
        // 获取指定时间
        LocalDateTime ld2 = LocalDateTime.of(2016, 11, 21, 10, 10, 10);
        System.out.println(ld2);//2016-11-21T10:10:10
        // 指定时间后移动2年
        LocalDateTime ldt3 = ld2.plusYears(20);
        System.out.println(ldt3);//2036-11-21T10:10:10
        // 指定时间前移动2月
        LocalDateTime ldt4 = ld2.minusMonths(2);
        System.out.println(ldt4);//2016-09-21T10:10:10

        System.out.println(ldt.getYear());//2021
        System.out.println(ldt.getMonthValue());//6
        System.out.println(ldt.getDayOfMonth());//29
        System.out.println(ldt.getHour());//16
        System.out.println(ldt.getMinute());//27
        System.out.println(ldt.getSecond());//58

        System.out.println("---------------当前时间解析-------------------");

        // 当前时间解析
        LocalDateTime currentTime = LocalDateTime.now();
        System.out.println("当前时间: " + currentTime);//2021-06-29T16:27:58.546

        LocalDate date1 = currentTime.toLocalDate();
        System.out.println("date1: " + date1);// 2021-06-29

        Month month = currentTime.getMonth();
        Integer mon=month.ordinal()+1;
        int day = currentTime.getDayOfMonth();
        int seconds = currentTime.getSecond();

        System.out.println("月: " + month +"/"+mon+", 日: " + day +", 秒: " + seconds);//月: JUNE/6, 日: 29, 秒: 58

        LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
        System.out.println("date2: " + date2);//date2: 2012-06-10T16:27:58.546

        // 12 december 2014
        LocalDate date3 = LocalDate.of(2014, Month.FEBRUARY, 25);
        System.out.println("date3: " + date3);//date3: 2014-02-25

        // 22 小时 15 分钟
        LocalTime date4 = LocalTime.of(22, 15);
        System.out.println("date4: " + date4);//date4: 22:15

        // 解析字符串
        LocalTime date5 = LocalTime.parse("20:15:30");
        System.out.println("date5: " + date5);//date5: 20:15:30
        System.out.println("-------------Instant : 时间戳--------------------");
        // Instant : 时间戳。 (使用 Unix 元年  1970年1月1日 00:00:00 所经历的毫秒值)
        Instant ins = Instant.now();  //默认使用 UTC 时区 比大陆时间提前8小时
        System.out.println("ins"+ins);//ins2021-06-29T08:27:58.578Z

        OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));
        System.out.println("odt"+odt);//odt2021-06-29T16:27:58.578+08:00

        System.out.println("ins.getNano():"+ins.getNano());//ins.getNano():578000000

        Instant ins2 = Instant.ofEpochSecond(5);
        System.out.println("ins2:"+ins2);//ins2:1970-01-01T00:00:05Z


        System.out.println("----------耗费时间统计------------");
        Instant ins1 = Instant.now();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
        }

        Instant ins3 = Instant.now();

        System.out.println("所耗费时间为:" + Duration.between(ins1, ins3));//所耗费时间为:PT1.005S
        
        LocalDate ld3 = LocalDate.now();
        LocalDate ld4 = LocalDate.of(2011, 1, 1);

        Period pe = Period.between(ld4, ld3);
        System.out.println(pe.getYears());//10
        System.out.println(pe.getMonths());//5
        System.out.println(pe.getDays());//28

    }

参考文章:

https://www.runoob.com/

JDK1.8新特性 - 知乎

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/759714.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号