java1.8新特性

Posted 夏芷雨涵梦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java1.8新特性相关的知识,希望对你有一定的参考价值。

java1.8新特性

  1. Lambda表达式
  2. 方法引用
  3. Stream API
  4. 新时间日期API
    Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本。 Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 javascript 引擎,新的日期 API,新的Stream API 等。
  • Lambda 表达式 − Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
  • 方法引用 − 方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
  • 默认方法 − 默认方法就是一个在接口里面有了一个实现的方法。
  • Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。
  • Date Time API − 加强对日期与时间的处理。
  • Optional 类 − Optional 类已经成为 Java 8 类库的一部分,用来解决空指针异常。
  • Nashorn, JavaScript 引擎 − Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。

lambda表达式

Lambda表达式可以看成是匿名内部类,Lambda允许把函数作为一个方法的参数(函数作为方法的参数),将代码像数据一样传递,使用Lambda表达式可以使代码变得更加简洁紧凑。

使用lambda表达式的注意事项
左侧是参数->右侧是方法体
形参列表的数据类型会自动推断
如果形参列表为空只需保留()
如果只有一个参数,可以将()省略,
如果执行语句只有一句,且无返回值,可以省略,若有返回值,想省略则必须同时省略return,且执行语句也保证只有一句
lambda不会单独生成一个内部类文件
lambda表达式若访问了局部变量,则局部变量必须是final的,若是局部变量没有加final关键字,那么系统会自用加,以后再修改局部变量会报错
函数式接口

如果一个接口只有一个抽象方法,则该接口称为函数式接口,函数式接口可以使用lambda表达式,lambda表达式会被匹配带这个抽象方法上。

为了确保你的每一个接口一定达到这个要求,你只需在接口是上添加@Functionallnterface注解,编译器会自动为你检查,多于一个抽象方法会报错。

函数式接口参数类型返回类型说明
Consumer 消费型接口Tvoidvoid accept(T t);对类型为T的对象应用操作
Supplier 供给型接口TT get(); 返回类型为T的对象
Function<T,R> 函数型接口TRR apply(T t);对类型为T的对象应用操作,并返回类型为R类型的对象。
Predicate 断言型接口Tbooleanboolean test(T t);确定类型为T的对象是否满足条件,并返回boolean类型。
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/*
 * created by 夏晓林 in 2019/8/21/021 at 8:09
 * lambda表达式的应用(四个核心函数式接口)
 * Consumer<T>消费型接口  有参数没有返回值
 * Supplier<T>供给型接口  没有参数有返回值
 * Function<T,R>函数型接口  参数是T返回值是R
 * Predicate<T>断言型接口  有参数,返回值是boolean型
 */
public class Demo2 
    public static void main(String[] args) 
        happy(1000,
                m-> System.out.println("吃烤全羊消费"+m)
        );
        happy(1000,m->System.out.print("消费"+m));
        List<Integer> nums=getNumbers(10,
            ()-> new Random().nextInt(100)
        );
        for (Integer num : nums) 
            System.out.println(num);
        
        System.out.println(stringOpe("hello",
                s-> s.toUpperCase()));
        System.out.println(stringOpe("Wo", s->s.toLowerCase()));

        List<String> names=new ArrayList<>();
        names.add("张三");
        names.add("李四");
        names.add("王五");
        names.add("赵六");
        List<String> list=filterString(names,
                s-> s.startsWith("张"));
        List<String> list1=filterString(names,s->s.equals("张三"));
        for (String s : list1) 
            System.out.println(s);
        
    


    //消费性接口
    public static void happy(double money, Consumer<Double> consumer)
        consumer.accept(money);
    

    //供给型接口
    public static List<Integer> getNumbers(int count, Supplier<Integer> supplier)
        List<Integer> list=new ArrayList<>();
        for (int i = 0; i <count ; i++) 
            list.add(supplier.get());
        
        return list;
    

    //函数式接口
    public static String stringOpe(String s, Function<String,String> function)
        return function.apply(s);
    

    //断言型接口
    public static List<String> filterString(List<String> list, Predicate<String> predicate)
        List<String> list1=new ArrayList<>();
        for (String s : list) 
            if(predicate.test(s))
                list1.add(s);
            
        
        return list1;
    



