JDK1.8 新特性Stream和Lambda的简单实用
Stream特点
- 无存储。stream不是一种数据结构,它只是某种数据源的一个视图,数据源可以是一个数组,Java容器或I/O
channel等。 - 为函数式编程而生。对stream的任何修改都不会修改背后的数据源,比如对stream执行过滤操作并不会删除被过滤的元素,而是会产生一个不包含被过滤元素的新stream。
- 惰式执行。stream上的操作并不会立即执行,只有等到用户真正需要结果的时候才会执行。
- 可消费性。stream只能被“消费”一次,一旦遍历过就会失效,就像容器的迭代器那样,想要再次遍历必须重新生成。
获取stream
@Test
public void getStream() {
//数组
String[] arr = new String[]{"aa","bb","cc"};
Stream<String> arrStream = Arrays.stream(arr);
//集合
List<String> list = Arrays.asList("aa","bb","cc");
Stream<String> colStream = list.stream();
//值
Stream<String> stream = Stream.of("aa","bb","cc");
}
stream方法使用
构建实体User类——使用lombok插件自动生成各种方法
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private int age;
}
测试要用到的数据:
List<User> list = Arrays.asList(
// name,age
new User("张三", 11),
new User("王五", 20),
new User("王五", 91),
new User("张三", 8),
new User("李四", 44),
new User("李四", 44),
new User("李四", 44)
);
forEach() 使用该方法迭代流中的每个数据
@Test
public void testForEach() {
//java8 ago
System.out.println("java8 ago");
for (User user: list){
System.out.println(user);
}
//java8 lambda
System.out.println("java 8 lambda");
list.forEach(user -> System.out.println(user));
//java8 stream lambda
System.out.println("java 8 stream lambda");
list.stream().forEach(user -> System.out.println(user));
}
sorted() 使用该方法排序数据
@Test
public void testSort() {
System.out.println("----------排序前-----------");
list.forEach(user -> System.out.println(user));
System.out.println("----------排序后-----------");
// java 8 以前
System.out.println("java8 ago");
Collections.sort(list, new Comparator<User>() {
@Override
public int compare(User o1, User o2){
return o1.getAge()-o2.getAge();
}
});
for(User user : list) {
System.out.println(user);
}
// java 8 stream方法引用
System.out.println("java 8 stream 方法引用");
list.stream().sorted(Comparator.comparing(User::getAge)).forEach(user -> System.out.println(user));
}
filter():使用该方法过滤
@Test
public void testFilter(){
//输出年龄大于50的人
System.out.println("过滤前");
list.forEach(user -> System.out.println(user));
//java 8 前
System.out.println("java 8 前");
for (User user: list){
if (user.getAge() > 50){
System.out.println(user);
}
}
//java 8 stream
System.out.println("java 8 stream");
list.stream().filter(user -> user.getAge() >50).forEach(user -> System.out.println(user));
System.out.println("过滤后");
}
limit():使用该方法截断
@Test
public void testLimit() {
// 从第三个开始截断,只输出前三个
System.out.println("-----截断前-----");
list.forEach(user -> System.out.println(user));
System.out.println("-----截断后-----");
//java 8 前
System.out.println("java 8 前");
for (int i = 0; i < 3; i++) {
System.out.println(list.get(i));
}
//java 8 stream
System.out.println("java 8 stream");
list.stream().limit(3).forEach(user -> System.out.println(user));
}
skip():与limit互斥,使用该方法跳过元素
@Test
public void testSkip() {
// 跳过前三个元素,从第四个开始输出
System.out.println("-----跳过前-----");
list.forEach(user -> System.out.println(user));
System.out.println("-----跳过后-----");
// java 8 前
System.out.println("java 8 前");
for (int i = 3; i < list.size(); i++) {
System.out.println(list.get(i));
}
//java 8 stream
System.out.println("java 8 stream");
list.stream().skip(3).forEach(user -> System.out.println(user));
}
distinct():使用该方法去重
/**
* distinct():使用该方法去重
* 注意:必须重写对应泛型的hashCode()和equals()方法
*/
@Test
public void testDdistinct(){
List<User> users = new ArrayList<>(list);
System.out.println("去重前");
list.forEach(user -> System.out.println(user));
System.out.println("去重后");
//java 8 前
System.out.println("java 8 前");
for (int i = 0; i < users.size()-1;i++) {
for (int j = users.size()-1;j>i;j--){
if (users.get(j).getAge() == users.get(i).getAge() && users.get(j).getName().
equals(users.get(i).getName())){
users.remove(i);
}
}
}
for (User user : users){
System.out.println(user);
}
//java 8 stream
System.out.println("java 8 stream");
users.stream().distinct().forEach(user -> System.out.println(user));
}
/**
* 去重+按照年龄小于40以后从大到小+只取前二
*/
@Test
public void demo() {
list.stream().distinct().filter(user -> user.getAge() < 40).
sorted(Comparator.comparing(User::getAge).reversed()).
limit(2).forEach(user -> System.out.println(user));
}
max,min,sum,avg,count
/**
* max,min,sum,avg,count
* 测试计算
*/
@Test
public void testNum(){
IntSummaryStatistics num = list.stream().mapToInt(user -> user.getAge()).
summaryStatistics();
System.out.println("总人数:" + num.getCount());
System.out.println("平均年龄:" + num.getAverage());
System.out.println("最大年龄:" + num.getMax());
System.out.println("最小年龄:" + num.getMin());
System.out.println("年龄之和:" + num.getSum());
}
map()
/**
* map():接收一个方法作为参数,
* 该函数会被应用到每个元素上,
* 并将其映射成一个新的元素
*/
@Test
public void testMap(){
//只输出所有人的年龄
list.stream().forEach(user -> System.out.println(user.getAge()));
System.out.println("映射后--------->");
List<Integer> ages = list.stream().map(user -> user.getAge()).collect(toList());
ages.forEach(age -> System.out.println(age));
//小写转大写
List<String> word = Arrays.asList("aaa","bbb","ccc");
System.out.println("全部大写-------->");
List<String> collect = word.stream().map(s -> s.toUpperCase()).collect(toList());
collect.forEach(s -> System.out.println(s));
}
flatMap()
/**
* flatMap():对每个元素执行mapper指定的操作,
* 并用所有mapper返回的Stream中的元素组成一个新的Stream
* 作为最终返回结果,通俗易懂就是将原来的stream中的
* 所有元素都展开组成一个新的stream
*/
@Test
public void testFlatMap() {
//创建一个 装有两个泛型的integer的集合
Stream<List<Integer>> stream = Stream.of(Arrays.asList(1,2,3),Arrays.asList(4,5));
Stream<Integer> integerStream = stream.flatMap(
(Function<List<Integer>, Stream<Integer>>) integers -> integers.stream());
// 为新的集合
List<Integer> collect = integerStream.collect(toList());
System.out.println("新stream大小" + collect.size());
System.out.println("------合并和---------");
collect.forEach(o -> System.out.println(o));
}
findFirst()
/**
* findFirst() :
* 使用该方法获取第一个元素
*/
@Test
public void testFindFirst() {
User user = list.stream().findFirst().get();
System.out.println(user);
}
reduce() :多面手
/**
* reduce() :多面手
* reduce 操作可以实现从一组元素中生成一个值
* sum()、max()、min()、count()等都是reduce操作,
* 将他们单独设为函数只是因为常用
* 例如:找到年龄最大的
*/
@Test
public void reduce() {
List<User> list = Arrays.asList(
new User("张三", 11),
new User("王五", 20),
new User("王五", 91),
new User("张三", 8),
new User("李四", 44),
new User("李四", 44),
new User("李四", 44)
);
//第一种使用reduce
Optional<User> reduce = list.stream().reduce((s1, s2) -> s1.getAge() > s2.getAge() ? s1 : s2);
User user = reduce.get();
System.out.println(user);
//第二种使用单独的方法
Optional<User> min = list.stream().min(Comparator.comparing(User::getAge));
User user2 = min.get();
System.out.println(user2);
//通过reduce求年龄的总和
Integer reduce2 = list.stream().reduce(0,// 该参数为初始值
(integer, user3) -> integer + user3.getAge(),// 该参数为累加器,新元素如何累加
((integer, integer2) -> integer + integer2));// 多个部分如何合并
System.out.println(reduce2);
}
使用collect()做字符串join
/**
* 使用collect()做字符串join
*/
@Test
public void ColletJoinTest() {
//使用Collectors.joining()拼接字符串
Stream<String> stream = Stream.of("张三","李四","王五","赵六");
// String s = stream.collect(Collectors.joining());//张三李四王五赵六
// String s = stream.collect(Collectors.joining("-")); //张三-李四-王五-赵六
String s = stream.collect(Collectors.joining("-", "(",")"));//(张三-李四-王五-赵六)
System.out.println(s);
}
Stream转换成List或Set
// Stream转换成List或Set
@Test
public void StreamTest(){
Stream<String> stream = Stream.of("I", "love", "you", "too","too");
List<String> list = stream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll);// 方式1
// List<String> list = stream.collect(Collectors.toList());// 方式2
//Set<String> list = stream.collect(Collectors.toSet());// 方式3
System.out.println(list);
}