Java 8新特性(Lambda,Stream API)
由于最近总监要求学习Java 8的一些知识,就去网上找了 一套教程来学习学习,将学习结果做一个小的总结记录,方便以后使用;
主要内容:
- Lambda表达式
 - 函数式接口
 - 方法引用于构造器引用
 - Stream API
 - 接口中的默认方法与静态方法
 - 新时间日期API
 
其中,最主要的部分为Lambda表达式与Stream API;
1、Java 8的优点
速度更快
代码更少(增加了新的语法Lambda表达式)
强大的Stream API
便于并行
最大化减少空指针异常(Optional)
哈希算法        数组-链表-红黑树 
Java8中对HashMap的改变。(优先选择哈希表)
ConcurrentHashMap (并发级别:默认16个   concurrentLevel=16) 
Java8中改为CAS算法 
CAS算法比锁效率高,是底层操作系统支持的算法。
栈,堆,方法区。 
方法区属于堆中永久区(PremGen)的一部分。 
但是将方法区放置在堆区外。 
方法区:加载类信息;几乎不会被垃圾回收机制回收;会被垃圾回收机制回收,但是回收条件比较苛刻。 
JYM厂商很多种:Oracle-SUN、Hotspot、Oracle JRocket、IBM J9 JVM;  
当方法区快满的时候,垃圾回收机制开始回收。 
Java 8后,没有永久区了,改为MetaSpace元空间;其使用的为物理内存。 
物理内存较大,垃圾回收机制使用的概率也变小。默认物理内存多大,元空间多大。  
Java 8以前的JYM调优参数也改变了。 
2、Lambda表达式优点
Lambda是一个匿名函数,我们可以把Lambda表达式理解为是一段可以传递的代码(将代码像数据一样进行传递); 
可以写出更简洁、更灵活的代码。
作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
使用Lambda表达式以后; 
2.1Lambda实例
需求:获取当前公司员工年龄大于35的员工信息; 
首先;先创建一个Employee的类,里面包含属性name,age,salary,添加set、get方法,toString方法, 
以及无参和有参构造函数;
输出: 
2.2实例二:
需求:获取当前公司中员工工资大于5000的员工信息 
会发现以前的操作方法十分繁复冗余,那么可以通过哪些方式可以来优化代码呢?
优化方法一:策略设计模式
采用设计模式。 设计接口 ;
然后在类中实现该接口; 
优化后的写法: 
然后 
输出: 
如果想使用工资过滤,则新建类实现MyPredicate接口; 
然后在测试类中编写代码; 
输出: 
缺点:每次实现一个策略,必须新建一个类;
优化方式二:匿名内部类
然后; 
输出: 
优化方式三:Lambda表达式,(策略设计模式)
Lambda表达式: 
输出: 
优化方式四:Stream API
输出: 
3、流Stream
private static List<String> getLowCaloricDishesNamesInJava8(List<Dish> dishes) {
    return dishes.stream()
            // 选出400卡路里以下的菜肴
            .filter(d -> d.getCalories() < 400)
            // 按照卡路里排序
            .sorted(comparing(Dish::getCalories))
            // 提取菜名
            .map(Dish::getName)
            // 转为集合
            .collect(toList());
}
为了利用多核架构并行执行代码,将stream()改为parallelStream()。
private static List<String> getLowCaloricDishesNamesInJava8(List<Dish> dishes) {
    return dishes
            .parallelStream()
            // 选出400卡路里以下的菜肴
            .filter(d -> d.getCalories() < 400)
            // 按照卡路里排序
            .sorted(comparing(Dish::getCalories))
            // 提取菜名
            .map(Dish::getName)
            // 转为集合
            .collect(toList());
}
可以把几个基础操作链接起来,来表达复杂的数据处理流水线(在 filter 后面接上sorted 、 map 和 collect 操作),同时保持代码清晰可读。 filter 的结果被传给了 sorted 方法,再传给 map 方法,最后传给 collect 方法。
3.1 流简介
流:从支持数据处理操作的源生成的元素序列。
元素序列:就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值。因为集合是数据结构,所以它的主要目的是以特定的时间/空间复杂度存储和访问元素(如ArrayList 与 LinkedList )。但流的目的在于表达计算,比如你前面见到的filter 、 sorted 和 map 。集合讲的是数据,流讲的是计算。
源:流会使用一个提供数据的源,如集合、数组或输入/输出资源。请注意,从有序集合生成流时会保留原有的顺序。由列表生成的流,其元素顺序与列表一致。
数据处理操作:流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中的常用操作,如filter、map、reduce、find、match、sort等。流操作可以顺序执行,也可并行执行。
此外,流操作有两个重要特点。
- 流水线:很多流操作本身会返回一个流,这样多个操作就可以链接起来,形成一个大的流水线。
 - 内部迭代:与使用迭代器显式迭代的集合不同,流的迭代操作是在背后进行的。
 
