Stream流
说到Stream便容易想到I/O Stream,而实际上,谁规定“流”就一定是“IO流”呢?在Java 8中,得益于Lambda所带来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端。 使用流的步骤: 获取一个数据源(source)–>数据转换–>执行操作想要的结果,每次转换原有Stream对象不改变,返回一个新的Stream对象(可以多次转换),这就允许对其操作可以像链条一样排列,变成一个管道
获取流
java.util.stream.Stream 是Java 8新加入的最常用的流接口。(这并不是一个函数式接口。) 获取一个流非常简单,有以下几种常用的方式:
- 所有的Collection 集合都可以通过stream 默认方法获取流;
- Stream 接口的静态方法of 可以获取数组对应的流。
根据Collection获取流
首先, java.util.Collection 接口中加入了default方法stream 用来获取流,所以其所有实现类均可获取流。
List<String> list = new ArrayList<>();
// ...
Stream<String> stream1 = list.stream();
根据Map获取流
java.util.Map 接口不是Collection 的子接口,且其K-V数据结构不符合流元素的单一特征,所以获取对应的流 需要分key、value或entry等情况:
Map<String, String> map = new HashMap<>();
// ...
Stream<String> keyStream = map.keySet().stream();
Stream<String> valueStream = map.values().stream();
Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
根据数组获取流
如果使用的不是集合或映射而是数组,由于数组对象不可能添加默认方法,所以Stream 接口中提供了静态方法 of :
String[] array = { "张无忌", "张翠山", "张三丰", "张一元" };
Stream<String> stream = Stream.of(array);
备注: of 方法的参数其实是一个可变参数,所以支持数组。
常用方法
package DemoStream01;
import java.util.ArrayList;
import java.util.List;
public class Demo01ForEach {
public static void main(String[] args) {
List<String> list =new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");
//传统集合遍历,对集合中的数据进行过滤
List<String> list1=new ArrayList<>();
for (String name:list){
if (name.startsWith("张")){
list1.add(name);
}
}
List<String> list2=new ArrayList<>();
for (String name1:list1){
if (name1.length()==3){
list2.add(name1);
}
}
//Stream流的方式,对数据中集合进行过滤
list.stream()
.filter(s -> s.startsWith("张"))
.filter(s -> s.length()==3)
.forEach(System.out::println);
}
}
方法应用
package DemoStream01;
import java.util.stream.Stream;
public class Demo02ForEach {
public static void main(String[] args) {
Stream<String> srtream =Stream.of("张无忌","张三丰","周芷若");
srtream.forEach(name -> System.out.println(name));//forEach接收一个Consumer接口函数,会将每一个流元素交给该函数进行处理
Stream<String> stream =Stream.of("张无忌","张三丰","赵敏");
Stream<String> results = stream.filter(s -> s.startsWith("张"));//filter用于对Stream流中的数据进行过滤
System.out.println(results.count());//count方法类似于Collection中的size一样,流提供count方法来数一数其中方法的个数
/*Stream流属于管道流只能被消费(使用)一次,第一个Stream流调用完毕方法,
数据流转换到下一个Stream上,而这时Stream流已经使用完毕,也已经关闭了,所以代码会报IllegalStateException:
: stream has already been operated upon or closed*/
Stream<String> original = Stream.of("10","111","123");
Stream<Integer> result = original.map(s -> Integer.parseInt(s));//如果需要流中的元素映射到另一个流中,可以使用Map方法
result.forEach(s -> System.out.println(s));
Stream<String> original1= Stream.of("10","101","123");
Stream<String> result1 = original1.limit(2);//limit方法可以对流进行截取,只取前n个,参数是一个long型,如果集合当前长度大于参数
//进行截取,否则不进行操作
System.out.println(result1.count());
Stream<String> original2 =Stream.of("张无忌","张三丰","赵敏");
Stream<String> result2 = original2.skip(2);//如果希望跳过前几个元素,参数是一个long型,如果当前长度大于参数
//则跳过前n个,否则会得到一个长度为0的空流
System.out.println(result2);
Stream<String> streamA =Stream.of("张无忌","张三丰");
Stream<String> streamB =Stream.of("周芷若","赵敏");
Stream<String> result3 = Stream.concat(streamA,streamB);//如果有两个流,那么可以使用Stream接口的静态方法contact
//这是一个静态方法与java.lang.string当中的concat方法是不同的
result3.forEach(s -> System.out.println(result3));
}
}
练习 传统做法:
package DemoStream01;
import java.util.ArrayList;
public class Demo01Excercise {
public static void main(String[] args) {
//1、第一支队伍
ArrayList<String> one=new ArrayList<>();
one.add("迪丽热巴");
one.add("杨幂");
one.add("陈数");
one.add("赵丽颖");
one.add("宋轶");
one.add("杨颖");
one.add("杨千嬅");
one.add("容祖儿");
one.add("宋祖儿");
//2、第一支队伍只要名字为3个字的成员姓名,存储到一个新的集合中
ArrayList<String>one1= new ArrayList<>();
for (String name:one){
if (name.length()==3){
one1.add(name);
}
}
//3、第二支队伍
ArrayList<String> two=new ArrayList<>();
two.add("刘德华");
two.add("刘备");
two.add("刘谦");
two.add("刘德华");
two.add("张学友");
two.add("黎明");
two.add("成龙");
two.add("甄子丹");
two.add("李小龙");
//4、第二支队伍只要姓刘的成员姓名,存储到一个新的集合中
ArrayList<String> two1=new ArrayList<>();
for (String name:two){
if (name.startsWith("刘")){
two1.add(name);
}
}
//5、第二支队伍筛选后不要前两人
ArrayList<String>two2= new ArrayList<>();
for (int i = 2; i <two1.size() ; i++) {
two2.add(two1.get(i));
}
//6、将两个队伍合并为1个队伍,存储到一个新的集合中
ArrayList<String> all=new ArrayList<>();
all.addAll(one1);
all.addAll(two2);
//7、根据姓名创建Person对象,存储到一个新集合中
ArrayList<Person> persons =new ArrayList<>();
for (String person:all){
DemoStream01.Person personObject = new DemoStream01.Person(person);
persons.add(personObject);
}
//7、打印整个队伍的Person对象信息
for (DemoStream01.Person person :persons){
System.out.println(person.getName());
}
}
}
使用Stream流
package DemoStream01;
import java.util.ArrayList;
import java.util.stream.Stream;
public class Demo02Excercise {
public static void main(String[] args) {
//第一支队伍
ArrayList<String> one=new ArrayList<>();
one.add("迪丽热巴");
one.add("杨幂");
one.add("陈数");
one.add("赵丽颖");
one.add("宋轶");
one.add("杨颖");
one.add("杨千嬅");
one.add("容祖儿");
one.add("宋祖儿");
//1、第一支队伍只要名字为3个字的成员姓名,存储到一个新的集合中
//第一支队伍筛选之后只要前三个人,存储到一个新集合中
Stream<String> oneStream=one.stream().filter(name->name.length()==3).limit(3);
//第二支队伍
ArrayList<String> two=new ArrayList<>();
two.add("刘德华");
two.add("刘备");
two.add("刘谦");
two.add("刘德华");
two.add("张学友");
two.add("黎明");
two.add("成龙");
two.add("甄子丹");
two.add("李小龙");
//3、第二支队伍只要姓刘的成员姓名,存储到新的集合中
//4、第二支队伍筛选之后不要前两个人,存储到新集合中
Stream<String> twoStream= two.stream().filter(name->name.startsWith("张")).skip(2);
//5、将两个队伍合并为1个队伍,存储到一个新的集合中
//6、根据姓名创建Person对象,存储到一个新集合中
//7、打印整个队伍的Person对象信息
Stream.concat(oneStream,twoStream).map(name->new Person(name)).forEach(person -> System.out.println(person));
}
}
方法引用
package StreamMethodUseDemo;
/*Lambda表达式的目的,打印参数传递的字符串
把参数s传递给了system.out,调用out对象中的方法printIn对字符串进行了输出
注意:
1、System.out对象是已经存在的
2、printIn方法是已经存在的
所以可以使用方法引用优化Lambda表达式
可以使用System.out方法直接引用(调用)printIn方法
*/
import LambdaTest.Calculate;
public class Demo01Printable {
//定义一个方法,参数传递Printable接口,对字符串进行打印
public static void printString(Printable p){
p.print("Hello World");
}
public static void method(int num, Calcable lambda){
System.out.println(lambda.calc(num));
}
public static void main(String[] args) {
//调用printString方法,方法的参数Printable是一个函数式接口,所以可以传递Lambda
printString(s-> System.out.println(s));
printString(System.out::println);
//1、通过对象名引用成员方法
MethodRefObject obj = new MethodRefObject();
printString(obj::printUppercase);
//2、通过类名称引用静态方法
method(10,Math::abs);
}
}
package StreamMethodUseDemo;
public class Man extends Human{
@Override
public void sayHello() {
System.out.println("大家好,我是Man");
}
//定义方法Method,参数传递Greetable接口
public void Method(Greetable g){
g.greet();
}
public void show1(){
Method(()->new Human().sayHello());
//使用super关键字代替父类对象
Method(()->super.sayHello());
}
//3、使用方法引用来调用父类中的sayHello方法
public void show2(){
Method(super::sayHello);
}
}
package StreamMethodUseDemo;
public class Husband {
private void marry(Richable lambada){
lambada.buy();
}
private void buyHouse(){
System.out.println("买套房子");
}
public void beHappy(){
marry(()-> System.out.println("买套房子"));
//在lambda表达式中使用this关键字
marry(()->this.buyHouse());
//4、方法引用
marry(this::buyHouse);
}
}
package StreamMethodUseDemo;
//类构造器引用
public class Demo02Lambda {
public static void printName(String name,PersonBuilder builder){
System.out.println(builder.builderPerson(name).getName());
}
public static void main(String[] args) {
printName("赵丽颖",name -> new Person(name));
//5、类构造器引用
printName("赵丽颖",Person::new);
}
}
package StreamMethodUseDemo;
public class Demo02ArrayInitRef {
private static int[] intArray(int length,ArrayBuilder builder){
return builder.builderArray(length);
}
public static void main(String[] args) {
int[] array=intArray(10,length -> new int[length]);
//6、数组的构造器引用
int[] array1=intArray(10,int[]::new);
System.out.println(array.length);
}
}
|