Java 8 新特性介绍

Java 8 新特性介绍

新特性分类

  1. 语言功能增加特性
  2. API 类库
  3. 平台和虚拟机
  4. 周边工具

语言功能增加特性

  • 函数式接口
  • lambda表达式
  • 方法引用
  • 接口(interface)的改进

类库

  • 集合库的Lambda增强
  • 并行集合操作
  • 流API
  • 日期时间API
  • 网络
  • 安全
  • IO

JVM和平台

  • Nashorn JavaScript Engine
  • Reduce Cache Contention on Specified Fields
  • Remove the Permanent Generation
  • Retire Some Rarely-Used GC Combinations
  • Fence Intrinsics
  • Reduce Class Metadata Footprint
  • Enhanced Verification Errors

周边工具

  • DocTree API
  • DocLint
  • Access to Parameter Names at Runtime
  • Repeating Annotations
  • Enhance javac to Improve Build Speed

新特性介绍

函数式接口 FunctionalInterface

所谓函数式接口是只有一个抽象方法的接口
函数式接口实例 @FunctionalInterface注解
只要接口定义满足函数式接口 无论接口是否加上@FunctionalInterface注解 编译器都认为是函数式接口

函数式接口四条规则

  1. 接口只能定义一个抽象方法
  2. 覆盖Object类的抽象方法不算抽象方法里
  3. 注解@FunctionalInterface 只能用在接口上
  4. 如果满足函数式接口 无论是否使用@FunctionalInterface注解 编译器都认为是函数式接口
    JDK一些常用函数式接口
java.lang.Runnable
java.io.FileFilter
java.io.FilenameFilter
java.util.Comparator
java.util.concurrent.Callable

lambda表达式

冗长无意义的代码

** 一个简单的线程例子 **

//使用匿名内部类写一个线程方法
  new Thread(new Runnable() {
   @Override
   public void run() {
    System.out.println(Thread.currentThread().getName());
   }
  }).start();

//小写转大写
List nameList = Arrays.asList("a","b","c");
List upperNameList = new ArrayList();
for(String name : nameList){
    upperNameList.add(name.toLowerCase());
}

** 写代码能简单一点吗?**

可以

        // 使用lambda表达式
        new Thread(
                () -> System.out.println(Thread.currentThread().getName())

        ).start();
        
        
        //使用流操作
        nameList.stream().map(str -> str.toUpperCase());

Lambda表达式一般形式


//求和lambda表达式
(int x, int y) -> {return x + y;}

(String s) -> {System.out.println(s)};

list -> {list.add(42); return list;}

lambda表达式内可以访问外部变量

// Java 8 以前 i 必须用final修饰
int i = 0;
new Thread(new Runnable() {

    @Override
    public void run() {
System.out.println(i);
// i = 1; 都不能对i进行赋值
    }
});

int j = 1;
new Thread(() -> {
    System.out.println(j);
    // j = 1;不能对j进行赋值 官方名称为"effectively final"
});

** effectively final **

目标类型 target type

lambda表达式是什么?
比如 x -> x * 2 是函数式接口 interface IntOperation { int operate(int i); }
的一个实例

  IntOperation twice = x -> x * 2;
        IntOperation square = x -> x * x;
        System.out.println(twice.operate(3));
        System.out.println(square.operate(3));

        // lambda必须是函数式接口实例
        // Object o = x -> System.out.println(x);

        Consumer c = x -> System.out.println(x);
        Object o = c;
作用域和上下文
public class WhatIsThis {

    void checkThis() {
        System.out.println("outer " + this);

        new Thread(new Runnable() {

            public void run() {
                System.out.println("inner " + this);
                printThis();
            }
        }).start();

        new Thread(() -> {
            System.out.println("in lambda " + this);
        }).start();
    }

    void printThis() {
        System.out.println("from printThis() " + this);
    }

    public static void main(String[] args) {
        new WhatIsThis().checkThis();
    }
}

方法引用

编程语言内各种方法抽象出来作为一个变量类型,作为参数输入,或者做为返回值返回
通过方法引用实现函数式编程语言的function as first-classs object(函数作为一等公民) 方法可以像变量一样做为参数或返回值

例子一

 //字符串小写转大写 
 Function upperfier = String::toUpperCase;
 System.out.println(upperfier.apply("Hello"));

** 例子二 **

  //集合元素判断
 Set knowNames = new HashSet<>();
 knowNames.add("Zhang");
 knowNames.contains("Zhang");

 Predicate isKnowName = knowNames::contains;
 isKnowName.test("Zhang");
 isKnowName.test("Li");

方法引用类型有
| 类型 | 使用方法 | lambda形式 |
| --- | --- |
| 实例方法 | x::toString | () -> x.toString() |
| 静态方法 | String::valueOf | x -> x.toString() |
| 构造方法 | ArrayList::new | () -> new ArrayList<>() |
| 数组构造方法 | EleType[]::new |

JDK对方法的的抽象(输入输出抽象) 在java.util.function包下

// 输入类型为T输出为R
public interface Function{
      R apply(T t);
}

//输出布尔值
public interface Predicate{  
     boolean test(T t);
}

// 没有输入 输出为T
public interface Supplier {
    T get();
}

// 输入为类型T 没有输出
public interface Consumer {
      void accept(T t);
}
   

方法引用与lambda表达式的等价关系

接口的改进

接口允许有实现方法
virtual extension method
default 关键字来修饰实现方法

default public  void printOrderInfo(String orderId){
      System.out.println(orderId);
}

接口允许有静态方法

