设为首页 加入收藏

TOP

Java8中部分新特性详述(一)
2017-06-18 10:22:12 】 浏览:438
Tags:Java8 部分 特性 详述

Java8中的新特性


一、Lambda表达式


Lambda表达式可以理解为一种可传递的匿名函数:它没有名称,但又参数列表、函数主体、返回类型,可能还有一个可以抛出的异常列表。


匿名:和匿名类类似的,它没有明确的名字


函数:Lambda函数不属于某个特定的类,但和方法一样都具有参数列表、函数主体、返回类型,还可以有抛出的异常列表


传递:Lambda表达式可以作为参数传递给方法或者存储在变量中。


Lambda表达式的基本形式: (parameters)-> expression 或(parameters)-> {statements;}


怎么使用Lambda表达式?


哪里可以使用Lambda表达式?你可以在函数式接口上使用Lambda表达式。


函数式接口也就是只定义了一个抽象方法的接口。Lambda表达式允许直接以内联的形式为函数式接口的抽象方法提供实现,并把整个表达式作为函数式接口的实例。


    上面既然提到了Lambda表达式是函数式接口的抽象方法的具体实现,那这两者之间的函数描述符应该是一致的,才可以编译成功。


    如


    Runnable接口的函数描述符为()->void,而其对应的Lambda表达式实现也为()->void。签名一致的情况下才能通过类型检查。


函数式接口:


    在Java8以前,常用的函数式接口Comparable、Runnable、Callable等。而在Java8中又引入了一系列的函数式接口。


    常用的函数式接口


类型检查:


    Lambda的类型是从使用Lambda的上下文(比如接受它传递的方法的参数或者接受它的值的局部变量)中推断出来的,而我们且将上下文要求Lambda表达式需要的类型称为目标类型。当目标类型的抽象方法的函数描述符和Lambda表达式的函数描述符一致时,即类型检查无误。这样我们就可以将一个Lambda表达式应用到不同的函数式接口中,只要二者的函数描述符一致即可。 


    注意点:特出的void兼容规则


    如果一个Lambda的主体是一个语句表达式,它就和一个返回void的函数描述符兼容(参数列表兼容的前提下)


类型推断:Java编译器可以从上下文推断出用什么函数式接口来配合Lambda表达式,也能推断出使用Lambda的前面,这样就可以在Lambbda语法中省去标注参数类型。


Lambda与闭包:


  闭包:闭包是一个函数的实例,可以无限制地范围那个函数的非本地变量。如闭包可以作为参数传递给另一个函数,也可以访问和修改器作用域之外的变量。


而Java8中Lambda表达式和匿名类可以做类似于闭包的事情,可以作为参数传递给方法,并且可以访问其作用域之外的变量,但存在一个限制,它们不能修改定义Lambda的方法的局部变量的内容,这些变量都必须是隐式最终的。而匿名类则为显式最终的(可以理解为是对值封闭,而不是对变量封闭)


二、方法引用:


    方法引用可以被看做仅仅调用特定方法情形下的Lambda的一种快捷写法。它表示,如果一个Lambda表达式代表的只是直接调用这个方法,那最好还是用名称来调用它,而不是去描述如何调用它。


示例:


(Apple a)->a.getWeight()  等价于方法引用的 Apple::getWeight


(str,i)->str.substring(i) 等价于string::substring


如何构建方法引用:


指向静态方法的方法引用:


指向任意类型的实例方法的方法引用


指向现有对象的实例方法的方法引用 


构造函数引用


    对于一个现有构造函数,可以利用它的名称和关键字new来创建它的一个引用ClassName::new


三、Stream


1.Stream的概念简析


流(Stream)是Java API的新成员,允许你以声明性方法处理数据集合(在一定程度上有点类似于SQL语句),它表示的是要做什么,而不是怎么做。此外,它还可以透明的并行处理。


    下面先就展现一个流的示例写法:


List<String> threeHighCaloricDishNames = menu.stream()
        //筛选
        .filter(dish -> dish.getCalories()>500)
        //排序,降序
        .sorted(comparing(Dish::getCalories).reversed())
        //转换
        .map(Dish::getName)
        //限制输出为3个
        .limit(3)
        //将流转换为集合
        .collect(Collectors.toList());
System.out.println(threeHighCaloricDishNames);


上述代码完成了下述操作:


获取一个数据源(source)→ 数据转换→执行操作获取想要的结果


这里我们将数据转换中的操作称为中间操作,最后的执行操作获得想要的结果称作终端操作。


2.Stream的基本操作


以下是一些常见的中间操作和终端操作


中间操作


终端操作


注意点:


每次转换原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道


在对一个Stream进行多次中间操作时,由于转换操作具有延迟特性(多个转换操作只会在终端操作的时候融合起来,然后一次循环完成)。我们可以简单的这样理解,在Stream中有个操作函数的集合,每次转换操作的时候都会把转换函数放到这个集合中,在终端操作的时候循环Stream对应的集合,然后对每个元素执行所有的函数。


此外,有些中间操作和终端操作具有短路的特性。


即指对于一个中间操作而言,如果它接收的是一个无限大的流,但返回的是有限的新流。(如limt)


对于一个终端操作,如果它接受的是一个无限大的流,但能在有限的时间内计算出结果(如findFirst、findAny等)


3.Stream的使用


Stream的使用涉及到三点:


Stream的构建、Stream的转换、Stream的归约


1)Stream的构建:


最常用的创建Stream有两种途径:


a)    通过Stream接口的静态工厂方法(注意:Java8里接口可以带静态方法);


b)    通过Collection接口的默认方法--stream(),把一个Collection对象转换成Stream


Stream接口的静态工程方法


Collection接口的默认方法:


stream()

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇硬币找零问题之动态规划 下一篇Android SurfaceView的基本使用

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目