jkd1.8 stream
Stream
创建流
通过集合创建,例如Map (常用)
Stream<Map.Entry<Object, Object>> stream = new HashMap<>().entrySet().stream();
通过数组方式创建
Stream
通过Stream静态方法创建
1、 使用静态方法创建流
Stream
2、 通过Java 8 函数式接口Supplier
Stream
3、 通过Java 8 函数式接口UnaryOperator
Stream
一般无限流和limit一起使用
public static Integer x = 0;
public static void main(String[] args) {
Stream<Integer> limit = Stream.iterate(x, x -> x + 1).limit(10L);//0-9
}
中间操作
筛选和切片
filter
从流中过滤掉一些元素
limit
截断流,使得元素不超过给定数量
skip
跳过元素,返回一个扔掉了前n个元素的流,如果元素个数不足n,则返回一个空流
distinct
去重,通过流所生成元素的hashcode和equal方法去除重复的元素
映射
map
接受一个Lambda表达式,将流里面的元素转化为其他的元素,该函数会应用于每一个函数上,并映射成为一个新的元素。
flatmap
接受一个函数作为接受,一般是将流里面的元素转为另外一个流,再将这个流连接起来。
map和flatmap的区别
map的作用是对list中每个元素进行重新定义和包装。
flatmap的作用是把几个小的list转换到一个大的list
案例
将{"hello","world"}转化为{'h','e','l','l','o','w','o','r','l','d'}
/**
* 将{"hello","world"}转化为{'h','e','l','l','o','w','o','r','l','d'}
*/
public class MapTest {
@Test
public void test() {
List<String> list = new ArrayList<>(Arrays.asList("hello", "world"));
//i.chars().mapToObj(c -> (char) c)是将字符串转为Character流
//map 无法实现此功能
Stream<Stream<Character>> stream = list.stream().map(i -> i.chars().mapToObj(c -> (char) c));
Stream<Character> characterStream = list.stream().flatMap(i -> i.chars().mapToObj(c -> (char) c));
List<Character> collect = characterStream.collect(Collectors.toList());
collect.forEach(System.out::println);
}
}
排序
sorted()
自然排序按照comparable排序
sorted(Comparator c)
自定排序规则
终止操作
forEach
对于每个元素消费
查找和匹配
allMatch
是否匹配所有元素
anyMatch
是否匹配至少一个元素
noneMatch
是否没有匹配所有元素
findFirst
查找第一个元素
findAny
查找任意一个元素
count
计算元素个数
max
查找最大值
min
查找最小值
规约和收集
reduce
Optional
T reduce(T identity, BinaryOperator
将流中的元素反复结合起来,形成一个值
/*
通过reduce求和
*/
@Test
public void test1() {
Optional<Double> reduce = list.stream().map(Employee::getSalary).reduce((x, y) -> x + y);
}
/*
reduce在100的基础上求和
*/
@Test
public void test2() {
Double reduce = list.stream().map(Employee::getSalary).reduce(100D, (x, y) -> x + y);
}
toArray
/**
* 将名字收集为字符串数组
*/
@Test
public void test3(){
String[] names = list.stream().map(Employee::getName).toArray(String[]::new);
}
collect
/**
* 将名字收集为字符串数组
*/
@Test
public void test3() {
String[] names = list.stream().map(Employee::getName).toArray(String[]::new);
}
/**
* 将名字收集为集合
*/
@Test
public void test4() {
List<String> collect1 = list.stream().map(Employee::getName).collect(Collectors.toList());
ArrayList<String> collect = list.stream().map(Employee::getName).collect(Collectors.toCollection(ArrayList::new));
}
/**
* 计数
*/
@Test
public void test5() {
long count = list.stream().map(Employee::getName).collect(Collectors.counting());
long count1 = list.stream().map(Employee::getName).count();
}
/**
* 求平均值
*/
@Test
public void test6() {
Double collect = list.stream().collect(Collectors.averagingDouble(Employee::getSalary));
}
/**
* 求和
*/
@Test
public void test7() {
Double collect = list.stream().collect(Collectors.summingDouble(Employee::getSalary));
Double collect1 = list.stream().mapToDouble(Employee::getSalary).sum();
}
/**
* 分组
*/
@Test
public void test8() {
Map<State, List<Employee>> collect = list.stream().collect(Collectors.groupingBy(i -> i.getState()));
}
/**
* 分片
*/
@Test
public void test9() {
Map<Boolean, List<Employee>> collect = list.stream().collect(Collectors.partitioningBy(i -> i.getSalary() > 10));
}
/**
* 连接字符串
*/
public void test10() {
String collect = list.stream().map(Employee::getName).collect(Collectors.joining(",", "(", ")"));
}
collect经典应用
1、将一下Person的List通过名字筛选出每个人的money总数
ArrayList<Person> list = new ArrayList<>(Arrays.asList(
new Person("tom", 1, 100),
new Person("jack", 2, 100),
new Person("tom", 1, 100),
new Person("jack", 2, 100),
new Person("jack", 2, 100),
new Person("marry", 3, 100)
));
class Person {
private String name;
private Integer age;
private Integer money;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return name.equals(person.name) &&
age.equals(person.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public Person(String name, Integer money) {
this.name = name;
this.money = money;
}
public Person(String name, Integer age, Integer money) {
this.name = name;
this.age = age;
this.money = money;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getMoney() {
return money;
}
public void setMoney(Integer money) {
this.money = money;
}
}
答案
List<Person> ans = list.stream()
.collect(Collectors.groupingBy(Person::getName, Collectors.summingInt(Person::getMoney)))
.entrySet()
.stream()
.map(i -> new Person(i.getKey(), i.getValue()))
.collect(Collectors.toList());
2、通过以上方法获取的person会把age字段丢失,因为groupingBy是通过hashcode来做分组,要保留name和age两个字段的方法有两个。
- 将name和age单独封装为一个类,这样的做法和第一题差不多
- 如果name和age是一一对应的,比如tom就是1岁,是确定的,那么可以重写hashcode函数,这样name和age相同的对象就会被分到一个组。
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return name.equals(person.name) &&
age.equals(person.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
code
List<Person> collect1 = list.stream()
.collect(Collectors
//关键这里的i->i,会将name和age相同的分为一组
.groupingBy(i -> i, Collectors.summingInt(Person::getMoney)))
.entrySet()
.stream()
.map(i -> new Person(i.getKey().getName(), i.getKey().getAge(), i.getValue()))
.sorted(Comparator.comparingInt(Person::getAge))
.collect(Collectors.toList());