public interface InterfaceStaticMethod {
    static void myMethod(){
        System.out.println("myMethod");
    }
}
// Comparator接口生成比较器方法
public static > Comparator comparing(
            Function keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }

//根据名字做比较的比较器
Comparator nameComparator = Comparator.comparing(Employee::getName);

//根据薪水做比较比较器
Comparator salaryComparator = Comparator.comparing(Employee::getSalary);

接口多继承问题

  1. 继承多个具有相同的方法接口 必须在子接口方法里明确指定调用哪个父接口的方法
  2. 实现接口的类也同理
interface SubInterface extends MyInterface1,MyInferface2{

 @Override
 default void test(String str) {
  MyInferface2.super.test(str);
 }
 
}

class SubClass implements  MyInterface1,MyInferface2{

    @Override
    public void test(String str) {
        MyInterface1.super.test(str);
    }
    
}

类型推导

所谓类型推导编译器根据上下文 智能的推断变量的类型,不需要开发者显式指定变量类型

  1. java 7 对范型类型推导改进
 Map map2 = new HashMap();

 // 右边括号内<>参数类型可以省略 
Map map1 = new HashMap<>();

官方叫做diamond

lambda表达式智能推导参数类型

Comparator comparator = (String str1,String str2) -> {
   return str1.compareTo(str2);
  };
  
 // 不需要显式指定str1和str2的类型为String
  Comparator comparator2 = (str1,str2) -> {
   return str1.compareTo(str2);
  };

类型推导上下文范围

  • Variable declarations
  • Assignments
  • Return statements
  • Array initializers
  • Method or constructor arguments
  • Lambda expression bodies
  • Conditional expressions, ?:
  • Cast expressions

新特性花式组合完法

  1. 比较器的N种写法
    代码例子

类库

集合库的Lambda增强

  1. Collection新增方法

Iterable.forEach(Consumer)
Iterator.forEachRemaining(Consumer)
Collection.removeIf(Predicate)
Collection.spliterator()
Collection.stream()
Collection.parallelStream()
List.sort(Comparator)
List.replaceAll(UnaryOperator)
Map.forEach(BiConsumer)
Map.replaceAll(BiFunction)
Map.putIfAbsent(K, V)
Map.remove(Object, Object)
Map.replace(K, V, V)
Map.replace(K, V)
Map.computeIfAbsent(K, Function)
Map.computeIfPresent(K, BiFunction)
Map.compute(K, BiFunction)
Map.merge(K, V, BiFunction)
Map.getOrDefault(Object, V)

并行集合操作

集合的块数据操作

流API

** Stream的本质是对数据源进行抽象 提供一套通用API对数据源操作 **

引入Stream、函数式接口、lambda等几大特性java 8 有了一些函数式编程语言味道
Stream实现map filter reduce等操作,Stream的数据源包括数组、集合、IO通道、随机数生成器等,Stream相关接口在java.util.stream包下


public interface Stream extends BaseStream> {
    //过滤 
   Stream filter(Predicate predicate);

   // 映射
    Stream map(Function mapper);

  //聚合
  T reduce(T identity, BinaryOperator accumulator);
}

Stream接口方法分类

Intermediate 输出还是stream,比如filter,map
Terminal 对流的聚合操作比如 sum count等

对流操作的一般过程
  1. 从数据源获取流
  2. 执行一个或多个中间操作
    3 执行一个终结操作(terminal operation)

//对list求和
int result = list.stream().reduce(0,(x,y) -> x + y);

//对list过滤(大于5的数字)再求和
int result = list.stream().filter(x -> x > 5).reduce(0,(x,y) -> x + y);

//对list 过滤(大于5的数字) 映射(求平方) 再求和,先通过mapToInt生成IntStream,调用sum方法
result = list.stream().filter(x -> x > 5).map(x -> x * x).mapToInt(x -> x).sum();

各位脑补下写代码过程中如果用Stream的map filter reduce来简化代码

流的延迟初始化特性lazy

数字流
IntStream
LongStream
DoubleStream
可以对数字流进行sum, min, max,average等聚合操作

List strings = Arrays.asList("a", "b", "c");
strings.stream()                    // Stream
       .mapToInt(String::length)    // IntStream
       .longs()                     // LongStream
       .mapToDouble(x -> x / 10.0)  // DoubleStream
       .boxed()                     // Stream
       .mapToLong(x -> 1L)          // LongStream
       .mapToObj(x -> "")           // Stream

Unix下的管道?

玩转Stream之数据库SQL

https://technology.amis.nl/2013/10/05/java-8-collection-enhancements-leveraging-lambda-expressions-or-how-java-emulates-sql/

http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html

流与集合比较

Stream辅助类Collector

日期时间API

新的java.time包

Instant——代表的是时间戳
LocalDate——日期(不带时间)比如2016-10-29。它可以用来存储生日,周年纪念日,入职日期等,
LocalTime——它代表的是不含日期的时间
LocalDateTime——它包含了日期及时间,不过还是没有偏移信息或者说时区。
ZonedDateTime——这是一个包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的。
枚举类
DayOfWeek
Month

JAVA 8:健壮、易用的时间/日期API

网络

安全

JVM和平台

周边工具

----------参考资料-----------------
Oracle 官方 Java8新特性
Open JDK feature list
关于java lambda表达式一切问题

java 8 lambda 方法引用 Stream综合介绍

lambda和背后invokedynamic

JAVA 8:健壮、易用的时间/日期API

lambda和内部类性能比较

你可能感兴趣的:(Java 8 新特性介绍)