二、JDK8新特性

二、JDK8新特性


新特性如下:

  • 函数式接口
  • Lambda 表达式
  • 集合的流式操作
  • 注解
  • 安全性
  • IO/NIO
  • 全球化功能

1、函数式编程

函数式编程并不是Java新提出的概念,其与指令编程相比,强调函数的计算比指令的计算更重要;与过程化编程相比,其中函数的计算可以随时调用。
在这里插入图片描述

1.1 接口的默认方法(Default Methods for Interfaces)

接口可以定义静态属性(常量)和静态方法和抽象方法,接口不能直接实例化(new),静态方法和静态属性属于类,普通方法属于实例对象。

public interface Person {
    //1、静态属性
    public static final String state = "已审核";
    //2、静态方法
    public static void play(){
        System.out.println("play");
    }
    //3、抽象方法
    void say();
}

Java 8使我们能够通过使用 default 关键字向接口添加非抽象方法实现,此功能也称作虚拟扩展方法。

public interface Person {
    void say();//抽象方法
    //默认方法
    default  void play(){
        System.out.println("play");
    }
    //默认方法
    default void eat(){
        System.out.println("eat");
    }
}

方法调用:

public class Tom implements Person {
    @Override
    public void say() {
        System.out.println("say");
    }

    public static void main(String[] args) {
       Person p = new Tom();
       p.eat();
       p.play();
       p.say();
        
     //匿名内部类   
       Person p2 = new Person() {
            @Override
            public void say() {
                System.out.println("匿名内部类");
            }
        };
        p2.say();
        p2.play();
        p2.eat();
        
    }
}

不管是抽象类还是接口,都可以通过匿名内部类的方式访问。不能通过抽象类或者接口直接创 建对象。对于上面通过匿名内部类方式访问接口,可以这样理解:一个内部类实现了接口里的抽象方法并且返回一个内部类对象,之后让接口的引用来指向这个对象。

1.2 函数式接口

**“函数式接口”指仅仅只包含一个抽象方法,但是可以有多个非抽象方法(也就是默认方法)的接口。**关于接口的变动,与其他接口的区别就是:

  • 函数式接口中只能有一个抽象方法(我们在这里不包括与Object的方法重名的方法);
  • 可以有从Object继承过来的抽象方法,因为所有类的最终父类都是Object;
  • 接口中唯一抽象方法的命名并不重要,因为函数式接口就是对某一行为进行抽象,主要目的就是支持Lambda表达式。

Java 8增加了一种特殊的注解 @FunctionalInterface ,但是这个注解通常不是必须的(某些情况建议使 用),只要接口只包含一个抽象方法,虚拟机会自动判断该接口为函数式接口。一般建议在接口上使用 @FunctionalInterface 注解进行声明,这样的话,编译器如果发现你标注了这个注解的接口有多于 一个抽象方法的时候会报错的。

@FunctionalInterface
public interface Person {
    void say();//抽象方法
    //可以有多个默认方法
}
1.3 Lambda表达式
//函数式接口
@FunctionalInterface
public interface Person {
    String say(String msg);//抽象方法
}
public class Tom  {
    public static void tomSay(Person p){
        String helloJerry = p.say("hello jerry");
        System.out.println(helloJerry);
    }
    public static void main(String[] args) {
/**
 * 等价
 *         Tom.tomSay(new Person() {
 *             @Override
 *             public String say(String msg) {
 *                 return "jerry say: "+msg;
 *             }
 *         });
 */
           Tom.tomSay(msg ->"jerry say:"+msg );//lambda表达式
    }
}

函数式编程调用外部局部变量,建议加上final,外部局部变量不可变。

1.4 内置的函数式接口

内置常用函数式接口
在这里插入图片描述

1.4.1 Predicates

Predicate 接口是只有一个参数的返回布尔类型值的 断言型 接口。该接口包含多种默认方法来将 Predicate 组合成其他复杂的逻辑(比如:与,或,非),该方法是接受一个传入类型,返回一个布尔值,此方法应用于判断。

1.4.2 Functions

Function 接口接受一个参数并生成结果。默认方法可用于将多个函数链接在一起(compose, andThen):

public class Tom  {
    public static void tomSay(Function<String,String> function, String msg){
        System.out.println(function.apply(msg));

    }
    public static void main(String[] args) {
      Tom.tomSay(s-> "转化了"+s,"jerry");

        /**
         * 等价于静态内部类
         * Tom.tomSay(new Jerry(),"jerry");
         *     }
         * //    静态内部类
         *     private static class Jerry implements Function<String,String> {
         *         @Override
         *         public String apply(String s) {
         *             return "转化了"+s;
         *         }
         */

        /**
         * 等价于匿名内部类
         *       Tom.tomSay(new Function<String, String>() {
         *           @Override
         *           public String apply(String s) {
         *               return "转化了"+s;
         *           }
         *       },"jerry");
         */
    }
}
1.4.3 Suppliers

Supplier 接口产生给定泛型类型的结果。 与 Function 接口不同,Supplier 接口不接受参数。

1.4.4 Consumers

Consumer 接口表示要对单个输入参数执行的操作。

public class Tom  {
    public static void tomSay(Consumer<String> consumer,String msg){
        consumer.accept(msg);

    }
    public static void main(String[] args) {
        Tom.tomSay(msg-> System.out.println("消费了"+msg),"jerry");
        /**
         * 等价于
         *        Tom.tomSay(new Consumer<String>() {
         *             @Override
         *             public void accept(String msg) {
         *                 System.out.println("消费了"+msg);
         *             }
         *         },"jerry");
         */
    }
}
1.4.5 Comparators