方法引用

方法引用是lambda的一种简写方式。如果lambda表达式只是调用一个特定的已经存在的方法,则可以使用方法引用

  • 对象::实例方法
  • 类::静态方法
  • 类::实例方法
  • 类::new
import java.util.Comparator;
import java.util.TreeSet;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Supplier;

/*
 * created by 夏晓林 in 2019/8/21/021 at 22:21
 * 方法引用:如果lambda表达式方法体中只是调用一个特定的已经存在的方法,则可以使用方法引用
 * 对象::实例方法
 * 类::静态方法
 * 类::实例方法
 * 类::new
 *
 */
public class Demo3 
    public static void main(String[] args) 
        //方法引用 对象::方法名
        Consumer<String> con=s-> System.out.println(s);
        //等价于
        Consumer<String> con1=System.out::println;
        con.accept("hello");
        con1.accept("world");

        //类名::静态方法
        Comparator<Integer> comparator=(x,y)->Integer.compare(x, y);
        Comparator<Integer> comparator1=Integer::compare;
        TreeSet<Integer> treeSet=new TreeSet<>(comparator1);

        //类名::实例方法名
        BiPredicate<String,String> bpre=(x,y)->x.equals(y);
        BiPredicate<String,String> bpre1=String::equals;

        //构造方法引用:
//        Supplier<Employee> sup3=()->new Employee();
//        Supplier<Employee> sup4=Employee::new;
    


理解Stream API

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

Stream API特点:
	Stream 自己不会存储元素
	Stream不会改变原对象,相反,他们会返回一个持有结果的新Stream
	Stream操作时延迟执行的,这意味着他们会等到需要结果的时候才会执行
Stream遵循“做什么而不是怎么去做”的原则。只需要描述需要做什么,而不用考虑程序是怎么实现的。

使用Stream的三个步骤:

  • 创建一个Stream(创建)
  • 在一个或者是多个步骤中,将初始化Stream转化到另一个Stream的中间操作(中间操作)
  • 使用一个终止操作来产生一个结果。该操作会强制他之前的延迟操作立即执行。在这之后,该Stream就不会再被使用了。(终止操作)

Stream的中间操作:

包括:map、filter、distinct、sorted、peek、limit、skip、parallel、sequential、unordered

多个中间操作形成了一个流水线,除非流水线上触发终止操作,否则中间操作不会被执行的,而在终止操作时一次性全部处理,称为“惰性求值”

终止操作:

forEach forEachOrdered toArray rreduce collect min max count anyMatch allMatch noneMatch findFirst findAny iterator

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/*
 * created by 夏晓林 in 2019/8/22/022 at 11:23
 */
