1.增加JDK1.8中的Lambda、Stream和日期的示例代码

This commit is contained in:
xuwujing 2018-12-19 17:10:06 +08:00
parent 51450ef543
commit 5e3d7d0e16
3 changed files with 951 additions and 488 deletions

View File

@ -1,65 +1,165 @@
package com.pancm.jdk8;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.pancm.pojo.User;
/**
* @Title: LambdaTest
* @Description: 拉姆达表达式
* @Version:1.0.0
* @author pancm
* @date 2018年8月28日
*/
public class LambdaTest {
/**
* @param args
*/
public static void main(String[] args) {
test1();
test2();
}
private static void test1(){
Map<String , String> map = new HashMap<>();
map.put("a","a");
map.put("b","b");
map.put("c","c");
map.put("d","d");
map.put("e","e");
map.put("f","f");
map.forEach((k,v)->{
System.out.println("k="+k+"v="+v);
});
List<String> list = new ArrayList<String>();
list.add("aaa");
list.add("bbbbb");
list.add("ccccccc");
list.add("dddd");
list.forEach(v->{
System.out.println(v);
});
}
private static void test2(){
List<User> list = new ArrayList<User>();
List<User> list2 = new ArrayList<User>();
list.add(new User(1, "张三"));
list.add(new User(2, "李四"));
list.add(new User(3, "王五"));
list.add(new User(4, "赵六"));
System.out.println("list:"+list);
list.forEach(v->{
if(v.getId()>2){
list2.add(v);
}
});
System.out.println("list2:"+list2);
}
}
package com.pancm.jdk8;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.alibaba.fastjson.JSON;
/**
* @Title: lambdaTest
* @Description: 拉姆达表达式
*
* @Version:1.0.0
* @author pancm
* @date 2018年8月28日
*/
public class LambdaTest {
/**
* @param args
*/
public static void main(String[] args) {
test1();
test2();
}
private static void test1() {
Map<String, String> map = new HashMap<>();
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
map.put("d", "d");
System.out.println("map普通方式遍历:");
for (String key : map.keySet()) {
System.out.println("k=" + key + "v=" + map.get(key));
}
System.out.println("map拉姆达表达式遍历:");
map.forEach((k, v) -> {
System.out.println("k=" + k + "v=" + v);
});
List<String> list = new ArrayList<String>();
list.add("a");
list.add("bb");
list.add("ccc");
list.add("dddd");
System.out.println("list拉姆达表达式遍历:");
list.forEach(v -> {
System.out.println(v);
});
System.out.println("list双冒号运算符遍历:");
list.forEach(System.out::println);
}
private static void test2() {
List<User> list = new ArrayList<User>();
List<User> list2 = new ArrayList<User>();
list.add(new User(1, "张三"));
list.add(new User(2, "李四"));
list.add(new User(3, "王五"));
list.add(new User(4, "赵六"));
System.out.println("list:" + list);
list.forEach(v -> {
if (v.getId() > 2) {
list2.add(v);
}
});
System.out.println("list2:" + list2);
}
//使用普通的方式创建
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("普通方式创建!");
}
};
//使用拉姆达方式创建
Runnable r2 = ()-> System.out.println("拉姆达方式创建!");
}
class User {
/** 编号 */
private int id;
/** 姓名 */
private String name;
public User() {
}
/**
* 构造方法
*
* @param id 编号
* @param name 姓名
*/
public User(int id, String name) {
super();
this.id = id;
this.name = name;
}
/**
* 获取编号
*
* @return id
*/
public int getId() {
return id;
}
/**
* 设置编号
*
* @param id
*/
public void setId(int id) {
this.id = id;
}
/**
* 获取姓名
*
* @return name
*/
public String getName() {
System.out.println("姓名:" + name);
return name;
}
/**
* 设置姓名
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
@SuppressWarnings("rawtypes")
public Map toMap() {
return JSON.parseObject(toString(), HashMap.class);
}
/**
*
*/
@Override
public String toString() {
return "{\"id\":\"" + id + "\",\"name\":\"" + name + "\"}";
}
}

View File

