JDK1.8新特性复习
JDK1.8新特性
1、Lambda表达式
2、::运算符引用方法
3、stream
Stream是JDK1.8新增的一个特性,称之为Stream,它可以给予Lamdba表达式对集合数据进行处理(如:遍历、排序、去重、修改)等操作,并且支持同时使用2种或以上的操作。
Stream流是从支持数据处理操作的源生成的元素序列,源可以是数组、文件、集合、函数。流不是集合元素,它不是数据结构并不保存数据,它的主要目的在于计算。
3.1、创建Stream
3.1.1、使用Stream提供的方法创建
3.1.1.1、of方法创建
// 不仅可以使用int,也可以是对象、Map、Object。。。。
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
// 使用对象创建
Stream<Person> integerStream = Stream.of(person1, person2);
3.1.1.2、iterate方法创建
iterate的第一个参数为n的值,第二个参数是一个lambda表达式,返回一个值提供给Stream,由于这个流是无限的,所以需要使用limit方法进行截取,这个方法的具体用法可以参考3.2.5。
Stream<Integer> limit = Stream.iterate(1, n -> n + 2).limit(5);
3.1.1.3、generator方法创建
generator方法和iterate类似,只是lambda表达式的类型不一样,它的lambda表达式没有参数,只有返回值。这个流也是无限的,所以需要使用limit方法进行截取,这个方法的具体用法可以参考3.2.5。
Stream<Double> limit = Stream.generate(() -> Math.floor(Math.random() * 100)).limit(10);
3.1.2、使用集合创建
// 使用of方法创建
ArrayList<Integer> integers = new ArrayList<>();
integers.add(1);
integers.add(2);
integers.add(3);
integers.add(4);
integers.add(5);
Stream<Integer> interStream = integers.stream();
3.1.3、使用Array创建
// 使用of方法创建
Integer[] integerArray = {1,3,5,7,9};
Stream<Integer> stream = Arrays.stream(integerArray);
3.1.4、使用文件创建
通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行
try {
Stream<String> fileStream = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
} catch (IOException e) {
e.printStackTrace();
}
3.2、中间操作符
通常对于Stream的中间操作,可以视为是源的查询,并且是懒惰式的设计,对于源数据进行的计算只有在需要时才会被执行,与数据库中视图的原理相似;
Stream流的强大之处便是在于提供了丰富的中间操作,相比集合或数组这类容器,极大的简化源数据的计算复杂度
一个流可以跟随零个或多个中间操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用
这类操作都是惰性化的,仅仅调用到这类方法,并没有真正开始流的遍历,真正的遍历需等到终端操作时,常见的中间操作有下面即将介绍的 filter、map 等
3.2.1、filter方法
通过设置的条件过滤元素
// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 100)).limit(10);
// 先筛选大于50的,再进行遍历
stream.filter(v->v>50).forEach(System.out::println);
打印结果:
76.0
75.0
71.0
90.0
81.0
可以看到,原本十个随机数经过过滤后只剩下五个大于50的~
3.2.2、map方法
map元素可以对集合进行遍历,并且对每个元素进行修改后返回一个新的stream
// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 100)).limit(10);
// 先筛选大于50的,再把这部分数据都加上50
stream.filter(v->v>50).map(v->v+50).forEach(System.out::println);
打印结果:
125.0
144.0
105.0
146.0
119.0
149.0
从上面的结果可以看出,stream的方法是有顺序的,其实是一个链式调用,先对结果进行flter返回一个新的stream,再对这个新的stream修改后返回一个新的stream。
调换fiter和map的顺序再次执行
// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 100)).limit(10);
// 先筛选大于50的,再把这部分数据都加上50
stream.map(v->v+50).filter(v->v>50).forEach(System.out::println);
输出结果:
72.0
105.0
115.0
128.0
129.0
128.0
78.0
68.0
134.0
51.0
3.2.3、distinct方法
这个方法如单词含义一样,是用来去重的。对于Object的子类,是根据元素的hashCode和equels方法来实现的对比。所以要根据使用场景重写这两个方法。
// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 2)).limit(10);
// 先筛选大于50的,再把这部分数据都加上50
stream.map(v->v+50).filter(v->v>=50).distinct().forEach(System.out::println);
输出结果:
51.0
50.0
3.2.4、sorted方法
此方法用来排序,返回排序后的流。
// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 2)).limit(10);
// 先筛选大于50的,再把这部分数据都加上50
stream.map(v->v+50).filter(v->v>=50).distinct().sorted().forEach(System.out::println);
输出:
50.0
51.0
从运行结果可以看出它默认采取的是升序排序,如果想自定义查询规则,也可以调用sorted的重载方法,传递一个Comparator Lambda表达式。
// 创建stream,生成十个100以内的随机数填充
Stream<Double> stream = Stream.generate(() -> Math.floor(Math.random() * 5)).limit(10);
// 先筛选大于50的,再把这部分数据都加上50
stream.map(v->v+50).filter(v->v>=50).distinct().sorted((o1,o2)-> (int)Math.round(o2-o1)).forEach(System.out::println);
输出:
54.0
53.0
52.0
51.0
50.0
3.2.5、limit方法
会返回一个不超过给定长度的流,实际上我们上面的案例都已经用过这个方法了,下面再次演示一下limit“截取”流。
Stream.of(1,2,3,4,5,6,7,8,9,0).limit(4).forEach(System.out::println);
输出:
1
2
3
4
3.2.6、skip方法
如词义一样,这个方法用来跳过某个元素,如果说limit是截取后面的元素,那么skip就是截取前面的元素。
Stream.of(1,2,3,4,5,6,7,8,9,0).limit(4).skip(2).forEach(System.out::println);
输出:
3
4
3.2.7、flatMap方法
这个方法我的理解是,将流内存储的每个元素再转换为流,然后合并为一个流。
测试数据,下文都是使用此测试数据
ArrayList<Integer> arrayList1 = new ArrayList();
arrayList1.add(1);
arrayList1.add(2);
ArrayList<Integer> arrayList2 = new ArrayList();
arrayList2.add(3);
arrayList2.add(4);
ArrayList<Integer> arrayList3 = new ArrayList();
arrayList3.add(5);
arrayList3.add(6);
合并流
// 合并流
Stream.of(arrayList1,arrayList2,arrayList3)
.flatMap(arrayList -> arrayList.stream()).forEach(System.out::println);
输出:
1
2
3
4
5
6
同时还可以对这个合并后的流进行一系列操作。
// 合并后把买个元素+1再输出
Stream.of(arrayList1,arrayList2,arrayList3)
.flatMap(arrayList->arrayList.stream().map(value->value+1))
.forEach(System.out::println);
输出:
2
3
4
5
6
7
3.2.8、peek方法
对Stream内的元素进行遍历处理,如果是引用类型,遍历的过程中可以对属性进行编辑,非引用类型的只能修改形参,不过可以在其lambda表达式内进行改变和测试。peek的操作是返回一个新的stream的,且设计的初衷是用来debug调试的,因此使用steam.peek()必须对流进行一次处理再产生一个新的stream
// peek可以对元素进行遍历,但是不能进行修改
Stream.of(arrayList1,arrayList2,arrayList3)
.flatMap(arrayList -> arrayList.stream())
.peek(v->{ v=v+1; }).forEach(System.out::println);
输出:
1
2
3
4
5
6
3.3、终端操作符
Stream流执行完终端操作之后,无法再执行其他动作,否则会报状态异常,提示该流已经被执行操作或者被关闭,想要再次执行操作必须重新创建Stream流
一个流有且只能有一个终端操作,当这个操作执行后,流就被关闭了,无法再被操作,因此一个流只能被遍历一次,若想在遍历需要通过源数据在生成流。
终端操作的执行,才会真正开始流的遍历。如 count、collect 等
3.3.1、collect方法
收集器,将流转换为其他形式,下面介绍两种比较常见的场景,它还有一些其他的功能,例如转换的时候可以做最大值、最小值、平均值、总和值、总数等操作。
转换为List:
List<Integer> collect = Stream.of(arrayList1, arrayList2, arrayList3)
.flatMap(arrayList -> arrayList.stream()).peek(v -> {v = v + 1;})
.collect(Collectors.toList());
转换为Map,转换时需要提供k,v的生成策略,都是根据Lambda表达式生成:
Map<String, Integer> collect = Stream.of(arrayList1, arrayList2, arrayList3)
.flatMap(arrayList -> arrayList.stream())
.peek(v -> {
v = v + 1;
}).collect(Collectors.toMap(k -> "key" + k, v -> v));
collect.forEach((k,v)->{
System.out.println("key:"+k+",v:"+v);
});
输出:
key:key1,v:1
key:key2,v:2
key:key5,v:5
key:key6,v:6
key:key3,v:3
key:key4,v:4
3.3.2、forEach方法
遍历流,这个方法上面已经演示很多次了就不再演示了,需要注意的是,如果是在中途需要遍历可以使用peek,因为forEach是终止操作符。
3.3.3、findFirst方法
返回第一个元素,默认返回Optional,可以使用get返回元素。Optional内内置了一些方法可以对存储的元素进行过滤,遍历等操作。
// 取出第一个元素
Optional<ArrayList<Integer>> first = Stream.of(arrayList1, arrayList2, arrayList3).findFirst();
// 取出元素
ArrayList<Integer> integers = first.get();
3.3.4、findAny方法
返回流中所有元素
// 取出所有元素
Optional<ArrayList<Integer>> first = Stream.of(arrayList1, arrayList2, arrayList3).findAny();
// 取出元素
ArrayList<Integer> integers = first.get();
System.out.println(integers);
返回:
[1, 2]
3.3.5、count方法
返回元素个数
// 取出所有元素
long count = Stream.of(arrayList1, arrayList2, arrayList3,null).filter(v->v!=null).count();
// 打印结果
System.out.println(count);
返回:
3
3.3.6、sum方法
求和,这个方法必须配合mapToInt、mapToLong等方法一起使用,下面介绍如何求集合内所有元素的和
// 取出所有元素
long count = Stream.of(arrayList1, arrayList2, arrayList3, null)
.filter(v -> v != null)
.mapToInt(v -> v.stream().mapToInt(item->item).sum()).sum();
// 打印结果
System.out.println(count);
返回:
21
3.3.7 、max方法
求最大值,需要指定根据什么比较,比如这个是根据长度比较,
// 指定比较的对象是什么
ArrayList<Integer> integers = Stream.of(arrayList1, arrayList2, arrayList3)
.max(Comparator.comparingInt(value -> value.size())).get();
// 打印结果
System.out.println(integers.size());
输出:3
下面是先合并为一个大的集合,再根据元素内容比较
// 求最大值
Integer max = Stream.of(arrayList1, arrayList2, arrayList3).flatMap(v -> v.stream()).max(Comparator.comparingInt(value -> value)).get();
// 打印结果
System.out.println(max);
输出:6
3.3.8、min方法
求最小值,用法与max相似,这里就不再演示了。
3.3.9、anyMatch方法
检查是否包含某个元素
// 是否符合个条件
boolean b = Stream.of(arrayList1, arrayList2, arrayList3).flatMap(v -> v.stream()).anyMatch(v -> v == 0);
// 打印结果
System.out.println(b);
输出:false
3.3.10、allMatch方法
检查所有元素是否都符合条件,与3.3.9方法类似,这里就不演示了。
3.3.11、noneMatch方法
检查是否有不满足条件的,与3.3.9类似,这里就不演示了
3.3.12、reduce方法
可以将流中元素反复结合起来,得到一个值,这里的reduce虽然只有两个参数,但是并非只会执行一次,而是会将参数依次代入执行。
// 结合
ArrayList<Integer> integers = Stream.of(arrayList1, arrayList2, arrayList3)
.reduce((obj1, obj2) -> {
obj1.addAll(obj2);
return obj1;
}).get();
// 打印结果
System.out.println(integers);
输出:
[1, 2, 3, 4, 5, 6]
3.4、Collect收集
Collector:结果收集策略的核心接口,具备将指定元素累加存放到结果容器中的能力;并在Collectors工具中提供了Collector接口的实现类
3.4.1、toList
将用户ID存放到List集合中
List<Integer> idList = userList.stream().map(User::getId).collect(Collectors.toList()) ;
3.4.2、toMap
将用户ID和Name以Key-Value形式存放到Map集合中
Map<Integer,String> userMap = userList.stream().collect(Collectors.toMap(User::getId,User::getName));
3.4.3、toSet
将用户所在城市存放到Set集合中
Set<String> citySet = userList.stream().map(User::getCity).collect(Collectors.toSet());
3.4.4、counting
符合条件的用户总数
long count = userList.stream().filter(user -> user.getId()>1).collect(Collectors.counting());
3.4.5、summingInt
对结果元素即用户ID求和
Integer sumInt = userList.stream().filter(user -> user.getId()>2).collect(Collectors.summingInt(User::getId)) ;
3.4.6、minBy
筛选元素中ID最小的用户
User maxId = userList.stream().collect(Collectors.minBy(Comparator.comparingInt(User::getId))).get() ;
3.4.7、joining
将用户所在城市,以指定分隔符链接成字符串;
String joinCity = userList.stream().map(User::getCity).collect(Collectors.joining("||"));
3.4.8、groupingBy
按条件分组,以城市对用户进行分组;
Map<String,List<User>> groupCity = userList.stream().collect(Collectors.groupingBy(User::getCity));
3.4.9、orElse(null)
/**
* Return the value if present, otherwise return {@code other}.
*
* @param other the value to be returned if there is no value present, may
* be null
* @return the value, if present, otherwise {@code other}
* 返回值,如果存在,否则返回其他
*/
public T orElse(T other) {
return value != null ? value : other;
}
表示如果一个都没找到返回null(orElse()中可以塞默认值。如果找不到就会返回orElse中设置的默认值)
3.4.10、orElseGet(null)
/**
* Return the value if present, otherwise invoke {@code other} and return
* the result of that invocation.
*
* @param other a {@code Supplier} whose result is returned if no value
* is present
* @return the value if present otherwise the result of {@code other.get()}
* @throws NullPointerException if value is not present and {@code other} is
* null
* 返回值如果存在,否则调用其他值并返回该调用的结果
*/
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
表示如果一个都没找到返回null(orElseGet()中可以塞默认值。如果找不到就会返回orElseGet中设置的默认值)
orElse() 接受类型T的 任何参数,而orElseGet()接受类型为Supplier的函数接口,该接口返回类型为T的对象
3.4.10、orElse(null)和orElseGet(null)区别:
1、当返回Optional的值是空值null时,无论orElse还是orElseGet都会执行
2、而当返回的Optional有值时,orElse会执行,而orElseGet不会执行
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class TestStream {
public static void main(String[] args) {
List<User> list = new ArrayList<>();
//定义三个用户对象
User user1 = new User();
user1.setUserName("admin");
user1.setAge(16);
user1.setSex("男");
User user2 = new User();
user2.setUserName("root");
user2.setAge(20);
user2.setSex("女");
User user3 = new User();
user3.setUserName("admin");
user3.setAge(18);
user3.setSex("男");
User user4 = new User();
user4.setUserName("admin11");
user4.setAge(22);
user4.setSex("女");
//添加用户到集合中
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
/*
在集合中查询用户名包含admin的集合
*/
List<User> userList = list.stream().filter(user -> user.getUserName().contains("admin")&& user.getAge() <= 20).collect(Collectors.toList());
System.out.println(userList);
/*
在集合中查询出第一个用户名为admin的用户
*/
Optional<User> user = list.stream().filter(userTemp -> "admin".equals(userTemp.getUserName())).findFirst();
System.out.println(user);
/*
orElse(null)表示如果一个都没找到返回null(orElse()中可以塞默认值。如果找不到就会返回orElse中设置的默认值)
orElseGet(null)表示如果一个都没找到返回null(orElseGet()中可以塞默认值。如果找不到就会返回orElseGet中设置的默认值)
orElse()和orElseGet()区别:在使用方法时,即使没有值 也会执行 orElse 内的方法, 而 orElseGet则不会
*/
//没值
User a = list.stream().filter(userT-> userT.getAge() == 12).findFirst().orElse(getMethod("a"));
User b = list.stream().filter(userT11-> userT11.getAge() == 12).findFirst().orElseGet(()->getMethod("b"));
//有值
User c = list.stream().filter(userT2-> userT2.getAge() == 16).findFirst().orElse(getMethod("c"));
User d = list.stream().filter(userT22-> userT22.getAge() == 16).findFirst().orElseGet(()->getMethod("d"));
System.out.println("a:"+a);
System.out.println("b:"+b);
System.out.println("c:"+c);
System.out.println("d:"+d);
}
public static User getMethod(String name){
System.out.println(name + "执行了方法");
return null;
}
}
4、Optional
5、新的日期格式
6、其他特性
参考:Java--Stream流详解,后面相当一部分是直接粘贴的,基本等于转载了~,大家可以看看原文哦