List<Dish> menu = Dish.MENU;
// 从menu获得流
List<String> threeHighCaloricDishNames = menu.stream()
        // 通过链式操作,筛选出高热量的菜肴
        .filter(d -> d.getCalories() > 300)
        // 获取菜名
        .map(Dish::getName)
        .limit(3)
        .collect(Collectors.toList());
// [pork, beef, chicken]
System.out.println(threeHighCaloricDishNames);
- filter: 接受Lambda,从流中排除某些元素。在刚刚的代码中,通过传递Lambda表达式 d -> d.getCalories() > 300,选择出热量高于300卡路里的菜肴。
 - map:接受一个Lambda,将元素转换成其他形式或提取信息。在刚刚的代码中,通过传递方法引用Dish::getName,提取了每道菜的菜名。
 - limit:截断流,使其元素不超过给定的数量。
 - collect:将流转换为其他形式。在刚刚的代码中,流被转为一个List集合。
 
3.2 流与集合
集合与流之间的差异就在于什么时候进行计算。集合是一个内存中的数据结构,它包含数据结构中目前所有的值,集合中的每个元素都得先算出来才能添加到集合中。
相比之下,流则是在概念上固定的数据结构,其元素则是按需计(懒加载)算的。需要多少就给多少。这是一种生产者与消费者的关系。从另一个角度来说,流就像是一个延迟创建的集合:只有在消费者要求的时候才会生成值。与之相反,集合则是急切创建的(就像黄牛囤货一样)。
流只能遍历一次 
和迭代器类似,流只能遍历一次。遍历完之后,我们就说这个流已经被消费掉了。你可以从原始数据源那里再获得一个新的流来重新遍历一遍,就像迭代器一样(这里假设它是集合之类的可重复的源,如果是I/O通道就没戏了)。例如以下代码会抛出一个异常,说流已被消费掉了:
List<String> names = Arrays.asList("Java8", "Lambdas", "In", "Action");
Stream<String> s = names.stream();
s.forEach(System.out::println);
// 再继续执行一次,则会抛出异常
s.forEach(System.out::println);
外部迭代与内部迭代 
使用Collection接口需要用用户去做迭代(比如用for-each),这个称为外部迭代。反之,Stream库使用内部迭代,它帮你把迭代做了,还把得到的流值存在了某个地方,你只要给出一个函数说要干什么就可以了。下面的代码说明了这种区别。
集合:使用for-each循环外部迭代:
// 集合:使用for-each循环外部迭代
List<Dish> menu = Dish.MENU;
List<String> names = new ArrayList<>();
for (Dish dish : menu) {
    names.add(dish.getName());
}
集合:用背后的迭代器做外部迭代。
List<String> names = new ArrayList<>();
Iterator<String> iterator = menu.iterator();
while(iterator.hasNext()) {
    Dish d = iterator.next();
    names.add(d.getName());
}
流:内部迭代
List<String> names = menu.stream()
                    .map(Dish::getName)
                    .collect(toList());
3.3 流操作
List<String> names = menu.stream()
                // 中间操作
                .filter(d -> d.getCalories() > 300)
                // 中间操作
                .map(Dish::getName)
                // 中间操作
                .limit(3)
                // 将Stream转为List
                .collect(toList());
filter、map和limit可以连成一条线,collect触发流水线执行并关闭它。可以连起来的称为中间操作,关闭流的操作可以称为终端操作。
3.4 中间操作
诸如filter和sorted等中间操作会返回一个流。让多个操作可以连接起来形成一个查询。重要的是,除非流水线上触发一个终端操作,否则中间操作不会执行任何处理它们懒得很。这就是因为中间操作一般都可以合并起来,在终端操作时一次性全部处理。
List<String>  names = menu.stream()
        .filter(d -> {
            System.out.println("filtering:" + d.getName());
            return d.getCalories() > 300;
        })
        .map(dish -> {
            System.out.println("mapping:" + dish.getName());
            return dish.getName();
        })
        .limit(3)
        .collect(toList());
System.out.println(names);
执行结果:
filtering:pork
mapping:pork
filtering:beef
mapping:beef
filtering:chicken
mapping:chicken
[pork, beef, chicken]
3.5 终端操作
终端操作会从流的流水线生产结果。其结果是任何不是流的值,比如List、Integer,甚至是void。例如,在下面的流水线中,foreachh返回的是一个void的终端操作,它对源中的每道菜应用一个Lambda。把System.out.println()传递给foreach,并要求它打印出由menu生成的流中每一个Dish:
menu.stream().forEach(System.out::println);
3.6 使用流
流的使用一般包括三件事:
- 一个数据源(比如集合)来执行查询
 - 一个中间操作链,形成一条流的流水线
 - 一个终端操作,执行流水线,并能生成结果。
 
3.7 相关中间操作与终端操作
终端: 
Java 8新特性(Lambda,Stream API)的更多相关文章
- Java8 新特性 Lambda & Stream API
		
