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<String> nameList = Arrays.asList("a","b","c");
List<String> upperNameList = new ArrayList<String>();
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<String, String> upperfier = String::toUpperCase;
 System.out.println(upperfier.apply("Hello"));

** 例子二 **

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

 Predicate<String> 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<T, R>{
      R apply(T t);
}

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

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

// 输入为类型T 没有输出
public interface Consumer<T> {
      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 <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & 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<String, Object> map2 = new HashMap<String, Object>();

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

官方叫做diamond

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

Comparator<String> comparator = (String str1,String str2) -> {
   return str1.compareTo(str2);
  };
  
 // 不需要显式指定str1和str2的类型为String
  Comparator<String> 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<T> extends BaseStream<T, Stream<T>> {
    //过滤 
   Stream<T> filter(Predicate<? super T> predicate);

   // 映射
   <R> Stream<R> map(Function<? super T, ? extends R> mapper);

  //聚合
  T reduce(T identity, BinaryOperator<T> 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<String> strings = Arrays.asList("a", "b", "c");
strings.stream()                    // Stream<String>
       .mapToInt(String::length)    // IntStream
       .longs()                     // LongStream
       .mapToDouble(x -> x / 10.0)  // DoubleStream
       .boxed()                     // Stream<Double>
       .mapToLong(x -> 1L)          // LongStream
       .mapToObj(x -> "")           // Stream<String>

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和内部类性能比较

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容