@ -0,0 +1,228 @@
package com.pancm.jdk8;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
/**
* @Title: timeTest
* @Description:
* 时间测试
* @Version:1.0.0
* @author pancm
* @date 2018年6月21日
*/
public class LocalDateTimeTest {
/**
* @param args
*/
public static void main(String[] args) {
/*
新版API中java.time包里的一些关键类
Instant瞬时实例
LocalDate本地日期不包含具体时间 例如2014-01-14 可以用来记录生日纪念日加盟日等
LocalTime本地时间不包含日期
LocalDateTime组合了日期和时间但不包含时差和时区信息
ZonedDateTime最完整的日期时间包含时区和相对UTC或格林威治的时差
Java 8日期时间API 使用说明:
1提供了javax.time.ZoneId 获取时区
2提供了LocalDate和LocalTime类
3Java 8 的所有日期和时间API都是不可变类并且线程安全而现有的Date和Calendar API中的java.util.Date和SimpleDateFormat是非线程安全的
4主包是 java.time,包含了表示日期时间时间间隔的一些类里面有两个子包java.time.format用于格式化 java.time.temporal用于更底层的操作
5时区代表了地球上某个区域内普遍使用的标准时间每个时区都有一个代号格式通常由区域/城市构成Asia/Tokyo在加上与格林威治或 UTC的时差例如东京的时差是+09:00
6OffsetDateTime类实际上组合了LocalDateTime类和ZoneOffset类用来表示包含和格林威治或UTC时差的完整日期和时间纳秒信息
7DateTimeFormatter 类用来格式化和解析时间与SimpleDateFormat不同这个类不可变并且线程安全需要时可以给静态常量赋值 DateTimeFormatter类提供了大量的内置格式化工具同时也允许你自定义在转换方面也提供了parse()将字符串解析成日期如果解析出错会抛出DateTimeParseExceptionDateTimeFormatter类同时还有format()用来格式化日期如果出错会抛出DateTimeException异常
8再补充一点日期格式MMM d yyyyMMM dd yyyy有一些微妙的不同第一个格式可以解析Jan 2 2014Jan 14 2014而第二个在解析Jan 2 2014就会抛异常因为第二个格式里要求日必须是两位的如果想修正你必须在日期只有个位数时在前面补零就是说Jan 2 2014应该写成 Jan 02 2014
*/
test1();
test2();
test3();
test4();
}
/**
*
*/
private static void test1(){
/*
* 获取当前时间
*/
//本地日期,不包括时分秒
LocalDate nowDate = LocalDate.now();
//本地日期,包括时分秒
LocalDateTime nowDateTime = LocalDateTime.now();
System.out.println("当前时间:"+nowDate);
System.out.println("当前时间:"+nowDateTime);
// 当前时间:2018-12-19
// 当前时间:2018-12-19T15:24:35.822
/*
* 格式化时间
*/
LocalDate ld=LocalDate.parse("2017-11-17");
LocalDate ld2=LocalDate.parse("2018-01-05");
/**
* 创建指定日期
*/
LocalDate ld3=LocalDate.of(2017, Month.NOVEMBER, 17);
LocalDate ld4=LocalDate.of(2018, 02, 11);
//jdk1.8的类用于比较时间
//可以得到相差年
Period p=Period.between(ld, ld2);
System.out.println("相差年: "+p.getYears()+" 相差月 :"+p.getMonths() +" 相差天:"+p.getDays());
// 相差年: 0 相差月 :1 相差天:19
System.out.println("增加2个月: "+ld.plusMonths(2));
Period p2=Period.between(ld3, ld4);
System.out.println("相差年: "+p2.getYears()+" 相差月 :"+p2.getMonths() +" 相差天:"+p2.getDays()+"--"+p2.toTotalMonths());
//相差年: 0 相差月 :2 相差天:25
}
/**
* 时间测试
*/
private static void test2(){
// String time="2018-06-29 09:19:45.498";
String time2="2018-01-04T09:19:29.499";
//格式化时间
LocalDateTime ldt2=LocalDateTime.parse(time2);
//获取当前的时间包括毫秒
LocalDateTime ldt = LocalDateTime.now();
System.out.println("当前年:"+ldt.getYear()); //2018
System.out.println("当前年份天数:"+ldt.getDayOfYear());//172
System.out.println("当前月:"+ldt.getMonthValue());
System.out.println("当前时:"+ldt.getHour());
System.out.println("当前分:"+ldt.getMinute());
System.out.println("当前时间:"+ldt.toString());
// 当前年:2018
// 当前年份天数:353
// 当前月:12
// 当前时:15
// 当前分:24
// 当前时间:2018-12-19T15:24:35.833
System.out.println("格式化时间: "+ ldt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
//格式化时间:2018-12-19 15:37:47.119
System.out.println("后5天时间:"+ldt.plusDays(5));
System.out.println("前5天时间并格式化:"+ldt.minusDays(5).format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); //2018-06-16
System.out.println("前一个月的时间:"+ldt2.minusMonths(1).format(DateTimeFormatter.ofPattern("yyyyMM"))); //2018-06-16
System.out.println("后一个月的时间:"+ldt2.plusMonths(1)); //2018-06-16
System.out.println("指定2099年的当前时间:"+ldt.withYear(2099)); //2099-06-21T15:07:39.506
// 后5天时间:2018-12-24T15:50:37.508
// 前5天时间并格式化:2018-12-14
// 前一个月的时间:201712
// 后一个月的时间:2018-02-04T09:19:29.499
// 指定2099年的当前时间:2099-12-19T15:50:37.508
System.out.println("得到的时间:"+ldt2.toString());
System.out.println("格式化时间:"+ldt2.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
/*
*
通过 Clock时钟类用于获取当时的时间戳或当前时区下的日期时间信息
*/
Clock clock = Clock.systemUTC();
System.out.println("当前时间戳 : " + clock.millis());
Clock clock2 = Clock.system(ZoneId.of("Asia/Shanghai"));
System.out.println("亚洲上海此时的时间戳:"+clock2.millis());
Clock clock3 = Clock.system(ZoneId.of("America/New_York"));
System.out.println("美国纽约此时的时间戳:"+clock3.millis());
// 当前时间戳 : 1545209277657
// 亚洲上海此时的时间戳:1545209277657
// 美国纽约此时的时间戳:1545209277658
/*
* 时区计算
*/
ZoneId zoneId= ZoneId.of("America/New_York");
ZonedDateTime dateTime=ZonedDateTime.now(zoneId);
System.out.println("美国纽约此时的时间 : " + dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")));
System.out.println("美国纽约此时的时间 和时区: " + dateTime);
// 美国纽约此时的时间 : 2018-12-19 03:52:22.494
// 美国纽约此时的时间 和时区: 2018-12-19T03:52:22.494-05:00[America/New_York]
/**
*
* 时间比较
*/
LocalDateTime ldt4 = LocalDateTime.now();
LocalDateTime ldt5 = ldt4.plusMinutes(10);
System.out.println("当前时间是否大于:"+ldt4.isAfter(ldt5));
System.out.println("当前时间是否小于"+ldt4.isBefore(ldt5));
// false
// true
}
/**
*
*/
private static void test3(){
/*
* Duration 这个类以秒和纳秒为单位建模时间的数量或数量
*/
Instant inst1 = Instant.now();
System.out.println("当前时间戳: " + inst1);
Instant inst2 = inst1.plus(Duration.ofSeconds(10));
System.out.println("增加之后的时间 : " + inst2);
System.out.println("相差毫秒 : " + Duration.between(inst1, inst2).toMillis());
System.out.println("相毫秒 : " + Duration.between(inst1, inst2).getSeconds());
// 当前时间戳 : 2018-12-19T08:14:21.675Z
// 增加之后的时间 : 2018-12-19T08:14:31.675Z
// 相差毫秒 : 10000
// 相毫秒 : 10
}
/**
* 单个时间单位内测量一段时间
*/
private static void test4(){
/*
* ChronoUnit 日期周期单位的标准集合
*/
LocalDate startDate = LocalDate.of(2017, 11, 17);
LocalDate endDate = LocalDate.of(2018, 01, 05);
System.out.println("相差月份:"+ChronoUnit.MONTHS.between(startDate, endDate));
System.out.println("两月之间的相差的天数 : " + ChronoUnit.DAYS.between(startDate, endDate));
// 相差月份:1
// 两天之间的差在天数 : 49
}
}

View File

@ -1,423 +1,558 @@
package com.pancm.jdk8;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.Stack;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import com.pancm.pojo.User;
/**
* @Title: StreamTest
* @Description: Stream测试用例 流的操作类型分为两种
*
* Intermediate一个流可以后面跟随零个或多个 intermediate
* 操作其目的主要是打开流做出某种程度的数据映射/过滤然后返回一个新的流交给下一个操作使用
* 这类操作都是惰性化的lazy就是说仅仅调用到这类方法并没有真正开始流的遍历 Terminal一个流只能有一个
* terminal 操作当这个操作执行后流就被使用无法再被操作 所以这必定是流的最后一个操作 Terminal
* 操作的执行才会真正开始流的遍历并且会生成一个结果或者一个 side effect
* @Version:1.0.0
* @author pancm
* @date 2018年9月3日
*/
public class StreamTest {
/**
* @param args
*/
public static void main(String[] args) {
test1();
test2();
test3();
test4();
/*
* Stream 的特性可以归纳为
不是数据结构
它没有内部存储它只是用操作管道从 source数据结构数组generator functionIO channel抓取数据
它也绝不修改自己所封装的底层数据结构的数据例如 Stream filter 操作会产生一个不包含被过滤元素的新 Stream而不是从 source 删除那些元素
所有 Stream 的操作必须以 lambda 表达式为参数
不支持索引访问
你可以请求第一个元素但无法请求第二个第三个或最后一个不过请参阅下一项
很容易生成数组或者 List
惰性化
很多 Stream 操作是向后延迟的一直到它弄清楚了最后需要多少数据才会开始
Intermediate 操作永远是惰性化的
并行能力
当一个 Stream 是并行化的就不需要再写多线程代码所有对它的操作会自动并行进行的
可以是无限的
集合有固定大小Stream 则不必limit(n) findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成
*/
}
/**
* 简单实用
*/
private static void test1() {
/*
* 普通的方式过滤
*/
List<String> list = Arrays.asList("张三", "李四", "王五");
System.out.println("过滤之前:" + list);
List<String> result = new ArrayList<>();
for (String str : list) {
if (!"李四".equals(str)) {
result.add(str);
}
}
System.out.println("过滤之后:" + result);
/*
* stream 过滤
*/
List<String> result2 = list.stream().filter(str -> !"李四".equals(str)).collect(Collectors.toList());
System.out.println("stream 过滤之后:" + result2);
// 另一种方式输出
result2.forEach(System.out::println);
// 使用stream.filter ()过滤一列表.findAny().orElse
// 遍历该list查询数据如果查不到就返回 找不到!
String result3 = list.stream().filter(str -> "李四".equals(str)).findAny().orElse("找不到!");
String result4 = list.stream().filter(str -> "李二".equals(str)).findAny().orElse("找不到!");
System.out.println("stream 过滤之后 2:" + result3);
System.out.println("stream 过滤之后 3:" + result4);
}
/**
* 基本使用
*/
@SuppressWarnings({ "unchecked", "rawtypes", "unused" })
private static void test2() {
/*
* 构造流的几种方式
*/
Stream stream = Stream.of("a", "b", "c");
String[] strArray = new String[] { "a", "b", "c" };
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
List<String> list = Arrays.asList(strArray);
stream = list.stream();
/*
* 流之间的相互转化 一个 Stream 只可以使用一次这段代码为了简洁而重复使用了数次因此会抛出异常
*/
try {
Stream<String> stream2 = Stream.of("a", "b", "c");
// 转换成 Array
String[] strArray1 = stream2.toArray(String[]::new);
// 转换成 Collection
List<String> list1 = stream2.collect(Collectors.toList());
List<String> list2 = stream2.collect(Collectors.toCollection(ArrayList::new));
Set set1 = stream2.collect(Collectors.toSet());
Stack stack1 = stream2.collect(Collectors.toCollection(Stack::new));
// 转换成 String
String str = stream.collect(Collectors.joining()).toString();
} catch (Exception e) {
e.printStackTrace();
}
/*
* 汇总操作
*/
List<User> lists = new ArrayList<User>();
lists.add(new User(6, "张三"));
lists.add(new User(2, "李四"));
lists.add(new User(3, "王五"));
lists.add(new User(1, "张三"));
// 计算这个list中出现 "张三" id的值
int sum = lists.stream().filter(u -> "张三".equals(u.getName())).mapToInt(u -> u.getId()).sum();
System.out.println("计算结果:" + sum); // 7
/*
* 数值类型的流 包括IntStream, LongStream和DoubleStream
*/
System.out.println("遍历输出该数组的数据:");
IntStream.of(new int[] { 1, 2, 3, 4 }).forEach(System.out::println);
System.out.println("查询范围在 2-3(2<=i<3)之间的数据:");
IntStream.range(2, 3).forEach(System.out::println);
System.out.println("查询范围在2-3(2<=i<=3)之间的数据:");
IntStream.rangeClosed(2, 3).forEach(System.out::println);
/* stream中的 map使用 */
/*
* 转换大写
*/
List<String> list3 = Arrays.asList("zhangSan", "liSi", "wangWu");
System.out.println("转换之前的数据:" + list3);// 转换之前的数据:[zhangSan, liSi,
// wangWu]
List<String> list4 = list3.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println("转换之后的数据:" + list4); // 转换之后的数据:[ZHANGSAN, LISI,
// WANGWU]
/*
* 转换数据类型
*/
List<String> list31 = Arrays.asList("1", "2", "3");
System.out.println("转换之前的数据:" + list31);// 转换之前的数据:[1, 2, 3]
List<Integer> list41 = list31.stream().map(Integer::valueOf).collect(Collectors.toList());
System.out.println("转换之后的数据:" + list41); // [1, 2, 3]
/*
* 转换数据类型
* 对象转map
*/
List<User> list32 = new ArrayList<User>();
for(int i=1;i<=10;i++){
list32.add(new User(i,"张三"+i));
}
System.out.println("转换之前的数据:" + list32);// 转换之前的数据:[1, 2, 3]
List<Map> list42 = list32.stream().map(User::toMap).collect(Collectors.toList());
System.out.println("转换之后的数据:" + list42); // [1, 2, 3]
/*
* 获取平方
*/
List<Integer> list5 = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 });
List<Integer> list6 = list5.stream().map(n -> n * n).collect(Collectors.toList());
System.out.println("平方的数据:" + list6);// 转换之前的数据:[1, 4, 9, 16, 25]
/*
* flatMap 一对多 得到多个数组里面的数字
*/
Stream<List<Integer>> inputStream = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6));
Stream<Integer> outputStream = inputStream.flatMap((childList) -> childList.stream());
System.out.println("打印 stream中的数字:");
outputStream.forEach(System.out::println);
/*
* 得到一段句子中的单词
*/
String worlds = "Never let success get to your head and never let failure get to your heart.";
List<String> list7 = new ArrayList<>();
list7.add(worlds);
List<String> list8 = list7.stream().flatMap(str -> Stream.of(str.split(" ")))
.filter(world -> world.length() > 0).collect(Collectors.toList());
System.out.println("单词:");
list8.forEach(System.out::println);
/*
* peek 对每个元素执行操作并返回一个新的 Stream
*/
System.out.println("peek使用:");
Stream.of("one", "two", "three", "four").filter(e -> e.length() > 3).peek(e -> System.out.println("转换之前: " + e))
.map(String::toUpperCase).peek(e -> System.out.println("转换之后: " + e)).collect(Collectors.toList());
/*
* limit skip limit 返回 Stream 的前面 n 个元素skip 则是扔掉前 n 个元素它是由一个叫
* subStream 的方法改名而来
*/
List<User> list9 = new ArrayList<User>();
for (int i = 1; i < 10; i++) {
User user = new User(i, "pancm" + i);
list9.add(user);
}
System.out.println("截取之前的数据:");
// 取前5条数据但是扔掉了前面的3条可以理解为拿到的数据为 3<=i<5 (i 是数值下标)
List<String> list10 = list9.stream().map(User::getName).limit(5).skip(3).collect(Collectors.toList());
System.out.println("截取之后的数据:" + list10);
/*
* sort 进行排序 先获取在排序效率更高
*/
System.out.println("排序之前的数据:");
List<User> list11 = list9.stream().sorted((u1, u2) -> u1.getName().compareTo(u2.getName())).limit(3)
.collect(Collectors.toList());
System.out.println("排序之后的数据:" + list11);
List<User> list12 = list9.stream().limit(3).sorted((u1, u2) -> u1.getName().compareTo(u2.getName()))
.collect(Collectors.toList());
System.out.println("优化排序之后的数据:" + list12);
/*
* min/max/distinct
* 最大最小和去重
*/
BufferedReader br;
int longest = 0;
List<String> words = null;
try {
br = new BufferedReader(new FileReader("test.properties"));
longest = br.lines().mapToInt(String::length).max().getAsInt();
br.close();
} catch (IOException e1) {
e1.printStackTrace();
}
System.out.println("test.properties 最长的字符串的长度是:" + longest);
String lines = "good good study day day up";
List<String> list13 = new ArrayList<String>();
list13.add(lines);
words = list13.stream().flatMap(line -> Stream.of(line.split(" "))).filter(word -> word.length() > 0)
.map(String::toLowerCase).distinct().sorted().collect(Collectors.toList());
System.out.println("去重复之后:" + words);
/*
* Match 匹配
*
* allMatchStream 中全部元素符合传入的 predicate返回 true anyMatchStream
* 中只要有一个元素符合传入的 predicate返回 true noneMatchStream 中没有一个元素符合传入的
* predicate返回 true
*/
boolean all = lists.stream().allMatch(u -> u.getId() > 3);
System.out.println("是否都大于3:" + all);
boolean any = lists.stream().anyMatch(u -> u.getId() > 3);
System.out.println("是否有一个大于3:" + any);
boolean none = lists.stream().noneMatch(u -> u.getId() > 3);
System.out.println("是否没有一个大于3的:" + none);
/*
* 生成随机数 通过实现 Supplier 接口你可以自己来控制流的生成这种情形通常用于随机数常量的
* Stream或者需要前后元素间维持着某种状态信息的 Stream Supplier 实例传递给 Stream.generate()
* 生成的 Stream默认是串行相对 parallel 而言但无序的相对 ordered 而言
* 由于它是无限的在管道中必须利用 limit 之类的操作限制 Stream 大小
*/
Random seed = new Random();
Supplier<Integer> random = seed::nextInt;
System.out.println("生成5个随机数:");
Stream.generate(random).limit(5).forEach(System.out::println);
System.out.println("生成5正整数的随机数:");
IntStream.generate(() -> (int) (System.nanoTime() % 100)).limit(5).forEach(System.out::println);
}
/**
* 一些关联使用
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static void test3() {
/*
* Optional
*/
String strA = " abcd ", strB = null;
System.out.println("数据校验开始...");
print(strA);
print("");
print(strB);
getLength(strA);
getLength("");
getLength(strB);
System.out.println("数据校验结束...");
/*
* reduce 主要作用是把 Stream 元素组合起来
*/
// 字符串连接concat = "ABCD"
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
System.out.println("字符串拼接:" + concat);
// 求最小值minValue = -3.0
double minValue = Stream.of(-1.5, 1.0, -3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
System.out.println("最小值:" + minValue);
// 求和sumValue = 10, 有起始值
int sumValue = Stream.of(1, 2, 3, 4).reduce(0, Integer::sum);
System.out.println("求和:" + sumValue);
// 求和sumValue = 10, 无起始值
sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
System.out.println("求和:" + sumValue);
// 过滤字符串连接concat = "ace"
concat = Stream.of("a", "B", "c", "D", "e", "F").filter(x -> x.compareTo("Z") > 0).reduce("", String::concat);
System.out.println("过滤和字符串连接:" + concat);
/*
* iterate iterate reduce 操作很像接受一个种子值和一个 UnaryOperator例如 f
* 然后种子值成为 Stream 的第一个元素f(seed) 为第二个f(f(seed)) 第三个以此类推 iterate
* 时候管道必须有 limit 这样的操作来限制 Stream 大小
*/
// 生成一个等差队列
Stream.iterate(0, n -> n + 3).limit(10).forEach(x -> System.out.print(x + " "));
/*
* 分组排序 groupingBy/partitioningBy
*/
// 通过id进行排序
System.out.println("通过id进行分组排序:");
Map<Integer, List<User>> personGroups = Stream.generate(new UserSupplier2()).limit(5)
.collect(Collectors.groupingBy(User::getId));
Iterator it = personGroups.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, List<User>> persons = (Map.Entry) it.next();
System.out.println("id " + persons.getKey() + " = " + persons.getValue());
}
//通过年龄排序
System.out.println("进行分区排序:");
Map<Boolean, List<User>> children = Stream.generate(new UserSupplier2()).limit(5)
.collect(Collectors.partitioningBy(p -> p.getId() < 18));
System.out.println("小孩: " + children.get(true));
System.out.println("成年人: " + children.get(false));
}
/**
* 自定义流
*/
private static void test4() {
/*
* 自定义一个流 然后进行输出
*/
Stream.generate(new UserSupplier()).limit(2).forEach(u -> System.out.println(u.getId() + ", " + u.getName()));
}
public static void print(String text) {
// jdk1.8之前的写法
// if (text != null) {
// System.out.println(text);
// }
// jdk1.8的写法
Optional.ofNullable(text).ifPresent(System.out::println);
}
public static void getLength(String text) {
// jdk1.8之前的写法
// return if (text != null) ? text.length() : -1;
// jdk1.8的写法
int i = Optional.ofNullable(text).map(String::length).orElse(-1);
System.out.println("数据:" + i);
};
}
class UserSupplier implements Supplier<User> {
private int index = 10;
private Random random = new Random();
@Override
public User get() {
return new User(index++, "pancm" + random.nextInt(10));
}
}
class UserSupplier2 implements Supplier<User> {
private int index = 10;
private Random random = new Random();
@Override
public User get() {
return new User(index % 2 == 0 ? index++ : index, "pancm" + random.nextInt(10));
}
}
package com.pancm.jdk8;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.Stack;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* @Title: StreamTest
* @Description: Stream测试用例 流的操作类型分为两种
*
* Intermediate一个流可以后面跟随零个或多个 intermediate
* 操作其目的主要是打开流做出某种程度的数据映射/过滤然后返回一个新的流交给下一个操作使用
* 这类操作都是惰性化的lazy就是说仅仅调用到这类方法并没有真正开始流的遍历 Terminal一个流只能有一个
* terminal 操作当这个操作执行后流就被使用无法再被操作 所以这必定是流的最后一个操作 Terminal
* 操作的执行才会真正开始流的遍历并且会生成一个结果或者一个 side effect
* @Version:1.0.0
* @author pancm
* @date 2018年9月3日
*/
public class StreamTest {
/**
* @param args
*/
public static void main(String[] args) {
test1();
test2();
test3();
test4();
/*
* Stream 的特性可以归纳为
不是数据结构
它没有内部存储它只是用操作管道从 source数据结构数组generator functionIO channel抓取数据
它也绝不修改自己所封装的底层数据结构的数据例如 Stream filter 操作会产生一个不包含被过滤元素的新 Stream而不是从 source 删除那些元素
所有 Stream 的操作必须以 lambda 表达式为参数
不支持索引访问
你可以请求第一个元素但无法请求第二个第三个或最后一个不过请参阅下一项
很容易生成数组或者 List
惰性化
很多 Stream 操作是向后延迟的一直到它弄清楚了最后需要多少数据才会开始
Intermediate 操作永远是惰性化的
并行能力
当一个 Stream 是并行化的就不需要再写多线程代码所有对它的操作会自动并行进行的
可以是无限的
集合有固定大小Stream 则不必limit(n) findFirst() 这类的 short-circuiting 操作可以对无限的 Stream 进行运算并很快完成
*/
}
/**
* 简单实用
*/
private static void test1() {
/*
* 普通的方式过滤
*/
List<String> list = Arrays.asList("张三", "李四", "王五", "xuwujing");
System.out.println("过滤之前:" + list);
List<String> result = new ArrayList<>();
for (String str : list) {
if (!"李四".equals(str)) {
result.add(str);
}
}
System.out.println("过滤之后:" + result);
/*
* stream 过滤
*/
List<String> result2 = list.stream().filter(str -> !"李四".equals(str)).collect(Collectors.toList());
System.out.println("stream 过滤之后:" + result2);
// 另一种方式输出
result2.forEach(System.out::println);
// 使用stream.filter ()过滤一列表.findAny().orElse
// 遍历该list查询数据如果查不到就返回 找不到!
String result3 = list.stream().filter(str -> "李四".equals(str)).findAny().orElse("找不到!");
String result4 = list.stream().filter(str -> "李二".equals(str)).findAny().orElse("找不到!");
System.out.println("stream 过滤之后 2:" + result3);
System.out.println("stream 过滤之后 3:" + result4);
//stream 过滤之后 2:李四
//stream 过滤之后 3:找不到!
}
/**
* 基本使用
*/
@SuppressWarnings({ "unchecked", "rawtypes", "unused" })
private static void test2() {
/*
* 构造流的几种方式
*/
Stream stream = Stream.of("a", "b", "c");
String[] strArray = new String[] { "a", "b", "c" };
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);
List<String> list = Arrays.asList(strArray);
stream = list.stream();
/*
* 流之间的相互转化 一个 Stream 只可以使用一次这段代码为了简洁而重复使用了数次因此会抛出异常
*/
try {
Stream<String> stream2 = Stream.of("a", "b", "c");
// 转换成 Array
String[] strArray1 = stream2.toArray(String[]::new);
// 转换成 Collection
List<String> list1 = stream2.collect(Collectors.toList());
List<String> list2 = stream2.collect(Collectors.toCollection(ArrayList::new));
Set set1 = stream2.collect(Collectors.toSet());
Stack stack1 = stream2.collect(Collectors.toCollection(Stack::new));
// 转换成 String
String str = stream.collect(Collectors.joining()).toString();
} catch (Exception e) {
e.printStackTrace();
}
/*
* 汇总操作
*/
List<User> lists = new ArrayList<User>();
lists.add(new User(6, "张三"));
lists.add(new User(2, "李四"));
lists.add(new User(3, "王五"));
lists.add(new User(1, "张三"));
// 计算这个list中出现 "张三" id的值
int sum = lists.stream().filter(u -> "张三".equals(u.getName())).mapToInt(u -> u.getId()).sum();
System.out.println("计算结果:" + sum);
// 7
/*
* 数值类型的流 包括IntStream, LongStream和DoubleStream
*/
System.out.println("遍历输出该数组的数据:");
IntStream.of(new int[] { 1, 2, 3, 4 }).forEach(System.out::println);
System.out.println("查询范围在 2-3(2<=i<3)之间的数据:");
IntStream.range(2, 3).forEach(System.out::println);
System.out.println("查询范围在2-3(2<=i<=3)之间的数据:");
IntStream.rangeClosed(2, 3).forEach(System.out::println);
/* stream中的 map使用 */
/*
* 转换大写
*/
List<String> list3 = Arrays.asList("zhangSan", "liSi", "wangWu");
System.out.println("转换之前的数据:" + list3);
List<String> list4 = list3.stream().map(String::toUpperCase).collect(Collectors.toList());
System.out.println("转换之后的数据:" + list4);
// 转换之后的数据:[ZHANGSAN, LISI,WANGWU]
/*
* 转换数据类型
*/
List<String> list31 = Arrays.asList("1", "2", "3");
System.out.println("转换之前的数据:" + list31);
List<Integer> list41 = list31.stream().map(Integer::valueOf).collect(Collectors.toList());
System.out.println("转换之后的数据:" + list41);
// [1, 2, 3]
/*
* 转换数据类型
* 对象转map
*/
List<User> list32 = new ArrayList<User>();
for(int i=1;i<=10;i++){
list32.add(new User(i,"张三"+i));
}
System.out.println("转换之前的数据:" + list32);// 转换之前的数据:[1, 2, 3]
List<Map> list42 = list32.stream().map(User::toMap).collect(Collectors.toList());
System.out.println("转换之后的数据:" + list42); // [1, 2, 3]
/*
* 获取平方
*/
List<Integer> list5 = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5 });
List<Integer> list6 = list5.stream().map(n -> n * n).collect(Collectors.toList());
System.out.println("平方的数据:" + list6);
// [1, 4, 9, 16, 25]
/*
* flatMap 一对多 得到多个数组里面的数字
*/
Stream<List<Integer>> inputStream = Stream.of(Arrays.asList(1), Arrays.asList(2, 3), Arrays.asList(4, 5, 6));
Stream<Integer> outputStream = inputStream.flatMap((childList) -> childList.stream());
System.out.println("打印 stream中的数字:");
outputStream.forEach(System.out::println);
/*
* 得到一段句子中的单词
*/
String worlds = "The way of the future";
List<String> list7 = new ArrayList<>();
list7.add(worlds);
List<String> list8 = list7.stream().flatMap(str -> Stream.of(str.split(" ")))
.filter(world -> world.length() > 0).collect(Collectors.toList());
System.out.println("单词:");
list8.forEach(System.out::println);
// 单词:
// The
// way
// of
// the
// future
/*
* peek 对每个元素执行操作并返回一个新的 Stream
*/
System.out.println("peek使用:");
Stream.of("one", "two", "three", "four").filter(e -> e.length() > 3).peek(e -> System.out.println("转换之前: " + e))
.map(String::toUpperCase).peek(e -> System.out.println("转换之后: " + e)).collect(Collectors.toList());
// 转换之前: three
// 转换之后: THREE
// 转换之前: four
// 转换之后: FOUR
/*
* limit skip limit 返回 Stream 的前面 n 个元素skip 则是扔掉前 n 个元素它是由一个叫
* subStream 的方法改名而来
*/
//limit 简单使用
Random rd = new Random();
System.out.println("取到的前三条数据:");
rd.ints().limit(3).forEach(System.out::println);
// 取到的前三条数据:
// 1167267754
// -1164558977
// 1977868798
List<User> list9 = new ArrayList<User>();
for (int i = 1; i < 4; i++) {
User user = new User(i, "pancm" + i);
list9.add(user);
}
System.out.println("截取之前的数据:");
// 取前3条数据但是扔掉了前面的2条可以理解为拿到的数据为 2<=i<3 (i 是数值下标)
List<String> list10 = list9.stream().map(User::getName).limit(3).skip(2).collect(Collectors.toList());
System.out.println("截取之后的数据:" + list10);
// 截取之前的数据:
// 姓名:pancm1
// 姓名:pancm2
// 姓名:pancm3
// 截取之后的数据:[pancm3]
/*
* sort 进行排序 先获取在排序效率更高
*/
Random rd2 = new Random();
System.out.println("取到的前三条数据然后进行排序:");
rd2.ints().limit(3).sorted().forEach(System.out::println);
// 取到的前三条数据然后进行排序:
// -2043456377
// -1778595703
// 1013369565
//普通的排序取值
List<User> list11 = list9.stream().sorted((u1, u2) -> u1.getName().compareTo(u2.getName())).limit(3)
.collect(Collectors.toList());
System.out.println("排序之后的数据:" + list11);
//优化排序取值
List<User> list12 = list9.stream().limit(3).sorted((u1, u2) -> u1.getName().compareTo(u2.getName()))
.collect(Collectors.toList());
System.out.println("优化排序之后的数据:" + list12);
//排序之后的数据:[{"id":1,"name":"pancm1"}, {"id":2,"name":"pancm2"}, {"id":3,"name":"pancm3"}]
//优化排序之后的数据:[{"id":1,"name":"pancm1"}, {"id":2,"name":"pancm2"}, {"id":3,"name":"pancm3"}]
/*
* min/max/distinct
* 最大最小和去重
*/
List<String> list13 = Arrays.asList("zhangsan","lisi","wangwu","xuwujing");
int maxLines = list13.stream().mapToInt(String::length).max().getAsInt();
int minLines = list13.stream().mapToInt(String::length).min().getAsInt();
System.out.println("最长字符的长度:" + maxLines+",最短字符的长度:"+minLines);
//最长字符的长度:8,最短字符的长度:4
String lines = "good good study day day up";
List<String> list14 = new ArrayList<String>();
list14.add(lines);
List<String> words = list14.stream().flatMap(line -> Stream.of(line.split(" "))).filter(word -> word.length() > 0)
.map(String::toLowerCase).distinct().sorted().collect(Collectors.toList());
System.out.println("去重复之后:" + words);
//去重复之后:[day, good, study, up]
/*
* Match 匹配
*
* allMatchStream 中全部元素符合则返回 true ;
* anyMatchStream 中只要有一个元素符合则返回 true;
* noneMatchStream 中没有一个元素符合则返回 true
*/
boolean all = lists.stream().allMatch(u -> u.getId() > 3);
System.out.println("是否都大于3:" + all);
boolean any = lists.stream().anyMatch(u -> u.getId() > 3);
System.out.println("是否有一个大于3:" + any);
boolean none = lists.stream().noneMatch(u -> u.getId() > 3);
System.out.println("是否没有一个大于3的:" + none);
// 是否都大于3:false
// 是否有一个大于3:true
// 是否没有一个大于3的:false
/*
* 生成随机数 通过实现 Supplier 接口你可以自己来控制流的生成这种情形通常用于随机数常量的
* Stream或者需要前后元素间维持着某种状态信息的 Stream Supplier 实例传递给 Stream.generate()
* 生成的 Stream默认是串行相对 parallel 而言但无序的相对 ordered 而言
* 由于它是无限的在管道中必须利用 limit 之类的操作限制 Stream 大小
*/
Random seed = new Random();
seed.ints().limit(3).forEach(System.out::println);
Supplier<Integer> random = seed::nextInt;
System.out.println("生成5个随机数:");
Stream.generate(random).limit(3).forEach(System.out::println);
System.out.println("生成5正整数的随机数:");
IntStream.generate(() -> (int) (System.nanoTime() % 100)).limit(3).forEach(System.out::println);
System.out.println("生成5个随机数:");
/*
并行parallel程序
parallelStream 是流并行处理程序的代替方法
*/
List<String> strings = Arrays.asList("a", "", "c", "", "e","", " ");
// 获取空字符串的数量
long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
System.out.println("空字符串的个数:"+count);
/*
* 合并字符串
*/
List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
System.out.println("筛选列表: " + filtered);
String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(", "));
System.out.println("合并字符串: " + mergedString);
// 筛选列表: [a, c, e, ]
// 合并字符串: a, c, e,
}
/**
* 一些关联使用
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
private static void test3() {
/*
* Optional
*/
String strA = " abcd ", strB = null;
System.out.println("数据校验开始...");
print(strA);
print("");
print(strB);
getLength(strA);
getLength("");
getLength(strB);
System.out.println("数据校验结束...");
/*
* reduce 主要作用是把 Stream 元素组合起来
*/
// 字符串连接concat = "ABCD"
String concat = Stream.of("A", "B", "C", "D").reduce("", String::concat);
System.out.println("字符串拼接:" + concat);
//字符串拼接:ABCD
// 求最小值
double minValue = Stream.of(-4.0, 1.0, 3.0, -2.0).reduce(Double.MAX_VALUE, Double::min);
System.out.println("最小值:" + minValue);
//最小值:-4.0
// 求和, 无起始值
int sumValue = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
System.out.println("有无起始值求和:" + sumValue);
// 求和, 有起始值
sumValue = Stream.of(1, 2, 3, 4).reduce(1, Integer::sum);
System.out.println("有起始值求和:" + sumValue);
// 有无起始值求和:10
// 有起始值求和:11
// 过滤字符串连接concat = "ace"
concat = Stream.of("a", "B", "c", "D", "e", "F").filter(x -> x.compareTo("Z") > 0).reduce("", String::concat);
System.out.println("过滤和字符串连接:" + concat);
//过滤和字符串连接:ace
/*
* iterate iterate reduce 操作很像接受一个种子值和一个 UnaryOperator例如 f
* 然后种子值成为 Stream 的第一个元素f(seed) 为第二个f(f(seed)) 第三个以此类推 iterate
* 时候管道必须有 limit 这样的操作来限制 Stream 大小
*/
System.out.println("从2开始生成一个等差队列:");
Stream.iterate(2, n -> n + 2).limit(5).forEach(x -> System.out.print(x + " "));
// 从2开始生成一个等差队列:
// 2 4 6 8 10
System.out.println("\n");
/*
* 分组排序 groupingBy/partitioningBy
*/
// 通过id进行排序
System.out.println("通过id进行分组排序:");
Map<Integer, List<User>> personGroups = Stream.generate(new UserSupplier2()).limit(5)
.collect(Collectors.groupingBy(User::getId));
Iterator it = personGroups.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, List<User>> persons = (Map.Entry) it.next();
System.out.println("id " + persons.getKey() + " = " + persons.getValue());
}
// 通过id进行分组排序:
// id 10 = [{"id":10,"name":"pancm1"}]
// id 11 = [{"id":11,"name":"pancm3"}, {"id":11,"name":"pancm6"}, {"id":11,"name":"pancm4"}, {"id":11,"name":"pancm7"}]
//通过年龄排序
System.out.println("通过年龄进行分区排序:");
Map<Boolean, List<User>> children = Stream.generate(new UserSupplier3()).limit(5)
.collect(Collectors.partitioningBy(p -> p.getId() < 18));
System.out.println("小孩: " + children.get(true));
System.out.println("成年人: " + children.get(false));
// 通过年龄进行分区排序:
// 小孩: [{"id":16,"name":"pancm7"}, {"id":17,"name":"pancm2"}]
// 成年人: [{"id":18,"name":"pancm4"}, {"id":19,"name":"pancm9"}, {"id":20,"name":"pancm6"}]
/*
* IntSummaryStatistics 用于收集统计信息(如countminmaxsum和average)的状态对象
*/
List<Integer> numbers = Arrays.asList(1, 5, 7, 3, 9);
IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("列表中最大的数 : " + stats.getMax());
System.out.println("列表中最小的数 : " + stats.getMin());
System.out.println("所有数之和 : " + stats.getSum());
System.out.println("平均数 : " + stats.getAverage());
// 列表中最大的数 : 9
// 列表中最小的数 : 1
// 所有数之和 : 25
// 平均数 : 5.0
}
/**
* 自定义流
*/
private static void test4() {
/*
* 自定义一个流 然后进行输出
*/
System.out.println("自定义一个流进行计算输出:");
Stream.generate(new UserSupplier()).limit(2).forEach(u -> System.out.println(u.getId() + ", " + u.getName()));
//第一次:
//自定义一个流进行计算输出:
//10, pancm7
//11, pancm6
//第二次:
//自定义一个流进行计算输出:
//10, pancm4
//11, pancm2
//第三次:
//自定义一个流进行计算输出:
//10, pancm4
//11, pancm8
}
public static void print(String text) {
// jdk1.8之前的写法
// if (text != null) {
// System.out.println(text);
// }
// jdk1.8的写法
Optional.ofNullable(text).ifPresent(System.out::println);
}
public static void getLength(String text) {
// jdk1.8之前的写法
// return if (text != null) ? text.length() : -1;
// jdk1.8的写法
int i = Optional.ofNullable(text).map(String::length).orElse(-1);
System.out.println("数据:" + i);
};
}
class UserSupplier implements Supplier<User> {
private int index = 10;
private Random random = new Random();
@Override
public User get() {
return new User(index++, "pancm" + random.nextInt(10));
}
}
class UserSupplier2 implements Supplier<User> {
private int index = 10;
private Random random = new Random();
@Override
public User get() {
return new User(index % 2 == 0 ? index++ : index, "pancm" + random.nextInt(10));
}
}
class UserSupplier3 implements Supplier<User> {
private int index = 16;
private Random random = new Random();
@Override
public User get() {
return new User(index++, "pancm" + random.nextInt(10));
}
}