目录
一张图说明Stream流
常见的操作函数
常见的终结函数
如何创建一个Stream流
方法引用
具体说说方法引用
首先说明一下,什么是操作函数,就是调用这个函数之后,依然会给我们返回这个流,不会结束
1.filter函数
内部传入了Predicate函数式接口,里面有一个方法是boolean test(T t),也就是他是一个判断过滤函数,不满足条件的数据流会被踢出去。
2.skip函数
3.limit函数
4.map
它内部的一个方法是apply,把一个数据类型变成另外一个数据类型
Demo3.java
import java.util.stream.Stream;
public class Demo3 {
public static void main(String[] args) {
Stream stream1 = Stream.of("10","520","13");
//这是一个String类型的流,我要变成int类型的流
Stream res = stream1.map(str->Integer.parseInt(str));
}
}
5.contact函数
1.count函数
2.foreach函数
接收一个参数进行消费,这个方法一般是对流里面的数据一个打印操作
看一个具体实现代码
Demo1.java
import java.util.ArrayList;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class Demo1 {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("张三丰");
list.add("李四");
list.add("王五");
list.add("张君宝");
list.add("张帅");
Stream stream1 = list.stream();
Stream stream2 = stream1.filter(str->str.length() == 3)
.filter(str->str.startsWith("张"))
.limit(3);
ArrayList list1 = new ArrayList();
stream2.forEach(str-> list1.add(str));
System.out.println(list1);
}
}
运行结果:
然后来看代码:
List one = new ArrayList<>();
// ...
List two = new ArrayList<>();
// ...
// 第一个队伍只要名字为3个字的成员姓名;
// 第一个队伍筛选之后只要前3个人;
Stream streamOne = one.stream().filter(s ‐> s.length() == 3).limit(3);
// 第二个队伍只要姓张的成员姓名;
// 第二个队伍筛选之后不要前2个人;
Stream streamTwo = two.stream().filter(s ‐> s.startsWith("张")).skip(2);
// 将两个队伍合并为一个队伍;
// 根据姓名创建Person对象;
// 打印整个队伍的Person对象信息。
Stream.concat(streamOne, streamTwo).map(Person::new).forEach(System.out::println);
大致就是:obj::方法
其中类的构造器与数组的构造器引用如下使用:
类::new
int[]::new
下面说一下方法引用的可推导原则:
1.方法引用的前提:
函数式接口
为啥是函数式接口呢?因为方法引用本质就是,调用了一个已经实现了函数式接口的方法。
2.方法引用的参数:
无参数
为啥说无参数,因为调用了一个已经存在了的方法,别人已经把参数做好了,你还要啥参数,只需要这个方法匹配就可以了。可推导就是可省略嘛
3.看几个实例
3.1通过对象名引入成员方法
函数式接口AddInterface.java
package pxx;
public interface AddInterface {
//是不是与对象里面的一个方法对应了呢,与Demo1里面的饿方法
int add(int num1,int num2);
}
上一个对象,其实就是实现了函数式接口里面的方法
Demo1.java
package pxx;
public class Demo1 {
//对象名要引入这个方法对吗?
//做一个函数式接口的一个实现
public int add(int num1,int num2) {
return num1 + num2;
}
}
然后测试类Demo2.java
package pxx;
public class Demo2 {
//这里也就是说,要调用函数式接口对吧
public static int calcRes(int num1,int num2,AddInterface addInterface) {
return addInterface.add(num1,num2);
}
public static void main(String[] args) {
Demo1 demo1 = new Demo1();
//lambda表达式可以不,这样绝对可以,但是有点麻烦
int res = calcRes(1,2,(num1,num2)->num1+num2);
//我就用方法引用,存了已经实现了好了的函数式接口方法,为何不用
int res1 = calcRes(1,2,demo1::add);
System.out.println(res + " " + res1);
}
}
运行结果:
其他类似。
具体再说一下对象引用与类的构造器引用
package com.pxx.functionInterface;
import java.util.stream.Stream;
class Person {
private String name;
public Person() {
this.name = "unknown";
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
public class Demo1 {
public static void main(String[] args) {
//创建两个字符串流
Stream streamOne = Stream.of("aa","bb","cc");
//函数传入参数适用于可推导原则
//比如Person::new这里就是类的构造器引用
//这里的推导原则就是:他符不符合当前内部函数式接口的实现
//比如Person::new -> 它的构造方法是一个有参的构造函数 public Person(String name)
//通过这个函数,我们传入一个name,会给我们返回一个Person对象
//而在map方法里面是一个Function函数式接口
//R apply(T t)把T类型变成R类型是不是和上面构造方法是一个方式
//所以,可以通过类的构造器引用进行一个函数式接口的实现
//------------------------------
//再来看一下forEach,它也是Stream流里面的方法
//它内部的函数式接口是forEach(Consumer super T> action)
//Consumer是一个消费式的函数式接口,也就是接收一个参数,然后把这个参数用来干嘛无返回值
//这里System.out就是一个对象吗,它是一个标准输出流对象PrintStream
//它内部的一个println方法就是接收一个参数,然后内部进行操作,无返回值
//这里就是对象引用
streamOne.map(Person::new).forEach(System.out::println);
}
}
这里我在来引入一个问题就是,当我们使用类的构造器引入一个构造方法的时候,到底是用调用的有参构造还是无参构造方法,这里就涉及到了一个“目标类型的推断”。
根据实际场景会自动选择合适的构造函数
package com.pxx.functionInterface;
import java.util.stream.Stream;
class Person1 {
private String name;
public Person1() {
this.name = "unknown";
}
public Person1(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person1{" +
"name='" + name + '\'' +
'}';
}
}
public class Demo2 {
public static void main(String[] args) {
//这里利用generate生成一个无限流,就是这个流里面会有很多的数据
//(Supplier s) 它是一个生产式的接口,没有参数,需要范返回值
//这里调用无参,为什么调用无参,就是因为generate里面就是无参的函数式接口
Stream.generate(Person::new).limit(5).forEach(System.out::println);
}
}