四大内置核心函数式接口
1. Consumer:消费型接口 void accept(T t);
消费型接口就是传进去参数经过表达式处理,没有返回值。
public void test(){
shopping(1000,(x)-> System.out.println("今天购物发了"+x+"元"));
}
public void shopping(double money, Consumer<Double> con){
con.accept(money);
}
2. Supplier :供给型接口 T get();
供给型接口就是无中生有,不传参经过表达式处理返回值,比如生成随机数
public void test2(){
List<Integer> numList=getNumList(3,()->(int)(Math.random()*10));
}
public List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> list=new ArrayList<>();
for (int i=0;i<num;i++){
Integer n=sup.get();
list.add(n);
}
return list;
}
3. Function<T,R>: 函数型接口 R apply(T t);
函数型接口有传参有返回值。
public void test3(){
String newStr= handlerStr("helloworld",(str)->str.substring(3,6));
System.out.println(newStr);
}
public String handlerStr(String str, Function<String,String> fun){
return fun.apply(str);
}
4. Predicate: 断言型接口 boolean test(T t)
返回true或者false
public void test4(){
List<String> list= Arrays.asList("idea","eclipse","predicate","function");
List<String> returnList= filterStr(list,(str)->str.length()>4);
}
public List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> newList=new ArrayList<>();
for (String str:list) {
if(pre.test(str)){
newList.add(str);
}
}
return newList;
}
下面直观点了解Stream:
- Stream是Java8 新增的流特性,目的是让程序员写出高效率、干净、简洁的代码
- Stream类似于SQL语句,可以对代码进行集合运算和表达
- Stream就是把元素看成一种流,流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。
Stream使用格式成如下图 :
构建Stream ------------中间操作----------------------终端操作
注意:在没有终端操作 的前提下,中间操作即生成流不会执行
数据源:分为串行流Stream和并行流parallelStream()
列举一下构建串行流的方式,与并行流类似
- 构建Stream流的4中途径
- 通过数组 Arrays.stream
/**
* Created with IntelliJ IDEA.
*
* @Author: DIXian
* @Date: 2021/07/04/19:31
*/
public class Test04 {
public static void main(String[] args) {
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6);
Stream<Integer> stream = integers.stream();
stream.forEach(System.out::println);
}
}
2. 通过集合Collection.stream
@Test
public void test01(){
ArrayList<Object> list = new ArrayList<>();
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.stream().forEach(System.out:: println);
}
}
3. 通过Stream的静态of()方法Stream.of
@Test
public void test02(){
Stream.of(2, 3, 4, 5).forEach(System.out :: println);
}
}
4. 通过创建无限流的两种方式
- Stream.iterate
- Stream.generate
@Test
public void test03(){
//seed :给定一个初始值 ,后一个参数 T -> t ,此处加个一个截断操作 limit(10)
Stream.iterate(0, item -> item+2).limit(10).forEach(System.out :: println);
}
生成流:即对构建好的进行中间操作
- filter()
- map()
- flatMap()
- distinct()
- sorted()
- peek()
- limit()
- skip()
1. filter():filter(): 返回结果生成新的流中只包含满足筛选条件的数据。
public void test04(){
List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5, 6);
integers.stream().filter(item -> item.equals(1)).forEach(System.out :: println);
}
2.map():将流中的元素进行再次加工形成一个新流,流中的每一个元素映射为另外的元素。
// 2、map:返回元素的大写类型和哈希值
List<String> mzc = Arrays.asList("ma", "zhi", "chu");
List<String> mzcUpperCase = mzc.stream().
map(n -> n.toUpperCase()).
collect(Collectors.toList());
List<Integer> mzcHashCode = mzc.stream().map(n -> n.hashCode()).collect(Collectors.toList());
System.out.println("mzcUpperCase:"+mzcUpperCase+" ----- mzcHashCode:"+mzcHashCode);
运行结果:
mzcUpperCase:[MA, ZHI, CHU] ----- mzcHashCode:[3476, 120571, 98480]
示例场景:取出商品的所有id,就可以这样写(伪代码):
List<Product> productList = productService.selectAll();
List<Integer> pIds = productList.stream().map(p->p.getId).collect(Collectors.toList());
这样就可以拿到所有商品id的集合。
3.flatMap():扁平化映射,它具体的操作是将多个stream连接成一个stream,这个操作是针对类似多维数组的,比如集合里面包含集合,相当于降维作用,类似list中的addAll()操作
flatMap是将流中的每个元素都放到一个流中,最后将所有的流合并成一个新流,所有流对象中的元素都合并到这个新生成的流中返回。
// flatMap:将多层集合中的元素取出来,放到一个新的集合中去
List<Integer> num1 = Arrays.asList(1, 2, 3);
List<Integer> num2 = Arrays.asList(4, 5, 6);
List<Integer> num3 = Arrays.asList(7, 8, 9);
List<List<Integer>> lists = Arrays.asList(num1, num2, num3);
Stream<Integer> outputStream = lists.stream().flatMap(l -> l.stream());
List<Integer> flatMapResult = outputStream.sorted().collect(Collectors.toList());
System.out.println(flatMapResult);
运行结果:[1, 2, 3, 4, 5, 6, 7, 8, 9]
示例场景:取出所有部门人员的姓名,就可以这样写(伪代码):
// 1、取出所有部门
List<Department> departments = ...;
// 2、这个时候可以利用flatMap先将所有部门的所有人员汇聚起来
List<Person> persons = departments.stream.flatMap(d->d.getPersonList()).collect(Collectors.toList());
// 3、再利用map()方法取出
4.distinct():顾名思义,将流中的元素去重之后输出。
List<String> mzc = Stream.of("ma","zhi","chu","zhi","shuo","ma")
.distinct()
.collect(Collectors.toList());
System.out.println(mzc);
运行结果:
[ma, zhi, chu, shuo]
5.sorted():这个很简单了,顾名思义,将流中的元素按照自然排序方式进行排序。
// sorted:自然顺序排序
List<Integer> nums = Arrays.asList(1, 3, 5, 6, 8, 2);
List<Integer> sortedNum = nums.stream().sorted().collect(Collectors.toList());
System.out.println(sortedNum);
// sorted:降序排序
List<Integer> sortedNum2 = nums.stream().sorted(Comparator.reverseOrder()).collect(Collectors.toList());
System.out.println(sortedNum2);
// sorted:使用Comparator
List<Integer> sortedNums3 = nums.stream().sorted(Comparator.comparing(n -> n)).collect(Collectors.toList());
System.out.println(sortedNums3);
// 不用stream直接顺序排序
nums.sort(Comparator.comparing(Integer::intValue));
System.out.println(nums);
//不用stream直接降序排序
nums.sort(Comparator.comparing(Integer::intValue).reversed());
System.out.println(nums);
运行结果:
[1, 2, 3, 5, 6, 8]
[8, 6, 5, 3, 2, 1]
[1, 2, 3, 5, 6, 8]
[1, 2, 3, 5, 6, 8]
[8, 6, 5, 3, 2, 1]
6.peek():对流中每个元素执行操作,并返回一个新的流,返回的流还是包含原来流中的元素。
// peek():
String[] arr = new String[]{"a","b","c","d"};
Arrays.stream(arr)
.peek(System.out::println) //a,b,c,d
.count();
// peek()+filter()
Stream.of("ma", "zhi", "chu")
.filter(e -> e.length() > 2)
.peek(e -> System.out.println(e))
.collect(Collectors.toList());
运行结果:
a
b
c
d
zhi
chu
7、limit():顾名思义,返回指定数量的元素的流。返回的是Stream里前面的n个元素。
// limit():取出100中的前十个
List<Integer> limitNum = IntStream.range(1,100).limit(10)
.boxed()
.collect(Collectors.toList());
System.out.println(limitNum);
// limit():取出前4个单词
List<String> words = Arrays.asList("ma", "zhi", "chu", "wait", "you", "follow");
List<String> limitWord = words.stream().limit(4).collect(Collectors.toList());
System.out.println(limitWord);
运行结果:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[ma, zhi, chu, wait]
8.skip():和limit()相反,将前几个元素跳过(取出)再返回一个流,如果流中的元素小于或者等于n,就会返回一个空的流。
// skip():跳过前面三个单词再返回
List<String> words = Arrays.asList("ma", "zhi", "chu", "wait", "you", "follow");
List<String> skipWord = words.stream().limit(4).collect(Collectors.toList());
System.out.println(skipWord);
// skip():跳过全部单词再返回
List<String> emptyWord = words.stream().skip(6).collect(Collectors.toList());
System.out.println(emptyWord);
// skip():跳过超过单词长度的数目再返回
List<String> emptyWord2 = words.stream().skip(10).collect(Collectors.toList());
System.out.println(emptyWord);
运行结果:
[91, 92, 93, 94, 95, 96, 97, 98, 99]
[ma, zhi, chu, wait]
[]
[]
聚合操作:即对流进行终端操作
- forEach()
- forEachOrdered()
- toArray()
- reduce()
- collect()
- min()
- max()
- count()
- anyMatch()
- allMatch()
- noneMatch()
- findFirst()
- findAny()
- toMap()
1.forEach():遍历流中的每一个元素,按照指定的方法执行,执行顺序不一定按照流的顺序。
// foreach:遍历流中每一个元素,执行顺序按照流的顺序
Stream.of(1,2,3,4,5,6).forEach(System.out::println);
// foreach:遍历流中每一个元素,执行顺序不一定按照流的顺序,.parallel()表示创建一个并行流
Stream.of(1,2,3,4,5,6).parallel().forEach(System.out::println);
2.forEachOrdered():遍历流中的每一个元素,按照指定的方法执行,执行顺序按照流的顺序。
// forEachOrdered():遍历流中每一个元素,执行顺序按照流的顺序
Stream.of(1,2,3,4,5,6).forEachOrdered(System.out::println);
// forEachOrdered:遍历流中每一个元素,执行顺序按照流的顺序,.parallel()表示创建一个并行流
Stream.of(1,2,3,4,5,6).parallel().forEachOrdered(System.out::println);
运行结果:
1
2
3
4
5
6
1
2
3
4
5
6
3.toArray():将流中的元素放入到一个数组中
// toArray():将流中的元素放入到一个数组中
String[] strings = Stream.of("ma", "zhi", "chu").toArray(String[]::new);
System.out.println(Arrays.toString(strings));
运行结果:[ma, zhi, chu]
4.reduce():这个方法的主要作用是把 Stream 元素组合起来。它提供一个起始值(种子),然后依照运算规则(BinaryOperator),和前面 Stream 的第一个、第二个、第 n 个元素组合。从这个意义上说,字符串拼接、数值的 sum、min、max、average 都是特殊的 reduce。
// reduce():字符串拼接
String reduceStr1 = Stream.of("ma", "zhi", "chu").reduce("", String::concat);
String reduceStr2 = Stream.of("ma", "zhi", "chu").reduce("", (x,y)->x+y);
System.out.println(reduceStr1);
System.out.println(reduceStr2);
// reduce():求和,identity(起始值)为0
Integer total1 = Stream.of(1,2,3,4).reduce(0, Integer::sum);
Integer total2 = Stream.of(1,2,3,4).reduce(0, (x, y) -> x +y);
System.out.println(total1);
System.out.println(total2);
// 求和,sumValue = 10, 无起始值
Integer total3 = Stream.of(1, 2, 3, 4).reduce(Integer::sum).get();
System.out.println(total3);
// reduce():求最小值
double minValue = Stream.of(-1.1, 8.8, -2.2, -6.6).reduce(Double.MAX_VALUE, Double::min);
System.out.println(minValue);
运行结果:
mazhichu
mazhichu
10
10
10
-6.6
5.collect():是Stream的一个函数,负责收集流。前面我们说中间操作是将一个流转换成另一个流,这些操作是不消耗流的,但是终端操作会消耗流,产生一个最终结果,collect()就是一个规约操作,将流中的结果汇总。结果是由传入collect()中的Collector定义的
// collect():负责收集流,将结果汇总,比如将下面的流中的结果汇总到一个集合中去
List<Integer> skipNum = IntStream.range(1,100).skip(90)
.boxed()
.collect(Collectors.toList());
System.out.println(skipNum);
运行结果:[91, 92, 93, 94, 95, 96, 97, 98, 99]
6.min():返回流中的最小值
// min():返回流中的最小值
List<Integer> nums = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer minNum = nums.stream().min(Integer::compareTo).get();
Integer min = nums.stream().min((x,y) -> x.compareTo(y)).get();
System.out.println(minNum);
System.out.println(min);
运行结果:
1
1
7.max():返回流中的最大值
// max():返回流中的最大值
List<Integer> num = Arrays.asList(1, 2, 3, 4, 5, 6);
Integer maxNum = num.stream().max(Integer::compareTo).get();
Integer max = num.stream().max(Comparator.comparing(Function.identity())).get();
System.out.println(maxNum);
System.out.println(max);
运行结果:
6
6
8.count():返回流中元素的数量
// count():返回流中元素的数量
List<Integer> ls = Arrays.asList(1,2,3,4,5);
long count = ls.stream().count();
long count1 = ls.stream().filter(l -> l > 2).count();
System.out.println(count);
System.out.println(count1);
运行结果:
5
3
9.anyMatch():Stream 中只要有一个元素符合传入的断言,就返回 true,否则返回false。
// anyMatch():判断流中数据是否有一个复合断言
List<Integer> ins = Arrays.asList(1,2,3,4,5);
boolean b = ins.stream().anyMatch(l -> l > 2);
boolean b1 = ins.stream().anyMatch(l -> l > 5);
System.out.println(b);
System.out.println(b1);
// anyMatch():判断流中数据是否有一个复合断言,如果流为空,永远返回false
List<Integer> inss = Arrays.asList();
boolean b2 = inss.stream().anyMatch(l -> l > 2);
System.out.println(b2);
运行结果:
true
false
false
10.allMatch():Stream 中所有元素都符合传入的断言时返回 true,否则返回false,流为空时总是返回true。
// allMatch():判断流中元素是否都符合断言条件
List<Integer> ints = Arrays.asList(1,2,3,4,5);
boolean c = ints.stream().allMatch(l -> l > 0);
boolean c1 = ints.stream().allMatch(l -> l > 1);
System.out.println(c);
System.out.println(c1);
// allMatch():判断流中元素是否都符合断言条件,如果流为空,永远返回true
List<Integer> emptyList = new ArrayList<>();
boolean c2 = emptyList.stream().allMatch(e -> e > 1);
System.out.println(c2);
运行结果:
true
false
true
11.noneMatch():Stream 中所有元素都不满足传入的断言时返回 true,否则返回false。
// noneMatch():判断流中元素是否都不符合传入的断言条件
List<Integer> numList = Arrays.asList(1,2,3,4,5);
boolean d = numList.stream().noneMatch(l -> l > 6);
boolean d1 = numList.stream().noneMatch(l -> l > 1);
System.out.println(d);
System.out.println(d1);
// noneMatch():判断流中元素是否都不符合传入的断言条件,流为空时永远返回true
List<Integer> numist = Arrays.asList();
boolean d2 = numist.stream().noneMatch(l -> l > 6);
System.out.println(d2);
运行结果:
true
false
true
12.findFirst():总是返回流中的第一个元素,如果流为空,返回一个空的Optional.
// findFirst():返回流中的第一个元素
List<Integer> integers = Arrays.asList(1, 2, 3);
Optional<Integer> first = integers.stream().findFirst();
System.out.println(first);
System.out.println(first.isPresent()); // 判断是否不等于null,isPresent()相当于!=null的判断
System.out.println(first.get());
//findFirst():返回流中的第一个元素,如果流为空,返回一个空的Optional
List<Integer> lls = Collections.EMPTY_LIST;
Optional<Integer> first1 = lls.stream().findFirst();
System.out.println(first1);
System.out.println(first1.isPresent());
运行结果:
Optional[1]
true
1
Optional.empty
false
13.findAny():返回流中的任意一个元素即可,如果流为空,返回一个空的Optional.
// findAny():返回流中任意一个元素,
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6);
Optional<Integer> any = list.stream().findAny();
// 并行流下每次返回的结果会不同
// Optional<Integer> any = list.stream().parallel().findAny();
System.out.println(any);
System.out.println(any.isPresent());
System.out.println(any.get());
// findAny():返回流中任意一个元素,如果流为空,返回一个空的Optional
List<Integer> list1 = Arrays.asList();
Optional<Integer> any1 = list1.stream().findAny();
System.out.println(any1);
System.out.println(any1.isPresent());
运行结果:
Optional[1]
true
1
Optional.empty
false
以上即为Stram的流程操作理解
14.toMap()
此为聚合操作中转换为map的操作
使用toMap()函数之后,返回的就是一个Map了,自然会需要key和value。
toMap()的第一个参数就是用来生成key值的,第二个参数就是用来生成value值的。
第三个参数用在key值冲突的情况下:如果新元素产生的key在Map中已经出现过了,第三个参数就会定义解决的办法。
在你的例子中
.collect(Collectors.toMap(UserBo::getUserId, v -> v, (v1, v2) -> v1));
第一个参数UserBo::getUserId 表示选择UserBo的getUserId作为map的key值;
第二个参数v -> v表示选择将原来的对象作为map的value值;
第三个参数(v1, v2) -> v1中,如果v1与v2的key值相同,选择v1作为那个key所对应的value值
可参考:https://www.cnblogs.com/mazhichu/p/11983451.html