public class Demo5 
    /*public static void main(String[] args) 
        //Stream的创建方法
        //Stream.of方法
        Stream stream=Stream.of("a","b","c");
        //Arrays.stream方法
        String[] arr=new String[]"a","b","c";
        stream =Stream.of(arr);
        stream= Arrays.stream(arr);
        //集合方法
        List<String> list=Arrays.asList(arr);
        stream=list.stream();
        stream=list.parallelStream();//并行流
        //创建无限流
        //迭代
        Stream<Integer> stream1=Stream.iterate(0, x->x+2);
        stream1.limit(10).forEach(System.out::println);
        //生成
        Stream<Double>stream2=Stream.generate(()->Math.random());
        stream2.limit(5).forEach(System.out::println);
    */


    public static void main(String[] args) 
        List<Employee> employees=new ArrayList<>();
        employees.add(new Employee("xxx",30,1000,"男"));
        employees.add(new Employee("yyy",20,3000,"女"));
        employees.add(new Employee("zzz",23,1200,"女"));
        employees.add(new Employee("张三",42,2000,"男"));
        employees.add(new Employee("李四",19,1900,"男"));
        employees.add(new Employee("李四",19,1900,"男"));

        //筛选和切片
        System.out.println("--------filter排除------");
        Stream<Employee> stream=employees.stream()
                .filter(e->e.getAge()>25);
        stream.forEach(System.out::println);
        System.out.println("---------limit限制个数-----------");
        Stream<Employee> stream1=employees.stream().limit(3);
        stream1.forEach(System.out::println);
        System.out.println("---------skip跳过元素,返回一个扔掉了前n个元素的流-----------");
        Stream<Employee> stream3=employees.stream().skip(2);
        stream3.forEach(System.out::println);
        System.out.println("---------distinct筛选通过流所生成元素的equals()去除重复元素-----------");
        Stream<Employee> stream4=employees.stream().distinct();
        stream4.forEach(System.out::println);

        //映射map--接收Lambda
        //将元素转换为其他形式或提取信息。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素
        System.out.println("-------获取员工姓名--------");
        Stream<String> str=employees.stream().map(e->e.getName());
        str.forEach(System.out::println);
        System.out.println("------转换为大写-------");
        List<String> list=Arrays.asList("aaa","bbb","ccc","ddd");
        Stream<String> stream2=list.stream().map(String::toUpperCase);
        stream2.forEach(System.out::println);
        //排序
        /*
        * sorted()---自然排序
        * sorted(Comparator com)----定制排序
        * */
        System.out.println("------sorted()自然排序--------");
        employees.stream().map(Employee::getName)
                .sorted()
                .forEach(System.out::println);
        System.out.println("定制排序");
        employees.stream().sorted((x,y)-> 
                if(x.getAge()==y.getAge())
                    return x.getName().compareTo(y.getName());
                else
                    return Integer.compare(x.getAge(),y.getAge() );
                
            
        ).forEach(System.out::println);
        //
        System.out.println("---------foreach------------");
        employees.stream().forEach(System.out::println);
        /*
        * allMatch---检查是否匹配所有元素
        * anyMatch---检查是否至少匹配一个元素
        * noneMatch---检查是否没有匹配的元素
        *findFirst---返回第一个元素
        * findAny----返回当前流中的任意元素,默认是第一个
        * count----返回流中元素的总个数
        * max----返回流中的最大值
        * min----返回流中最小值
        * */
        boolean b = employees.stream().allMatch(e -> e.getSex().equals("男"));
        boolean b1=employees.stream().anyMatch(e->e.getSex().equals("女"));
        boolean b2=employees.stream().noneMatch(e->e.getSex().equals("男"));//没有匹配的元素返回true
        System.out.println(b);
        System.out.println(b1);
        System.out.println(b2);
        Optional<Employee> first = employees.stream().findFirst();
        Optional<Employee> any = employees.stream().findAny();
        System.out.println(first.get());
        System.out.println(any.get());
        Optional<Employee> max=employees.stream().max((o1,o2)->o1.getAge()-o2.getAge());
        System.out.println(max.get());
        Optional<Double> min=employees.stream().map(Employee::getSalary).min(Double::compareTo);
        System.out.println(min.get());
        //归纳和收集
        /*
        * reduce归约  reduce(T identity, BinaryOperator)/reduce(BinaryOperator)
        * 可以将流中的元素反复结合起来,得到一个值
        * */
        List<Integer> list1=Arrays.asList(1,2,3,4,5,6,7,8,9,10);
        Integer sum=list1.stream().reduce(0,(x,y)->x+y );//第一个参数是初始值,第二个运算法则
        System.out.println(sum);
        System.out.println("--------------------");
        Optional<Double> op = employees.stream().map(Employee::getSalary).reduce(Double::sum);
        System.out.println(op.get());
        /*
        * collect---将流转换为其他形式,接收一个Collector接口的实现,用于给Stream中的元素做汇总的方法
        *
        * */
        List<String> list2 = employees.stream().map(Employee::getName).collect(Collectors.toList());
        list2.forEach(System.out::println);
        System.out.println("--------Set集合----------");
        Set<String> set = employees.stream().map(Employee::getName).collect(Collectors.toSet());
        set.forEach(System.out::println);
    




