1.1首先看一个代码片段
list.stream().anyMatch(person -> person.getAge() == 30);
list.stream().anyMatch(new Predicate
@Override
public boolean test(Person person) {
return person.getAge() == 30;
}
});
以上两段代码是等价的
1.2下面5种格式表达的都是一个意思,很关键,必须全部掌握
Person::getAge
person -> {return person.getAge();}
(person) -> {return person.getAge();}
(person) -> person.getAge()
person -> person.getAge()
表示当前参数接收一个匿名内部类,类中的方法接收一个Person类型的参数,方法的逻辑是调用person的getAge方法
collect:用于把Stream转换为List,set,map等待操作,示例:stream.collect(Collectors.toList) 参考示例test1(),test2()
filter:用于过滤集合元素,比原生代码速度快的多,参考示例 test1(),test2()
去重示例:
main(){
list.stream().filter(distinctByKey(Person::getName)).collect(Collectors.toList());
}
public static Predicate distinctByKey(Function super T, Object> keyExtractor) {
Map
以上示例如果看不太明白,其实等价于:原理就是使用HaspMap的putIfAbsent方法,如果元素不存在,才put,并返回null,否则返回map中存在的元素,使用该原理可以判断当前元素是否重复,即(v != null)表示重复,如果重复就由stream.filter进行过滤
public static void main(String[] args) {
List list = Lists.newArrayList(new Person(22, "Strawberry", 10010),new Person(22, "Strawberry", 10010),new Person(23, "Marry", 10010));
Function personNameFunction = new Function() {
@Override
public String apply(Person t) {
return t.getName();
}
};
list = list.stream().filter(distinctByKey(personNameFunction)).collect(Collectors.toList());
System.out.println(list);
}
public static Predicate distinctByKey(Function personNameFunction) {
final Map
sorted:用于对集合中的元素比较排序,效率远远高于传统方式,参考示例 test3()
peek:用于对stream中的元素迭代做某些操作,注意peek后要返回一个新的list,peek才有效与foreach区别开,参考示例 test10()
map:用于操作集合列表元素,并且返回另一个元素类型的集合列表
list元素为基本类型时,使用stream.map操作比原生代码快
list元素为引用类型时,使用stream.map操作比原生代码慢
参考示例test4(),test5()
Collectors.toMap 这种方式list转为map依然比原生操作慢
flatMap:用于扁平化流,把list列表中的数组打平成元素
参考示例:test6()
collectFlatMap中的数据格式:[test, 1, 2, 3, 4, 5, 6, 7, 8, 9]
collectMap中的数据格式:[[test, 1],[test, 2],[test, 3],[test, 4],[test, 5],[test, 6],[test, 7],[test, 8],[test, 9]]
注意要distinct()保证去重
性能上还是不如原生操作
match:是否匹配 参考示例:test12()
allMatch:全部都匹配返回true
anyMatch:只要有一个匹配返回true,false全部都不匹配
noneMatch: 全部都不匹配
reduce:可以进行filter,max,min等等操作,参考test()12
skip(int n):丢弃Stream前n个元素,拿到剩下的元素
limit(int n):获取Stream前n个元素
利用以上两个方法可以做到分页效果:
stream().skip((pageNum - 1) * pageSize).limit(pageSize)
package cn.qu.function;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FunctionTest {
public static void main(String[] args) {
test1();
}
private static Random random;
private static List list;
static void init(Integer n){
random = new Random();
list = new ArrayList<>();
for(int i = n; i < 2*n - 1; i ++){
list.add(new Person().setId(i).setDeviceId("A1-01-" + (random.nextInt(2) + 1)).setAge(random.nextInt(30) + 1).setName("A"));
}
}
//使用stream.reduce求person列表中personId最小的person
public static void test13() {
init(101);
Optional reduce = list.stream().reduce((person1,person2) -> person1.getId() < person2.getId() ? person1 : person2);
System.out.println(reduce.get());
}
//匹配当前person列表中是否有年龄为30岁的人
public static void test12() {
init(101);
boolean anyMatch = list.stream().anyMatch(person -> person.getAge() == 30);
System.out.println("person列表中是否有30岁的人:" + anyMatch);
}
//求person列表中最大值,平均值,最小值
public static void test11() {
init(101);
Map> collect = null;
//测试Collectors.maxBy 分组求最大值
collect = list.stream().collect(Collectors.groupingBy(Person::getDeviceId,Collectors.maxBy(Comparator.comparing(Person::getId))));
System.out.println("分组求最大值:");
System.out.println(collect);
//测试Collectors.minBy 分组求最小值
collect = list.stream().collect(Collectors.groupingBy(Person::getDeviceId,Collectors.minBy(Comparator.comparing(Person::getId))));
System.out.println("分组求最小值:");
System.out.println(collect);
//测试Collectors.averagingInt 分组求平均值
Map collect3 = list.stream().collect(Collectors.groupingBy(Person::getDeviceId,Collectors.averagingInt(Person::getAge)));
collect3.forEach((key,avg) -> {
avg = Math.round(avg*100)*0.01;
collect3.put(key, avg);
});
System.out.println("分组求平均值:");
System.out.println(collect3);
Map collect2 = null;
//测试Collectors.counting() 分组统计
collect2 = list.stream().collect(Collectors.groupingBy(Person::getDeviceId, Collectors.counting()));
System.out.println("分组统计:");
System.out.println(collect2);
//测试Collectors.counting() 分组求和
collect2 = list.stream().collect(Collectors.groupingBy(Person::getDeviceId, Collectors.summingLong(Person::getId)));
System.out.println("分组求和:");
System.out.println(collect2);
}
// 用于对stream中的元素迭代做某些操作
public static void test10() {
init(101);
List collect = list.stream().peek(person -> person.setName("B")).collect(Collectors.toList());
System.out.println(collect);
}
//核心概念就是对person列表按person.id属性去重
public static void test9() {
Random random = new Random();
List list = new ArrayList<>();
for(int i = 1000001; i < 2000001; i ++){
list.add(new Person().setId(random.nextInt(10000) + 10000).setDeviceId("A1-01-" + (random.nextInt(24) + 1)).setAge(10).setName("A"));
}
long start = System.currentTimeMillis();
//按设备ID分组
Map> collect = list.stream().collect(Collectors.groupingBy(Person::getDeviceId));
list.clear();
//对每一组的person列表按id去重复
collect.forEach((key,persons) ->{
//去重后得到一个新的list
ArrayList result = persons.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getId))), ArrayList::new));
//合并
list.addAll(result);
});
/*collect.forEach(new BiConsumer>() {
@Override
public void accept(String t, List u) {
ArrayList list = u.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(Person::getId))), ArrayList::new));
collect.put(t, list);
}
});*/
//按id分组统计list中人数
list.stream().collect(Collectors.groupingBy(Person::getAge, Collectors.counting()));
long end = System.currentTimeMillis();
System.out.println("按id分组统计list中人数耗时:" + (end - start));
}
// 按年龄分组统计person列表各个年龄段的人数
public static void test8() {
init(101);
Map collect = list.stream()
.collect(Collectors.groupingBy(Person::getAge, Collectors.counting()));
System.out.println(collect);
}
// 使用串行流方式对person列表按年龄进行分组,分组后拿到一个年龄为key的HashMap
public static void test7() {
init(101);
Map> collect = list.stream()
.collect(Collectors.groupingBy(new Function() {
@Override
public Integer apply(Person t) {
return t.getAge();
}
}));
System.out.println(collect);
}
/*
* stream.flatMap的作用: 使用stream.map把list列表中的字符串进行分割后得到的是一个String[]类型的list列表
* 使用stream.flatMap可以把String[]扁平化得到的是一个String类型的list列表
*/
public static void test6() {
List list = new ArrayList<>();
for (int i = 1; i < 10; i++) {
list.add("test-" + i);
}
/*
* List collect = list.stream().map((str) ->
* str.split("-")).flatMap(new Function>() {
*
* @Override public Stream extends String> apply(String[] array) {
* return Arrays.stream(array); }
* }).distinct().collect(Collectors.toList());
*/
List collect = list.stream().map((str) -> str.split("-")).flatMap(Arrays::stream).distinct()
.collect(Collectors.toList());
System.out.println(collect);
}
// 使用传统方式和串行流方式修改list列表中的字符串,串行流方式效率高的多
public static void test5() {
System.out.println("test4():");
List list = new ArrayList<>();
for (int i = 1000001; i < 2000001; i++) {
list.add("test-" + i);
}
long start = System.currentTimeMillis();
List collect = list.stream().map((string) -> string.toLowerCase()).collect(Collectors.toList());
long end = System.currentTimeMillis();
System.out.println("collect.size:" + collect.size() + " 耗时毫秒:" + (end - start));
long start2 = System.currentTimeMillis();
List strs = new ArrayList<>();
for (String string : list) {
strs.add(string.toUpperCase());
}
long end2 = System.currentTimeMillis();
System.out.println("strs.size:" + strs.size() + " 耗时毫秒:" + (end2 - start2));
}
// 使用传统方式和串行流方式把列表中的person更换成personVo,传统方式较快,串行流方式较慢
public static void test4() {
System.out.println("test3():");
init(1000001);
long start = System.currentTimeMillis();
List collect = list.stream()
.map((person) -> new PersonVo().setId(person.getId()).setAge(person.getAge()).setName(person.getName()))
.collect(Collectors.toList());
long end = System.currentTimeMillis();
System.out.println("stream流方式collect.size:" + collect.size() + " 耗时毫秒:" + (end - start));
long start2 = System.currentTimeMillis();
List personVos = new ArrayList<>();
for (Person person : list) {
personVos.add(new PersonVo().setId(person.getId()).setAge(person.getAge()).setName(person.getName()));
}
long end2 = System.currentTimeMillis();
System.out.println("传统方式personVos.size:" + personVos.size() + " 耗时毫秒:" + (end2 - start2));
}
// 使用传统选择排序和stream流对list元素排序,stream流方式快的多
public static void test3() {
init(1000001);
long start = System.currentTimeMillis();
list.stream().sorted(Comparator.comparing(Person::getAge).thenComparing(Person::getId))
.collect(Collectors.toList());
long end = System.currentTimeMillis();
System.out.println("stream串行流排序耗时:" + (end - start));
long start2 = System.currentTimeMillis();
Person[] persons = list.toArray(new Person[list.size()]);
for (int i = 0; i < persons.length; i++) {
for (int j = i + 1; j < persons.length; j++) {
Person temp = null;
if (persons[i].getAge() < persons[j].getAge()) {
temp = persons[i];
persons[i] = persons[j];
persons[j] = temp;
}
}
}
long end2 = System.currentTimeMillis();
System.out.println("传统选择排序耗时:" + (end2 - start2));
}
// 使用传统方式和串并行流方式过滤出age<15的person列表, 列表数量越大stream比传统方式越快,注意越test1的区别,test1只是统计人数,test2是过滤出元素
public static void test2() {
int age = 15;
init(1000001);
long start = System.currentTimeMillis();
// 传统方式
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
if (iterator.next().getAge() >= age) {
iterator.remove();
}
}
long end = System.currentTimeMillis();
System.out.println("传统方式统计年龄小于15岁的人数:" + list.size() + " 统计耗时毫秒:" + (end - start));
long start2 = System.currentTimeMillis();
List collect = list.stream().filter(person -> person.getAge() < age).collect(Collectors.toList());
// List collect = list.parallelStream().filter(person ->
// person.getAge() < age).collect(Collectors.toList());
long end2 = System.currentTimeMillis();
System.out.println("stream流方式统计年龄小于15岁的人数:" + collect.size() + " 统计耗时毫秒:" + (end2 - start2));
}
// 使用传统方式和串行流方式过滤出age<15的人数, 传统方式效率高一些
public static void test1() {
int age = 15;
init(1000001);
long start = System.currentTimeMillis();
int count = 0;
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getAge() < age) {
count++;
}
}
long end = System.currentTimeMillis();
System.out.println("年龄小于15岁的人数:" + count + " 统计耗时毫秒:" + (end - start));
long start2 = System.currentTimeMillis();
// long count2 = list.parallelStream().filter(person -> person.getAge()
// < age).count();
long count2 = list.stream().filter(person -> person.getAge() < age).count();
long end2 = System.currentTimeMillis();
System.out.println("年龄小于15岁的人数:" + count2 + " 统计耗时毫秒:" + (end2 - start2));
}
}
package cn.qu.function;
public class Person {
private Integer id;
private Integer age;
private String name;
private String deviceId;
public Integer getId() {
return id;
}
public Person setId(Integer id) {
this.id = id;
return this;
}
public Integer getAge() {
return age;
}
public Person setAge(Integer age) {
this.age = age;
return this;
}
public String getName() {
return name;
}
public Person setName(String name) {
this.name = name;
return this;
}
public String getDeviceId() {
return deviceId;
}
public Person setDeviceId(String deviceId) {
this.deviceId = deviceId;
return this;
}
@Override
public String toString() {
return "Person [id=" + id + ", age=" + age + ", name=" + name + ", deviceId=" + deviceId + "]";
}
}
//PersonVo extends Person