zoukankan      html  css  js  c++  java
  • Java8如何用

    2014年发布的Java8,现在应该是业界使用最普遍的Java版本,可很多Java开发人员并没有充分发挥这4年前发布的版本的优点,

    本文就是带着“学以致用”的目的去了解Java8,挖掘编码中可提高效率的特性。

    什么是Java8?官网第一句话解释

    Java Platform, Standard Edition 8 is a major feature release.
    注:虽然Java现在半年迭代一次,但LTS版本依然保持3年一个版本的计划(比如从Java8到Java11)

    1. Java Programming Language

    首先是编程语法的增强

    1) Lambda表达式:更多的场景是跟“函数式接口”结合。(注:函数式接口只有一个抽象方法)例:

    public class Java8Tester {
       public static void main(String args[]){
          Java8Tester tester = new Java8Tester();
            
          // 类型声明(MathOperation是在本Class中定义的内部接口)
          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);
       }
    }

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

    2) 方法引用:特点是一对引号引用方法,包括构造方法,静态方法,实例方法等的引用,可跟Lambda表示式结合使用,例:

    import java.util.List;
    import java.util.ArrayList;
     
    public class Java8Tester {
       public static void main(String args[]){
          List names = new ArrayList();
            
          names.add("Google");
          names.add("Runoob");
          names.add("Taobao");
          names.add("Baidu");
          names.add("Sina");
            
          names.forEach(System.out::println);
       }
    }

     3)函数式接口

    函数式接口(Functional Interface)就是一个有且仅有一个抽象方法(无实现),但是可以有多个非抽象方法的接口。函数式接口可以被隐式转换为 lambda 表达式。

    Java8之前一直被匿名类实现,并不是说之前没有函数式接口,只是实现方法不同罢了,比如以下类就是函数式接口,就经常被匿名类实现

    java.lang.Runnable // 用于线程实现
    java.util.concurrent.Callable // 也用于线程,跟Runnable不同的是可以返回值,抛出异常
    java.security.PrivilegedAction // 用于异步编程,一般用于AccessController.doPrivileged
    java.util.Comparator // 类之间的比较,排序
    java.io.FileFilter // 文件或者路径名匹配
    java.nio.file.PathMatcher // NIO的文件路径匹配
    java.lang.reflect.InvocationHandler // 反射中的动态代理接口(Spring的AOP就是通过动态代理实现的)
    java.beans.PropertyChangeListener // 属性变更监听
    java.awt.event.ActionListener // 动作监听
    javax.swing.event.ChangeListener // 用户界面的变更监听

     简单实例如下:

    // Java8中添加此注解是为了编译级错误检查
    @FunctionalInterface
    interface GreetingService { void sayMessage(String message); }

    使用方法(lambda来表示一个实现):

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

     Java8加上java.util.function包的很多函数式接口,比如典型Predicate:

    Predicate <T> 接口是一个函数式接口,它接受一个输入参数 T,返回一个布尔值结果。

    该接口包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)。

    该接口用于测试对象是 true 或 false。

    import java.util.Arrays;
    import java.util.List;
    import java.util.function.Predicate;
     
    public class Java8Tester {
       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);
           
          System.out.println("输出所有偶数:");
          eval(list, n-> n%2 == 0 );
            
          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 + " ");
             }
          }
       }
    }

     上面输出大于3的更简单写法(过滤集合数据常用):

    list.stream().filter(n -> n > 3).forEach(System.out::println);

     4)接口的默认实现方法,这个不需多解释

    5)允许重复注解:主要是为了代码的可读性比如@Authorize(role="USER") @Authorize(role="ADMIN")

    6)注解可用于任何地方,不只类,属性,方法

    7)改进的类型引用。例:

    // <>中类型可以被编译器识别
    List<Integer> = new ArrayList<>()

    8)Method parameter reflection(通过反射取得方法参数):例:http://tutorials.jenkov.com/java-reflection/methods.html

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Parameter;
    
    /**
     * @author liuwei
     * @date 2019/1/1
     */
    public class TestMethodFlection {
    
        public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            Class aClass = TestMethodFlection.class;
            Method method = aClass.getMethod("test", int.class, int.class); // 包装类作为参数的话,也需要完全匹配
            for (Parameter parameter :  method.getParameters()) {
             System.out.println("参数类型:" + parameter.getType());
            }
            System.out.println("返回类型" + method.getReturnType());
            System.out.println("invoke方法结果为:" + method.invoke(null, 1, 2 )); // 静态方法的话,null作为第一个参数;否则,传具体object
        }
    
        public static int test(int x, int y){
            return x + y;
        }
    } 

    4)Optional:对于保存NULL对象的容器(很好的解决空指针异常)


    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; }

    2. Collections

    1)Stream(分串行模式和并行模式) 

    一个来自数据源的元素队列并支持聚合操作。典型用法:Pipelining,内部迭代。例:

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

    // map(取得元素加工后的Value)
    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());

    // 过滤空字符串
    List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
    int count = strings.stream().filter(string -> string.isEmpty()).count();

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

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

    // 转化为Map
    Map<String, String> versionMap = versions.stream().collect(Collectors.toMap(PersonAppVersion::getAppName, PersonAppVersion::getAppVersion));
    // 并行程序(可以充分利用多CPU来加快处理速度)
    List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
    // 获取空字符串的数量
    int count = strings.parallelStream().filter(string -> string.isEmpty()).count();

    // 统计
    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());

    2)HashMap的性能提升:key冲突机制变更 

    3. Compact Profiles

       精简版的profile,使得可以将一个大的java项目部分编译成较小版本

    4. Security

    1. 客户单默认使用TLS1.2协议(注:TLS和SSL的区别

    5. Nashorn取代Rhino(JDK 1.6, JDK1.7)成为Java的嵌入式JavaScript引擎

       // Java中执行JS代码
    public static void main(String args[]){ ScriptEngineManager scriptEngineManager = new ScriptEngineManager(); ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn"); String name = "Runoob"; Integer result = null; try { nashorn.eval("print('" + name + "')"); result = (Integer) nashorn.eval("10 + 2"); }catch(ScriptException e){ System.out.println("执行脚本错误: "+ e.getMessage()); } System.out.println(result.toString()); }

     除此之外,jjs是个基于Nashorn引擎的命令行工具,可以直接执行js代码或者文件。另外,js中也可以执行Java代码,这个应用场景较少,就不再举例

    6. 日期工具类

    之前的日期工具类存在很多问题,比如线程安全,时区问题,让不熟悉的程序员掉入坑里。Java8中引入的最主要API如下:

    • Local(本地) − 简化了日期时间的处理,没有时区的问题。(包括Locatate,LocalDateTime等)

    • Zoned(时区) − 通过制定的时区处理日期时间。(包括ZonedDateTime等)

    以上类都是线程安全的,java.time.Instant用于时间戳

    Java8新特性参考:官网介绍

    国内网站:http://www.runoob.com/java/java8-new-features.html

    函数式接口:http://www.cnblogs.com/chenpi/p/5890144.html

    重复注解:What can be real case use of Repeating annotations?

    TLS和SSL:https://kb.cnblogs.com/page/197396/

    动态代理机制:https://www.cnblogs.com/xiaoluo501395377/p/3383130.html

    反射机制:http://tutorials.jenkov.com/java-reflection

    ---栖息之鹰(一个外表懒洋洋的内心有激情的程序员) 此博客为笔者原著,转载时请注明出处,谢谢!
  • 相关阅读:
    智能移动机器人背后蕴含的技术——激光雷达
    Kalman Filters
    Fiddler抓HttpClient的包
    VSCode开发WebApi EFCore的坑
    WPF之小米Logo超圆角的实现
    windows react打包发布
    jenkins in docker踩坑汇总
    Using ML.NET in Jupyter notebooks 在jupyter notebook中使用ML.NET ——No design time or full build available
    【Linux知识点】CentOS7 更换阿里云源
    【Golang 报错】exec gcc executable file not found in %PATH%
  • 原文地址:https://www.cnblogs.com/roostinghawk/p/9899637.html
Copyright © 2011-2022 走看看