zoukankan      html  css  js  c++  java
  • JDK8新特性

      参考菜鸟教程:https://www.runoob.com/java/java8-new-features.html

    1. 接口默认方法

      Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法;而且允许定义static方法,使用的时候直接类名.方法名即可。

    package com.zd.bx.test;
    
    public interface Interface1 {
    
        /**
         * 抽象方法1
         * 
         * @param str
         */
        void method1(String str);
    
        /**
         * 静态方法
         * 
         * @param str
         */
        public static void method2(String str) {
            System.out.println(str);
        }
    
        default void log(String str) {
            System.out.println("I1 logging::" + str);
        }
    
    }

     

    2. Lambda 表达式

      Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。

    语法如下:

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

    1. 以下是lambda表达式的重要特征:

    可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
    可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
    可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
    可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

    例如:

    package com.zd.bx;
    
    public class MyTest {
    
        public static void main(String args[]) {
            MyTest tester = new MyTest();
    
            // 类型声明
            MathOperation addition = (int a, int b) -> a + b;
    
            // 不用类型声明
            MathOperation subtraction = (a, b) -> a - b;
    
            // 大括号中的返回语句
            MathOperation multiplication = (int a, int b) -> {
                return a * b;
            };
    
            // 没有大括号及返回语句
            MathOperation division = (int a, int b) -> a / b;
    
            System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
            System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
            System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
            System.out.println("10 / 5 = " + tester.operate(10, 5, division));
    
            // 不用括号
            GreetingService greetService1 = message -> System.out.println("Hello " + message);
    
            // 用括号
            GreetingService greetService2 = (message) -> System.out.println("Hello " + message);
    
            greetService1.sayMessage("Runoob");
            greetService2.sayMessage("Google");
        }
    
        interface MathOperation {
            int operation(int a, int b);
        }
    
        interface GreetingService {
            void sayMessage(String message);
        }
    
        private int operate(int a, int b, MathOperation mathOperation) {
            return mathOperation.operation(a, b);
        }
    }

    结果:

    10 + 5 = 15
    10 - 5 = 5
    10 x 5 = 50
    10 / 5 = 2
    Hello Runoob
    Hello Google

    2. 变量作用域:

      lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。

    例如:

    package com.zd.bx;
    
    public class MyTest {
    
        public static void main(String args[]) {
            String salutation = "Hello! ";
    
            GreetingService greetService1 = message -> {
                System.out.println(salutation + message);
                // 不允许修改引用,salutation隐式的被声明为final
                // salutation = "";
            };
            greetService1.sayMessage("Runoob");
        }
    
        interface GreetingService {
            void sayMessage(String message);
        }
    }

    lambda 表达式的局部变量可以不用声明为 final,但是必须不可被后面的代码修改(即隐性的具有 final 的语义)

     

    3.方法引用

    方法引用通过方法的名字来指向一个方法。
    方法引用可以使语言的构造更紧凑简洁,减少冗余代码。
    方法引用使用一对冒号 :: 。

     例如:

    package com.zd.bx;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Supplier;
    
    public class Car {
    
        // Supplier是jdk1.8的接口,这里和lamda一起使用了
        public static Car create(final Supplier<Car> supplier) {
            return supplier.get();
        }
    
        public static void collide(final Car car) {
            System.out.println("Collided " + car.toString());
        }
    
        public void follow(final Car another) {
            System.out.println("Following the " + another.toString());
        }
    
        public void repair() {
            System.out.println("Repaired " + this.toString());
        }
    
        public static void main(String[] args) {
            System.out.println("===1===");
            // 构造器引用:它的语法是Class::new,或者更一般的Class< T >::new
            final Car car = Car.create(Car::new);
            final List<Car> cars = Arrays.asList(car);
    
            System.out.println("===2===");
            // 静态方法引用:它的语法是Class::static_method
            cars.forEach(Car::collide);
    
            System.out.println("===3===");
            // 特定类的任意对象的方法引用:它的语法是Class::method
            cars.forEach(Car::repair);
    
            System.out.println("===4===");
            // 特定对象的方法引用:它的语法是instance::method
            final Car police = Car.create(Car::new);
            cars.forEach(police::follow);
        }
    }

    结果:

    ===1===
    ===2===
    Collided com.zd.bx.Car@3e3abc88
    ===3===
    Repaired com.zd.bx.Car@3e3abc88
    ===4===
    Following the com.zd.bx.Car@3e3abc88

     

    4.函数式接口

      函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 lambda 表达式。Lambda 表达式和方法引用(实际上也可认为是Lambda表达式)上。
    如定义了一个函数式接口如下:

    package com.zd.bx;
    
    @FunctionalInterface
    public interface GreetingService {
        void sayMessage(String message);
        
        default int method2() {
            return 2;
        }
    }

    那么就可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):

            GreetingService greetService1 = message -> System.out.println("Hello " + message);
            greetService1.sayMessage("234");

    函数式接口可以对现有的函数友好地支持 lambda。

    1.JDK8 之前已有的函数式接口

    java.lang.Runnable、java.util.concurrent.Callable、java.util.Comparator等。如:

    @FunctionalInterface
    public interface Runnable {
        public abstract void run();
    }

    2.JDK8提供的函数式接口

      JDK8提供了好几个函数式接口,其中有用的是如下几个:

    1.Consumer<T> 代表了接受一个输入参数并且无返回的操作

    package java.util.function;
    import java.util.Objects;
    
    @FunctionalInterface
    public interface Consumer<T> {
        void accept(T t);
    
        default Consumer<T> andThen(Consumer<? super T> after) {
            Objects.requireNonNull(after);
            return (T t) -> { accept(t); after.accept(t); };
        }
    }

    2. Supplier<T> 无参数,返回一个结果。 代表了接受一个输入参数并且无返回的操作

    package java.util.function;
    
    @FunctionalInterface
    public interface Supplier<T> {
    
        T get();
    }

    3. Predicate<T> 接受一个输入参数,返回一个布尔值结果。

    package java.util.function;
    import java.util.Objects;
    
    @FunctionalInterface
    public interface Predicate<T> {
        boolean test(T t);
    
        default Predicate<T> and(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) && other.test(t);
        }
    
        default Predicate<T> negate() {
            return (t) -> !test(t);
        }
    
        default Predicate<T> or(Predicate<? super T> other) {
            Objects.requireNonNull(other);
            return (t) -> test(t) || other.test(t);
        }
    
        static <T> Predicate<T> isEqual(Object targetRef) {
            return (null == targetRef)
                    ? Objects::isNull
                    : object -> targetRef.equals(object);
        }
    }

    4. Function<T,R> 接受一个输入参数,返回一个结果。

    package java.util.function;
    import java.util.Objects;
    
    @FunctionalInterface
    public interface Function<T, R> {
    
        R apply(T t);
    
        default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
            Objects.requireNonNull(before);
            return (V v) -> apply(before.apply(v));
        }
    
        default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
            Objects.requireNonNull(after);
            return (T t) -> after.apply(apply(t));
        }
    
        static <T> Function<T, T> identity() {
            return t -> t;
        }
    }

    例如:

    package com.zd.bx;
    
    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Predicate;
    
    import lombok.Data;
    
    @Data
    public class Car {
        public static void main(String args[]) {
            List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
    
            // Predicate<Integer> predicate = n -> true
            // n 是一个参数传递到 Predicate 接口的 test 方法
            // n 如果存在则 test 方法返回 true
    
            System.out.println("输出所有数据:");
    
            // 传递参数 n
            eval(list, n -> true);
    
            // Predicate<Integer> predicate1 = n -> n%2 == 0
            // n 是一个参数传递到 Predicate 接口的 test 方法
            // 如果 n%2 为 0 test 方法返回 true
    
            System.out.println("输出所有偶数:");
            eval(list, n -> n % 2 == 0);
    
            // Predicate<Integer> predicate2 = n -> n > 3
            // n 是一个参数传递到 Predicate 接口的 test 方法
            // 如果 n 大于 3 test 方法返回 true
    
            System.out.println("输出大于 3 的所有数字:");
            eval(list, n -> n > 3);
        }
    
        public static void eval(List<Integer> list, Predicate<Integer> predicate) {
            for (Integer n : list) {
                if (predicate.test(n)) {
                    System.out.println(n + " ");
                }
            }
        }
    }

    结果:

    输出所有数据:
    1 
    2 
    3 
    4 
    5 
    6 
    7 
    8 
    9 
    输出所有偶数:
    2 
    4 
    6 
    8 
    输出大于 3 的所有数字:
    4 
    5 
    6 
    7 
    8 
    9 

     

    5. Stream

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

    和以前的Collection操作不同, Stream操作还有两个基础的特征:

    (1)Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。

    (2)内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

    1.生成流

    集合接口有两个方法来生成流:

    stream() − 为集合创建串行流。

    parallelStream() − 为集合创建并行流。

    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
    List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());

    2. forEach

    Stream 提供了新的方法 'forEach' 来迭代流中的每个数据。以下代码片段使用 forEach 输出了10个随机数:

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

    3. map

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

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

    结果:

    [9, 4, 49, 25]

    4. filter

    filter 方法用于通过设置的条件过滤出元素。以下代码片段使用 filter 方法过滤出空字符串:

            List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
            // 获取空字符串的数量
            long count = strings.stream().filter(string -> string.isEmpty()).count();
            System.out.println(count);

    结果:

    2

    5. limit

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

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

    6. sorted

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

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

    7.并行(parallel)程序

    parallelStream 是流并行处理程序的代替方法。以下实例我们使用 parallelStream 来输出空字符串的数量:

            List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd", "", "jkl");
            // 获取空字符串的数量
            int count = (int) strings.parallelStream().filter(string -> string.isEmpty()).count();
            System.out.println(count);

    8. Collectors

    Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串:

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

    结果:

    筛选列表: [abc, bc, efg, abcd, jkl]

    合并字符串: abc, bc, efg, abcd, jkl

    9. 统计

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

            List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
            IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
            System.out.println("列表中最大的数 : " + stats.getMax());
            System.out.println("列表中最小的数 : " + stats.getMin());
            System.out.println("所有数之和 : " + stats.getSum());
            System.out.println("平均数 : " + stats.getAverage());

    6.Optional 类

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

      Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。

      Optional提供很多有用的方法,这样我们就不用显式进行空值检测。Optional 类的引入很好的解决空指针异常。

    例如:

    package com.zd.bx;
    
    import java.util.Optional;
    
    import lombok.Data;
    
    @Data
    public class Car {
        public static void main(String args[]) {
            Car java8Tester = new Car();
            Integer value1 = null;
            Integer value2 = new Integer(10);
    
            // Optional.ofNullable - 允许传递为 null 参数
            Optional<Integer> a = Optional.ofNullable(value1);
    
            // Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
            Optional<Integer> b = Optional.of(value2);
            System.out.println(java8Tester.sum(a, b));
        }
    
        public Integer sum(Optional<Integer> a, Optional<Integer> b) {
    
            // Optional.isPresent - 判断值是否存在
    
            System.out.println("第一个参数值存在: " + a.isPresent());
            System.out.println("第二个参数值存在: " + b.isPresent());
    
            // Optional.orElse - 如果值存在,返回它,否则返回默认值
            Integer value1 = a.orElse(new Integer(0));
    
            // Optional.get - 获取值,值需要存在
            Integer value2 = b.get();
            return value1 + value2;
        }
    }

    结果:

    第一个参数值存在: false

    第二个参数值存在: true

    10

    7. 日期时间 API

    在之前的API中,日期时间API有下列问题:

    (1)非线程安全:java.util.Date 是非线程安全的,所有的日期类都是可变的

    (2)设计上:java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。

    Java 8 在 java.time 包下提供了很多新的 API。以下为两个比较重要的 API:

    (1)Local(本地) − 简化了日期时间的处理,没有时区的问题。

    package com.zd.bx;
    
    import java.time.LocalDate;
    import java.time.LocalDateTime;
    import java.time.LocalTime;
    import java.time.Month;
    
    import lombok.Data;
    
    @Data
    public class Car {
        public static void main(String args[]) {
            Car java8tester = new Car();
            java8tester.testLocalDateTime();
        }
    
        public void testLocalDateTime() {
            // 获取当前的日期时间
            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);
    
            LocalDateTime date2 = currentTime.withDayOfMonth(10).withYear(2012);
            System.out.println("date2: " + date2);
    
            // 12 december 2014
            LocalDate date3 = LocalDate.of(2014, Month.DECEMBER, 12);
            System.out.println("date3: " + date3);
    
            // 22 小时 15 分钟
            LocalTime date4 = LocalTime.of(22, 15);
            System.out.println("date4: " + date4);
    
            // 解析字符串
            LocalTime date5 = LocalTime.parse("20:15:30");
            System.out.println("date5: " + date5);
        }
    }

    结果:

    当前时间: 2020-07-16T22:58:21.163

    date1: 2020-07-16

    月: JULY, 日: 16, 秒: 21

    date2: 2012-07-10T22:58:21.163

    date3: 2014-12-12

    date4: 22:15

    date5: 20:15:30

    (2)Zoned(时区) − 通过制定的时区处理日期时间。

    package com.zd.bx;
    
    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    
    import lombok.Data;
    
    @Data
    public class Car {
        public static void main(String args[]) {
            Car java8tester = new Car();
            java8tester.testZonedDateTime();
        }
    
        public void testZonedDateTime() {
    
            // 获取当前时间日期
            ZonedDateTime date1 = ZonedDateTime.parse("2015-12-03T10:15:30+05:30[Asia/Shanghai]");
            System.out.println("date1: " + date1);
    
            ZoneId id = ZoneId.of("Europe/Paris");
            System.out.println("ZoneId: " + id);
    
            ZoneId currentZone = ZoneId.systemDefault();
            System.out.println("当期时区: " + currentZone);
        }
    }

    8.  Base64

      在Java 8中,Base64编码已经成为Java类库的标准。Java 8 内置了 Base64 编码的编码器和解码器。

    例如:

    package com.zd.bx;
    
    import java.io.UnsupportedEncodingException;
    import java.util.Base64;
    import java.util.UUID;
    
    public class Car {
        public static void main(String args[]) {
            try {
    
                // 使用基本编码
                String base64encodedString = Base64.getEncoder().encodeToString("runoob?java8".getBytes("utf-8"));
                System.out.println("Base64 编码字符串 (基本) :" + base64encodedString);
    
                // 解码
                byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
    
                System.out.println("原始字符串: " + new String(base64decodedBytes, "utf-8"));
                base64encodedString = Base64.getUrlEncoder().encodeToString("runoob?java8".getBytes("utf-8"));
                System.out.println("Base64 编码字符串 (URL) :" + base64encodedString);
    
                StringBuilder stringBuilder = new StringBuilder();
    
                for (int i = 0; i < 10; ++i) {
                    stringBuilder.append(UUID.randomUUID().toString());
                }
    
                byte[] mimeBytes = stringBuilder.toString().getBytes("utf-8");
                String mimeEncodedString = Base64.getMimeEncoder().encodeToString(mimeBytes);
                System.out.println("Base64 编码字符串 (MIME) :" + mimeEncodedString);
    
            } catch (UnsupportedEncodingException e) {
                System.out.println("Error :" + e.getMessage());
            }
        }
    }
  • 相关阅读:
    SlimDX.dll安装之后所在位置
    使用正则表达式进行简单查找
    UDP-C#代码
    非Unicode工程读取Unicode文件
    模板类重载<<运算符
    ganglia及ganglia-api相关介绍
    keystone v3 相关介绍
    ubuntu下ssh使用proxy:corkscrew
    neutron用linux_bridge部署provider网络
    python thread的join方法解释
  • 原文地址:https://www.cnblogs.com/qlqwjy/p/13324761.html
Copyright © 2011-2022 走看看