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

posted @ 2019-01-06 10:23  栖息之鹰  阅读(1014)  评论(0编辑  收藏  举报