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

    ---栖息之鹰(一个外表懒洋洋的内心有激情的程序员) 此博客为笔者原著,转载时请注明出处,谢谢!
  • 相关阅读:
    为什么要学习Linux
    测试开发技术:DOM中 innerHTML、innerText、outerHTML、outerText的区别
    web service 组件
    老李分享:webservice是什么?
    hibernate 和 mybatis 的区别
    mybatis 缓存
    过滤器和拦截器
    Spring 注解
    Spring 全局异常处理
    mybatis Mapper XML 映射文件
  • 原文地址:https://www.cnblogs.com/roostinghawk/p/9899637.html
Copyright © 2011-2022 走看看