Comparator 是老Java中的经典接口, Java 8在此之上添加了多种默认方法:

2、Stream

2.1 基本概念

java.util.Stream 表示能应用在一组元素上一次执行的操作序列。Stream 操作分为中间操作或者最 终操作两种,最终操作返回一特定类型的计算结果,而中间操作返回Stream本身,这样你就可以将多 个操作依次串起来。Stream 的创建需要指定一个数据源,比如 java.util.Collection 的子类,List 或者 Set, Map 不支持。Stream 的操作可以串行执行或者并行执行。

Stream VS List

  • Stream 可以是无限的
  • Stream可并行处理
  • Stream可能延迟处理
2.2 基本操作

Filter(过滤): 过滤通过一个predicate接口来过滤并只保留符合条件的元素,该操作属于中间操作,所以我们可以在 过滤后的结果来应用其他Stream操作(比如forEach)。forEach需要一个函数来对过滤后的元素依次 执行。

Sorted(排序): 排序是一个 中间操作,返回的是排序好后的 Stream。如果你不指定一个自定义的 Comparator 则会 使用默认排序。

Sorted(排序): 排序是一个 中间操作,返回的是排序好后的 Stream。如果你不指定一个自定义的 Comparator 则会 使用默认排序。

Match(匹配): Stream提供了多种匹配操作,允许检测指定的Predicate是否匹配整个Stream。所有的匹配操作都是 最 终操作 ,并返回一个 boolean 类型的值。

Count(计数): 计数是一个 最终操作,返回Stream中元素的个数,返回值类型是 long。

Reduce(规约): 这是一个 最终操作 ,允许通过指定的函数来讲stream中的多个元素规约为一个元素

在这里插入图片描述

2.3 实例
public class Tom  {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 21, 12, 4, 5, 78, 12, 23);
//        Optional<Integer> reduce =
        list.stream()
                .map(item -> item * 10)//映射:每个数扩大三倍
                .filter(item -> item > 30)//过滤:保留大于30的数字
                .sorted((num1, num2) -> num1 - num2)//排序:由小到大
                .distinct()//去重
//                .reduce((num1, num2) -> num1 + num2);//规约:总和
//        System.out.println(reduce.get());
                .forEach(System.out::println);
    }
public class Tom  {
    public static void main(String[] args) {
     List<Person> people = Arrays.asList(
             new Person("tom",12,175),
             new Person("jerry",12,176),
             new Person("kitty",18,175),
             new Person("david",19,175),
             new Person("lucy",10,175)

     );
//        List<Person> collect = people.stream()
//                .filter(p -> p.getAge() > 12)//筛选
//                .sorted((p1,p2)->p1.getAge()-p2.getAge())
//                .collect(Collectors.toList());
//        System.out.println(collect);

//        people.sort((p1,p2)->p1.getAge()-p2.getAge());
//        people.sort(Comparator.comparing(p->p.getAge()));
        people.sort(Comparator.comparing(Person::getAge).reversed().thenComparing(Person::getHeight));

        people.forEach(System.out::println);

    }
}
2.4 并行流

Stream有串行和并行两种,串行Stream上的操作是在一个线程中依次完成,而并行Stream 则是在多个线程上同时执行。

下面的例子展示了是如何通过并行Stream来提升性能:

public class test {
    public static void main(String[] args) {
        List<Double> nums= new ArrayList<>();
//        随机生成10000000个数字,进行排序
        for (int i=0;i<10000000;i++){
            double random = Math.random();
            nums.add(random);
        }
//        串行流
        Long start = System.currentTimeMillis();
        List<Double> collect = nums.stream().sorted().collect(Collectors.toList());
        Long end = System.currentTimeMillis();
        System.out.println(end-start);
        System.out.println("-----------------------------");

//        并行流
        Long start1 = System.currentTimeMillis();
        List<Double> collect1 = nums.parallelStream().sorted().collect(Collectors.toList());
        Long end1 = System.currentTimeMillis();
        System.out.println(end1-start1);
    }
}

执行结果:

在这里插入图片描述

3、Date API(日期相关API)

3.1 Clock

Clock 类提供了访问当前日期和时间的方法,Clock 是时区敏感的,可以用来取代 System.currentTimeMillis() 来获取当前的微秒数。某一个特定的时间点也可以使用 Instant 类 来表示, Instant 类也可以用来创建旧版本的 java.util.Date 对象。

3.2 Timezones(时区)

在新API中时区使用 ZoneId 来表示。时区可以很方便的使用静态方法of来获取到。 抽象类 ZoneId (在 java.time 包中)表示一个区域标识符。 它有一个名为 getAvailableZoneIds 的静态 方法,它返回所有区域标识符。

3.3 LocalTime(本地时间)

LocalTime 定义了一个没有时区信息的时间,例如 晚上10点或者 17:30:15。

3.4 LocalDate(本地日期)

LocalDate 表示了一个确切的日期,比如 2014-03-11。该对象值是不可变的,用起来和LocalTime基本 一致。下

3.5 LocalDateTime(本地日期时间)

LocalDateTime 同时表示了时间和日期,相当于前两节内容合并到一个对象上了。LocalDateTime 和 LocalTime还有 LocalDate 一样,都是不可变的。LocalDateTime 提供了一些能访问具体字段的方法。

  public static void main(String[] args) {
//        Clock clock = Clock.systemDefaultZone();
//        System.out.println(clock.getZone());
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String format = now.format(dateTimeFormatter);
        System.out.println(format);
    }

执行结果:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值