理解新时间日期API

旧版时间API存在的问题:

  • 非线程安全—java.util.Date是非线程安全的,所有日期类都是可变的,这是java日期类最大的问题之一
  • 设计差—java的日期时间类的定义不一致,在util和sql包中都有日期类,此处用于格式化和解析的类在java.text包中定义。java.util.Date同时含有日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包中并不合理。另外这两个类具有相同的名字,本身就是一个很糟糕的设计
  • 时区处理麻烦–日期类并不提供国际化,没有时区支持,因此java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题

java8在java.time包中提供了很多新的API,以下为两个比较重要的API:

  • Local(本地)简化了日期时间的处理,没有时区的问题
  • Zoneld(时区)通过定制的时区处理日期时间

LocalDate/LocalTime 和 LocalDateTime 类可以在处理时区不是必须的情况。

LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日 历系统的日期、时间 、日期和时间。它们提供了简单的日期或时间,不包含与时区相关的信息。

Instant 时间戳 类似以前的Date、Timestamp

​ 它是以Unix元年(传统 的设定为UTC时区1970年1月1日午夜时分)开始 所经历的描述进行运算

TemporalAdjuster : 时间校正器。有时我们可能需要获 取例如:将日期调整到“下个周日”等操作。
TemporalAdjusters : 该类通过静态方法提供了大量的常 用 TemporalAdjuster 的实现。

java.time.format.DateTimeFormatter 类:该类提供了三种 格式化方法:
预定义的标准格式
语言环境相关的格式
自定义的格式

import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

/*
 * created by 夏晓林 in 2019/8/22/022 at 15:33
 */
public class Demo7 
    /*public static void main(String[] args) 
        //当前时间
        LocalDateTime ldt=LocalDateTime.now();
        System.out.println(ldt);
        //其他时间
        LocalDateTime ldt2=LocalDateTime.of(2012,10,1,2,3,4);
        System.out.println(ldt2);
        //加时间
        LocalDateTime ldt3=ldt2.plusDays(2);
        System.out.println(ldt3);
        //减时间
        LocalDateTime ldt4=ldt3.minusDays(2);
        System.out.println(ldt4);
        //获取时间部分
        System.out.println(ldt.getYear());
        System.out.println(ldt.getMonthValue());
        System.out.println(ldt.getDayOfMonth());
        System.out.println(ldt.getHour());
        System.out.println(ldt.getMinute());
        System.out.println(ldt.getSecond());


    */
    public static void main(String[] args) throws Exception
        //时间戳
        Instant instant=Instant.now();
        System.out.println(instant);
        Thread.sleep(1000);
        Instant instant1=Instant.now();
        long mills= Duration.between(instant, instant1).toMillis();
        System.out.println(mills);
        //时区
        System.out.println(ZoneId.getAvailableZoneIds());
        ZoneId zoneId=ZoneId.of("Europe/Berlin");
        ZoneId zoneId2=ZoneId.of("Brazil/East");
        System.out.println(zoneId.getRules());
        System.out.println(zoneId2.getRules());
        System.out.println("-----------Date--Instant---LocalDateTime-------");
        Date date=new Date();
        Instant instant2=date.toInstant();
        LocalDateTime localDateTime = instant2.atZone(ZoneId.systemDefault()).toLocalDateTime();
        System.out.println(localDateTime);
        System.out.println("--------LocalDateTime---Instant----Date--------");
        Instant instant3 = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
        Date date1 = Date.from(instant3);
        System.out.println(date1);

    


以上是关于java1.8新特性的主要内容,如果未能解决你的问题,请参考以下文章

java1.8新特性

java1.8新特性

java1.8新特性(三 关于 ::的用法)

java1.8新特性(optional 使用)

Java1.8新特性

java1.8 新特性(关于 match,find reduce )操作