目录 Lambda & Stream API 1 Lambda表达式 1.1 为什么要使用lambda表达式 1.2 Lambda表达式语法 1.3 函数式接口 1.3.1 什么是函数式接口? ...
 - Java 8 新特性之 Stream 流基础体验
		
Java 8 新特性之 Stream 流基础体验 package com.company; import java.util.ArrayList; import java.util.List; imp ...
 - Java 8 新特性 - Lambda表达式
		
Lambda表达式 vs 匿名类既然lambda表达式即将正式取代Java代码中的匿名内部类,那么有必要对二者做一个比较分析.一个关键的不同点就是关键字 this.匿名类的 this 关键字指向匿名类 ...
 - java 新特性之 Stream API
		
强大的 Stream API 一.Stream API 的概述 Stream到底是什么呢? 是数据渠道,用于操作数据源(集合.数组等)所生成的元素序列. "集合讲的是数据,Stream讲的是 ...
 - Java 8新特性之Stream(八恶人-3)
		
“You John Ruth The Hangman” 绞刑者鲁斯·约翰 “When the Hangman catches you, you hang.”当被绞刑者抓住了,你肯定会被绞死 一.基本介 ...
 - Java8 新特性之Stream API
		
1. Stream 概述 Stream 是Java8中处理集合的关键抽象概念,可以对集合执行非常复杂的查找,过滤和映射数据等操作; 使用 Stream API 对集合数据进行操作,就类似于使用 SQL ...
 - 浅析Java 8新特性Lambda Expression
		
什么是Lambda Expression 对于Lambda Expression,我的理解是,它是一个函数表达式,如下: (int x, int y) -> x - y 符号左边定义了函数的输入 ...
 - 【Java8新特性】Stream API有哪些中间操作?看完你也可以吊打面试官!!
		
写在前面 在上一篇<[Java8新特性]面试官问我:Java8中创建Stream流有哪几种方式?>中,一名读者去面试被面试官暴虐!归根结底,那哥儿们还是对Java8的新特性不是很了解呀!那 ...
 - java 8 新特性之Stream的排序/分类
		
Stream简介 Stream是Java8提供的一个新的API,它位于java.util.stream包下.Stream API提供了一种新的方式来对Java集合进行操作,这种操作方式极大的提高了Ja ...
 - Java 8新特性----Lambda
		
Lambda 一.如何辨别Lambda表达式 Runnable noArguments = () -> System.out.println("Hello World"); ...
 
随机推荐
- Java学习日报 9.29
			
package random;import java.util.*;import java.math.*;public class Com { public static void main(Stri ...
 - Java学习日报7.22
			
//3.2 逆向输出三位整数! 7.22 package 三个和尚比身高1; import java.util.Scanner; public class Demo1{ @SuppressW ...
 - Spark学习进度-实战测试
			
spark-shell 交互式编程 题目:该数据集包含了某大学计算机系的成绩,数据格式如下所示: Tom,DataBase,80 Tom,Algorithm,50 Tom,DataStructure ...
 - .NET 云原生架构师训练营(模块二 基础巩固 消息队列 介绍与基础)--学习笔记
			
2.6.1 消息队列 -- 介绍 主要使用场景 队列的三种形式 消息队列的优点 主要使用场景 典型的异步处理 流量削锋 应用解耦 队列的三种形式 点对点 工作队列 发布与订阅 消息队列的优点 1.屏蔽 ...
 - Spring源码深度解析之数据库连接JDBC
			
Spring源码深度解析之数据库连接JDBC JDBC(Java Data Base Connectivity,Java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供 ...
 - 有哪些适合个人开发的微信小程序
			
微信小程序提供了一个简单.高效的应用开发框架和丰富的组件及API,帮助开发者在微信中开发具有原生 APP 体验的服务. 微信小程序支持采用云开发模式,无需后台服务,十分的方便快捷,适合个人开发一些工具 ...
 - 【C++】《C++ Primer 》第十八章
			
第十八章 用于大型程序的工具 大规模应用程序的特殊要求包括: 在独立开发的子系统之间协同处理错误的能力. 使用各种库进行协同开发的能力. 对比较复杂的应用概念建模的能力. 一.异常处理 异常处理(ex ...
 - 安装SVN和汉化包及基本使用
			
官网下载程序 和 下载汉化包. https://tortoisesvn.net/ 注意SVN汉化包版本需要和SVN版本一致,否则是无效的. 一.下载 1.进入官网,点击downloads 2.点击 ...
 - 9. 细节见真章,Formatter注册中心的设计很讨巧
			
目录 本文提纲 版本约定 你好,我是A哥(YourBatman). Spring设计了org.springframework.format.Formatter格式化器接口抽象,对格式化器进行了大一统, ...
 - Docker学习笔记之基本命令使用
			
测试的环境为Ubuntu1804. 1. search命令搜索镜像 sudo docker search centos 搜索centos相关的镜像,可以看到第一个最多星的的centos是官方的镜像,而 ...