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 方法 ...
随机推荐
- C语言--字符串和数字的相互转换
1.数字转换为字符串 sprintf 跟printf 在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出. sprintf 是个变参函数,定义如下: int sp ...
- Chipmunk僵尸物理对象的出现和解决(八)
如何解决? 等到碰撞方法返回后在调用Star类方法.碰撞方法在物理引擎的一帧内应该会处理完成,在下一帧里碰撞回调已经结束.所以我们将Star类方法的调用放到下一帧里执行即可,代码如下: //... @ ...
- iOS-导航头像缩放,支持点击回调
在很多App中,经常存在一种需求就是,界面上下滚动时用户的头像也会跟着滚动,而用户头像在视图向上滚动一定范围时停留并在导航栏的位置 基本用法如下:1.单纯的实现这一效果: - (LEOHeaderVi ...
- JAVA之旅(十二)——Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口
JAVA之旅(十二)--Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口 开始挑战一些难度了,线程和I/O方面的操作了,继续坚持 一. ...
- 【一天一道LeetCode】#71. Simplify Path
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...
- [Ext.Net]TreePanel+gridPanel实例
@小花要完整例子,尝试一下图文并茂,力求完整. gridPanel TreePanel.JPG (27.49 KB, 下载次数: 16) 下载附件 保存到相册 2013-1-6 11:24 上 ...
- (四十三)UITabBarController和AppDelegate的一些细节
假设一个UITabBar是V1,V2,V3三个视图的根控制器. 一进入程序的时候,只会加载一个视图V1,也就是说UITabBar是延迟加载的. Tip:通过代码创建的UITabBar会一次性加载所有视 ...
- Python的time(时间戳与时间字符串互相转化)
strptime("string format")字符串如"20130512000000"格式的 输入处理函数 localtime(float a)时间戳的输入 ...
- 在多台PC上进行ROS通讯-学习笔记
首先,致谢易科(ExBot)和ROSWiki中文社区. 重要参考文献: Running ROS across multiple machines http://wiki.ros.org/ROS/Tut ...
- 总结C语言在嵌入式开发中应用的知识点(文件数据的加密与解密)
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...