java8完全解读二
继续着上次的java完全解读一
1.强大的Stream API
1.1什么是Stream
1.2 Stream操作的三大步骤
1.2.1 创建Stream
1.2.2 Stream的中间操作
筛选和切片
映射
排序
1.2.3 Stream 的终止操作
查找与匹配
归约
收集
2 新时间日期API
2.1 使用LocalDate、LocalTime、LocalDateTime
2.2 Duration 和Period
2.3 解析与格式化
2.4 时区的处理
3 接口中的默认方法与静态方法
3.1 接口中的默认方法
3.1.1 默认方法的使用
3.1.2 接口默认方法的”类优先”原则
3.1.3 接口默认方法的"接口冲突"
3.2 接口中的静态方法
1.强大的Stream API
Stream 是Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用SQL 执行的数据库查询。也可以使用Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
1.1什么是Stream
流(Stream)是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。
“集合讲的是数据,流讲的是计算!”
注意:
①Stream 自己不会存储元素。
②Stream 不会改变源对象。相反,他们会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
1.2 Stream操作的三大步骤
- 创建Stream
一个数据源(如:集合、数组),获取一个流 - 中间操作
一个中间操作链,对数据源的数据进行处理 - 终止操作(终端操作)
一个终止操作,执行中间操作链,并产生结果
1.2.1 创建Stream
创建Stream严格来说有三种方式
- Java8 中的Collection 接口被扩展,提供了两个获取流的方法:
//Collection的方法
default Stream<E> stream() : 返回一个顺序流
default Stream<E> parallelStream() : 返回一个并行流
- Java8 中的Arrays的静态方法stream() 可以获取数组流:
- 可以使用静态方法Stream.of(), 通过显示值创建一个流。它可以接收任意数量的参数
//Arrays的方法
static <T> Stream<T> stream(T[] array);// 返回一个流
//Stream的方法
public static<T> Stream<T> of(T… values);// 返回一个流
- 可以使用静态方法Stream.iterate() 和Stream.generate(), 创建无限流。
//迭代
public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f)
//生成
public static<T> Stream<T> generate(Supplier<T> s) :
/*
*UnaryOperator是传入类型T返回类型T
* Supplier是无参,返回类型T
*/
实际运用
public void test1(){
/**
* list中的数据本来是用List包裹,创建stream后,将list中的数据换成了stream包裹了,
* 同时对流中的数据操作变得更加方便
*/
//1. Collection 提供了两个方法 stream() 与 parallelStream()
List<String> list = new ArrayList<>();
Stream<String> stream = list.stream(); //获取一个顺序流
Stream<String> parallelStream = list.parallelStream(); //获取一个并行流
//2. 通过 Arrays 中的 stream() 获取一个数组流
Integer[] nums = new Integer[10];
Stream<Integer> stream1 = Arrays.stream(nums);
//通过 Stream 类中静态方法 of()底层也是调用
Stream<Integer> stream2 = Stream.of(1,2,3,4,5,6);
//3.创建无限流,这两个底层调用的都是一样的
//迭代
Stream<Integer> stream3 = Stream.iterate(0, (x) -> x + 2).limit(10);
stream3.forEach(System.out::println);
//生成
Stream<Double> stream4 = Stream.generate(Math::random).limit(2);
stream4.forEach(System.out::println);
}
1.2.2 Stream的中间操作
多个中间操作可以连接起来形成一个流水线,除非流水线上触发终止操作,否则中间操作不会执行任何的处理!而在终止操作时一次性全部处理,称为“惰性求值”。
筛选和切片
运用
//筛选年龄<=35岁的员工
@Test
public void test2(){
//所有的中间操作不会做任何的处理
Stream<Employee> stream = emps.stream()
.filter((e) -> {
System.out.println("测试中间操作");
return e.getAge() <= 35;
});
//只有当做终止操作时,所有的中间操作会一次性的全部执行,称为“惰性求值”
stream.forEach(System.out::println);
}
//查询薪水>=5000的前三个员工
@Test
public void test4(){
emps.stream()
.filter((e) -> {
return e.getSal() >= 5000;
}).limit(3)
.forEach(System.out::println);
}
//查询薪水>=5000的员工,去掉前两个
@Test
public void test5(){
emps.stream()
.filter((e) -> e.getSal()>= 5000)
.skip(2)//跳过2元素,返回一个扔掉了前2个元素的流
.forEach(System.out::println);
}
//去重
@Test
public void test6(){
emps.stream()
.distinct()
.forEach(System.out::println);
}
映射
实例运用
- map
@Test
public void test1() {
List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
//将传入的String值转为大写并返回String
Stream<String> stream = strList.stream()
.map(String::toUpperCase);
stream.forEach(System.out::println);
//传入的String,通过方法将String转化成包裹字符的stream了
Stream<Stream<Character>> stream2 = strList.stream()
.map(Stream2::filterCharacter);
stream2.forEach((sm) -> {
sm.forEach(System.out::println);
});
}
public static Stream<Character> filterCharacter(String str) {
List<Character> list = new ArrayList<>();
for (Character ch : str.toCharArray()) {
list.add(ch);
}
return list.stream();
}
- flatMap
//flatmap
@Test
public void Test3() {
List<String> strList = Arrays.asList("aaa", "bbb", "ccc", "ddd", "eee");
Stream<Character> stream3 = strList.stream()
.flatMap(Stream2::filterCharacter);
stream3.forEach(System.out::println);
}
排序
实际运用
@Test
public void test3() {
emps.stream()
.map(Employee::getName)
.sorted()
.forEach(System.out::println);
emps.stream()//按年龄排序,如果年龄相同:按名字排序
.sorted((x, y) -> {
if (x.getAge() == y.getAge()) {
return x.getName().compareTo(y.getName());
} else {
return Integer.compare(x.getAge(), y.getAge());
}
}).forEach(System.out::println);
}
1.2.3 Stream 的终止操作
终端操作会从流的流水线生成结果。其结果可以是任何不是流的值,例如:List、Integer,甚至是void 。
查找与匹配
归约
备注:map 和reduce 的连接通常称为map-reduce 模式,因Google 用它来进行网络搜索而出名。
使用
@Test
public void test1(){
//将数组中的值加起来
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Integer sum = list.stream()
.reduce(0, (x, y) -> x + y);
System.out.println(sum);
//使用map将员工的工资提取出来,使用reduce将工资累加
Optional<Double> op = emps.stream()
.map(Employee::getSal)
.reduce(Double::sum);
System.out.println(op.get());
}
//需求:搜索名字中 “六” 出现的次数
@Test
public void test2(){
Optional<Integer> sum = emps.stream()
.map(Employee::getName)
.flatMap(Stream2::filterCharacter)
.map((ch) -> {
if(ch.equals('六'))
return 1;
else
return 0;
}).reduce(Integer::sum);
System.out.println(sum.get());
}
收集
Collector 接口中方法的实现决定了如何对流执行收集操作(如收集到List、Set、Map)。但是Collectors 实用类提供了很多静态方法,可以方便地创建常见收集器实例,具体方法与实例如下表:
2 新时间日期API
2.1 使用LocalDate、LocalTime、LocalDateTime
LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。
提供的方法:
运用
@Test
public void test() {
LocalDate localDate = LocalDate.now();//现在的日期
LocalTime localTime = LocalTime.now();//现在的时间
LocalDateTime localDateTime = LocalDateTime.now();//现在的时间和日期
System.out.println(localDate+"==>"+localTime+"==>"+localDateTime);
}
@Test
public void test2() {
LocalDate localDate = LocalDate.of(1996, 02, 03);//指定现在的日期
LocalTime localTime = LocalTime.of(16, 04);//指定现在的时间
LocalDateTime localDateTime = LocalDateTime.of(1996, 02, 03, 16, 04);//指定现在的日期时间
System.out.println(localDate+"==>"+localTime+"==>"+localDateTime);
}
@Test
public void test3() {
LocalDate localDate = LocalDate.now();
LocalDate localDate1 = localDate.plusDays(5);//在当前时间上加5天
LocalDate localDate2 = localDate.plusMonths(2);//加2个月
LocalDate localDate3 = localDate.plusWeeks(1);//加一周
LocalDate localDate4 = localDate.plusYears(1);//加一年
LocalDate localDate5 = localDate.minusMonths(5);//减5天
System.out.println(localDate4);
}
@Test
public void test5() {
LocalDate localDate = LocalDate.now();
LocalDate localDate1 = localDate.withDayOfMonth(12);//将日期中的,这个月的天数修改为12
LocalDate localDate2 = localDate.withYear(2015);//将日期中的年修改为2015
LocalDate localDate3 = localDate.withMonth(8);//将日期中的月修改为8月
System.out.println(localDate3);
}
@Test
public void test6() {
LocalDate localDate = LocalDate.now();
int year = localDate.getYear();//获取当前的年份
System.out.println(year);
}
@Test
public void test7() {
LocalDate localDate = LocalDate.now();
LocalDate localDate1 = LocalDate.now();
Period period = localDate.until(localDate1);//获取两个日期间的日期间隔
boolean before = localDate.isBefore(localDate1);//比较两个localData
boolean leapYear = localDate.isLeapYear();//是否是闰年
System.out.println(before);
}
2.2 Duration 和Period
- Duration:用于计算两个“时间”间隔
- Period:用于计算两个“日期”间隔
使用
@Test
public void test4() {
//时间戳
Instant start = Instant.now();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
Instant end = Instant.now();
//Duration:用于计算两个“时间”间隔
Duration duration = Duration.between(start, end);
// Period:用于计算两个“日期”间隔
LocalDate localDate = LocalDate.now();
LocalDate localDate1 = LocalDate.of(2017, 12, 1);
Period period = Period.between(localDate, localDate1);
//给日期加一个间隔
LocalDate localDate3 = localDate.plus(period);
System.out.println(localDate3);
}
2.3 解析与格式化
使用java.time.format.DateTimeFormatter对时间和日期进行格式化
@Test
public void test8() {
LocalDateTime localDateTime = LocalDateTime.now();
//第一种对时间日期的格式化方式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yy年MM月dd日 HH:mm:ss");
String format = formatter.format(localDateTime);
System.out.println(format);
//第二种对时间日期的格式化方式
String format1 = localDateTime.format(DateTimeFormatter.ofPattern("yy年MM月dd日"));
System.out.println(format1);
}
2.4 时区的处理
Java8 中加入了对时区的支持,带时区的时间为分别为:ZonedDate、ZonedTime、ZonedDateTime其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式例如:Asia/Shanghai 等
@Test
public void test9() {
//时区
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(ldt);
}
3 接口中的默认方法与静态方法
3.1 接口中的默认方法
Java 8中允许接口中包含具有具体实现的方法,该方法称为“默认方法”,默认方法使用default关键字修饰.
3.1.1 默认方法的使用
如
public interface MyInterface {
default String getName(){
return "呵呵呵";
}
}
一个实现这个接口的类
public class SubClass implements MyInterface{
}
在主函数中调用
public static void main(String[] args) {
SubClass sc = new SubClass();
System.out.println(sc.getName());
}
打印结果呵呵呵
3.1.2 接口默认方法的”类优先”原则
这时假如这个子类有一个父类,父类中也有一个getName()方法
public class MyClass {
public String getName(){
return "嘿嘿嘿";
}
}
子类此时是
public class SubClass extends MyClass implements MyInterface{
}
这时在主类中掉用
public static void main(String[] args) {
SubClass sc = new SubClass();
System.out.println(sc.getName());
}
结果为嘿嘿嘿
类优先原则:若一个接口中定义了一个默认方法,而另外一个父类中又定义了一个同名的方法时.
选择父类中的方法。如果父类提供了具体的实现,那么接口中具有相同名称和参数的默认方法会被忽略。
3.1.3 接口默认方法的"接口冲突"
"接口冲突":假如子类实现的多个接口中有相同的方法和参数(不管方法是否是默认方法),那么必须覆盖该方法来解决冲突
如,子类的另一个实现的接口
public interface MyFun {
default String getName(){
return "哈哈哈";
}
}
这时子类必须覆盖方法,通过接口名来指定到底调用哪一个
public class SubClass implements MyFun,MyInterface{
@Override
public String getName() {
return MyInterface.super.getName();//指定调用的接口
}
}
在主类中调用
public static void main(String[] args) {
SubClass sc = new SubClass();
System.out.println(sc.getName());
}
执行结果:呵呵呵
3.2 接口中的静态方法
Java8 中,接口中允许添加静态方法。
使用
public interface MyInterface {
static void show(){
System.out.println("接口中的静态方法");
}
}
直接使用类名调用
public static void main(String[] args) {
MyInterface.show();
}
输出结果:接口中的静态方法
java8完全解读二的更多相关文章
- java8完全解读一
java8完全解读 java8完全解读前言java8的一些新特性1.为什么要用java8?1.1首先想到的逻辑应该是如下1.2使用策略模式来解这个问题1.3使用策略模式和内部类来解决问题1.4使用策略 ...
- jQuery.Callbacks 源码解读二
一.参数标记 /* * once: 确保回调列表仅只fire一次 * unique: 在执行add操作中,确保回调列表中不存在重复的回调 * stopOnFalse: 当执行回调返回值为false,则 ...
- java多线程解读二(内存篇)
线程的内存结构图 一.主内存与工作内存 1.Java内存模型的主要目标是定义程序中各个变量的访问规则.此处的变量与Java编程时所说的变量不一样,指包括了实例字段.静态字段和构成数组对象的元素,但是不 ...
- mybatis源码解读(二)——构建Configuration对象
Configuration 对象保存了所有mybatis的配置信息,主要包括: ①. mybatis-configuration.xml 基础配置文件 ②. mapper.xml 映射器配置文件 1. ...
- (转)go语言nsq源码解读二 nsqlookupd、nsqd与nsqadmin
转自:http://www.baiyuxiong.com/?p=886 ---------------------------------------------------------------- ...
- cJONS序列化工具解读二(数据解析)
cJSON数据解析 关于数据解析部分,其实这个解析就是个自动机,通过递归或者解析栈进行实现数据的解析 /* Utility to jump whitespace and cr/lf *///用于跳过a ...
- NSObject头文件解析 / 消息机制 / Runtime解读 (二)
本章接着NSObject头文件解析 / 消息机制 / Runtime解读(一)写 给类添加属性: BOOL class_addProperty(Class cls, const char *name, ...
- Nginx 小入门记录 之 Nginx 配置文件解读(二)
上一小节主要是记录一些环境准备和Nginx的安装,接下来对Nginx基本配置进行记录. 查看配置文件安装记录 可以通过以下Linux命令进行查看: rpm -ql nginx rpm 是liunx的包 ...
- 20190925 On Java8 第二十二章 枚举
第二十二章 枚举 基本 enum 特性 创建 enum 时,编译器会为你生成一个相关的类,这个类继承自 Java.lang.Enum. valueOf() 是在 Enum 中定义的 static 方法 ...
随机推荐
- Oracle R12 多组织访问的控制 - MOAC(Multi-Org Access Control)
什么是MOAC MOAC(Multi-Org Access Control)为多组织访问控制,是Oracle EBS R12的重要新功能,它可以实现在一个Responsibility下对多个Opera ...
- OpenCV导向滤波(引导滤波)实现(Guided Filter)代码,以及使用颜色先验算法去雾
论文下载地址:http://research.microsoft.com/en-us/um/people/jiansun/papers/GuidedFilter_ECCV10.pdf 本文主要介绍导向 ...
- 理解WebKit和Chromium: Chromium插件和扩展基础
转载请注明原文地址:http://blog.csdn.net/milado_nju ##概述 插件和扩展是一种扩充浏览器功能的技术,在之前我们介绍过NPAPI插件技术,在Chromium中,远远不只是 ...
- Android源码浅析(一)——VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置
Android源码浅析(一)--VMware Workstation Pro和Ubuntu Kylin 16.04 LTS安装配置 最近地方工作,就是接触源码的东西了,所以好东西还是要分享,系列开了这 ...
- 总账追朔各模块SQL
SELECT gjh.set_of_books_id, gjl.je_line_num, mta.organization_id, ood.organization_code, ood.organiz ...
- 页面缓存js问题解决
1.在jsp中加入头 <META HTTP-EQUIV="Pragma" CONTENT="no-cache"> <META HTTP ...
- UTF-8是现在流行的编码方式,根据规定回答问题
UTF-8是现在流行的编码方式,下面是RFC2279对UTF-8编码规则的规定 UCS-4 range (hex.) UTF-8 octet sequence (binary) 0000 0000-0 ...
- Working with bounded Task Flows
Working with Bounded Task Flows, Regions and Routers in JDeveloper 11g Purpose In this tutorial, y ...
- Gradle 1.12用户指南翻译——第四十一章. 项目报告插件
本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- PS图像特效算法——百叶窗
这个只要设置好条纹的宽度和条纹的间隔,建立一个遮罩层,等间隔的对原图进行等间距的遮罩. clc; clear all; Image=imread('4.jpg'); Image=double(Imag ...