1. Stream流
1.1. Stream流引入
Stream流完全不是I/O流,按照流水线处理方式来考虑代码中的思想。
JDK1.8 之后,我们拥有了Lambda表达式,让代码的中心偏向解决实际问题,直到重点,
可以提高效率。
Stream流中使用了大量Lambda表达式,利用Lambda操作 方式,提供开发效率
1.2 传统遍历方式和Stream类处理方式对比
public class Demo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>() ;
list.add("李渊") ;
list.add("李世民") ;
list.add("李隆基") ;
list.add("李隆飞") ;
list.add("武则天") ;
list.add("段段") ;
ArrayList<String> list1 = new ArrayList<>() ;
for (String s : list) {
if (s.contains("李")) {
list1.add(s) ;
}
}
System.out.println(list1);
ArrayList<String> list2 = new ArrayList<>() ;
for (String s : list1) {
if (3 == s.length()) {
list2.add(s) ;
}
}
for (String s : list2)
System.out.println(s);
}
}
public class BetterDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>() ;
list.add("李渊") ;
list.add("李世民") ;
list.add("李隆基") ;
list.add("李隆飞") ;
list.add("武则天") ;
list.add("段段") ;
/**
* 使用stream流对Demo1进行优化
*/
list.stream()
.filter(s -> s.contains("李"))
.filter(s -> s.length() == 3)
.forEach(s -> System.out.println(s));
}
}
1.3 Stream流对应的思想
流水线: 原材料从头到尾只会占用一份空间,中间的过程中不会占 用空间。最后生成一个结果。
Stream流有一些特征:
1. 带有很多Stream流操作的方法, filter,limit, map,sorted,skip…这些方法大多是都会使用到函数式接 口,有lambda表达式
2. 整个Stream流模型操作过程中,只有执行到count, foreach这些方法,操作真正的执行中的模型,如果不存在结 果导向,中间的所有操作是无效的,这里得益于Lambda表达式的延后性
3. Stream流是存在一定的管道性 Pipelining 流水线
1.4 获取Stream流
java.util.stream.Stream JDK1.8的新特征
1. 所有的Collection集合都有对应的Stream();
2. 可以通过Stream类中的static Stream of()获取
static Stream of(T… t); static Stream of(T t);
public class Demo2 {
public static void main(String[] args) {
List<String> list = new ArrayList<>() ;
Stream<String> stream1 = list.stream() ;
Set<String> set = new HashSet<>() ;
Stream<String> stream2 = set.stream();
//只要是connector单列集合都可以用stream()方法直接转换为Stream流
Map<String , String> map = new HashMap<>() ;
Stream<String> stream3 = map.keySet().stream() ;
Stream<String> stream4 = map.values().stream() ;
Stream<Map.Entry<String , String>> stream5 = map.entrySet().stream();
//Map要先转换成键,值或者键值对等单列集合在调用stream()方法转换为Stream流
Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5);
Integer[] arr1 = {1,2,3,4,5,6} ;
Stream<Integer> stream7 = Stream.of(arr1);
String[] arr2 = {"飞哥" , "羽羽" , "段段"} ;
Stream<String> stream8 = Stream.of(arr2);
//使用Stream接口中的静态方法将数组装换为Stream流
//把数组转换成Stream流
}
}
1.5 Stream常用方法
延迟方法:
返回值类型依然是Stream接口本身,并没有影响我们操 作真正的资源
允许链式操作,
例如 filter(XXX).limit(XXX).sorted(XXX).
终结方法: 返回值类型不是Stream接口本身,要么处理数据,要么返回其他类型数据,并且不再支持Stream流对象链式操作, count,foreach
1.5.1 foreach方法
forEach()方法将stream流中的数据进行遍历
返回值不再是stream流
是一个终结流方法
forEach()方法中的参数为Consumer函数式接口
package com.my.demo1;
import java.util.stream.Stream;
/**
* forEach()方法将stream流中的数据进行遍历
* 返回值不再是stream流
* 是一个终结流方法
*/
public class Demo3 {
public static void main(String[] args) {
Stream<String> stream = Stream.of("飞哥", "羽羽", "段段");
//流中的forEach方法对流中的数据进行遍历
//forEach()方法中的参数为Consumer函数式接口
//可以用lambda表达式书写
stream.forEach((s -> System.out.println(s)));
}
}
1.5.2 filter方法
filter方法将一个stream流中的数据进行过滤
返回值仍然是一个stream流
filter() 方法中的参数为Predicate函数式接口
package com.my.demo1;
import java.util.stream.Stream;
/**
* filter方法将一个stream流中的数据进行过滤
* 返回值仍然是一个stream流
*/
public class Demo4 {
public static void main(String[] args) {
Stream<String> stream = Stream.of("李隆基", "李隆飞", "杨玉环", "武则天");
Stream<String> stream1 = stream.filter((s -> s.startsWith("李"))) ;
stream1.forEach((s -> System.out.println(s)));
//stream.forEach(s -> System.out.println(s));
// 报错!!!
//一个stream流只能消费一次,第一个stream使用过后就关闭了,所以就不能再调用方法了
}
}
1.5.3map()方法
map()方法将一种stream流转换为另一种stream流
返回值仍然是一个stream流
map()方法中的参数为Function函数式接口
package com.my.demo1;
import java.util.stream.Stream;
/**
* map()方法将一种stream流转换为另一种stream流
* 返回值仍然是一个stream流
*/
public class Demo5 {
public static void main(String[] args) {
Stream<String> stream = Stream.of("1", "2", "3", "4");
Stream<Integer> integerStream = stream.map((s -> Integer.parseInt(s)));
integerStream.forEach((s) -> System.out.println(s));
}
}
1.5.4count()
count()方法用于统计stream流中的元素个数
返回值不再是一个Stream流,是一个long类型数据
是一个终结流方法
package com.my.demo1;
import java.util.ArrayList;
import java.util.stream.Stream;
/**
* count()方法用于统计stream流中的元素个数
* 返回值不再是一个Stream流,是一个long类型数据
* 是一个终结流方法
*/
public class Demo6 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>() ;
list.add(1) ;
list.add(2) ;
list.add(3) ;
list.add(4) ;
list.add(5) ;
Stream<Integer> stream = list.stream();
System.out.println(stream.count());
}
}
1.5.5limit(long maxSize)方法
limit(long maxSize)方法是对流中的元素进行截取
返回值仍然是一个stream流,可以进行链式操作
package com.my.demo1;
import java.util.stream.Stream;
public class Demo7 {
/**
* limit(long maxSize)方法是对流中的元素进行截取
* 返回值仍然是一个stream流,可以进行链式操作
*/
public static void main(String[] args) {
String[] strings = {"飞哥" , "羽羽" , "小明" , "段段"};
Stream<String> stream = Stream.of(strings);
Stream<String> stream1 = stream.limit(3);
stream1.forEach(s -> System.out.println(s));
}
}
2. 方法引用
2.1 Lambda冗余问题以及方法引用初识
public class Demo11 {
public static void main(String[] args) {
printString((s) -> System.out.println(s));
printString(System.out::println);
}
public static void printString(FunctionIn1 fun) {
fun.print("飞哥");
}
}
2.2 方法引用小要求
- 明确对象 对象 ==> 调用者 类对象,类名,super,this,构造方法,数组构造方法
- 明确的执行方法 该方法只有名字不需要显式出现参数
- 需要处理的数据 【联想,推导,省略】
- :: 方法引用格式
2.3 通过类对象来执行方法引用
- 明确对象 类对象
- 明确执行的方法 自定义
- 处理的数据 简单要求为String类型
public class Demo12 {
public static void main(String[] args) {
// printString((s -> {
// MethodDemo1 methodDemo1 = new MethodDemo1();
// methodDemo1.printUppercase(s);
// }));
/**
* 使用方法引用对lambda表达式进行优化
*/
printString(new MethodDemo1()::printUppercase);
}
public static void printString(FunctionIn1 fun){
fun.print("aaaddd");
}
}
2.4 通过类名来执行方法引用
public class Demo13 {
public static void main(String[] args) {
// int num = test(-10 , (n) ->{
// return Math.abs(n);
// });
/**
* 使用方法引用优化lambda表达式
*/
int num = test(-10 , Math::abs);
System.out.println(num);
}
public static int test(int number , FunctionIn2 fun) {
return fun.calsAbs(number);
}
}
2.5 通过super关键字执行方法引用
public class MethodDemo3 extends MethodDemo2 {
public static void main(String[] args) {
new MethodDemo3().show();
}
@Override
public void sayHello() {
System.out.println("你好啊!我是Demo3");
}
public void test(FunctionIn3 fun) {
fun.greet();
}
public void show() {
// test(() -> {
// MethodDemo2 methodDemo2 = new MethodDemo2();
// methodDemo2.sayHello();
// });
/**
* 使用方法引用优化lambda表达式
*/
test(super::sayHello);
}
}
2.6 通过this关键字执行方法引用
public class MethodDemo4 {
public static void main(String[] args) {
new MethodDemo4().soHappy();
}
public void buyHouse() {
System.out.println("买大别墅,靠大海!");
}
public void marry(FunctionIn4 fun) {
fun.buy();
}
public void soHappy() {
// marry(() -> {
// this.buyHouse();
// });
/*
使用方法引用优化lambda表达式
*/
marry(this::buyHouse);
}
}
2.7 构造器引用(构造方法引用)
public class MethodDemo5 {
public static void main(String[] args) {
printName("飞哥" , (name) -> {
return new Person(name) ;
});
//使用构造器引用优化lambda表达式
printName("羽羽" , Person::new);
}
public static void printName(String name , FunctionIn5 fun) {
Person person = fun.creatPerson(name);
System.out.println(person.getName());
}
}
2.8 数组引用
public class MethodDemo6 {
public static void main(String[] args) {
int[] arr1 = test(5 , (n) -> {
return new int[n] ;
} );
System.out.println(arr1.length);
int[] arr2 = test(6, int[]::new);
System.out.println(arr2.length);
System.out.println(Arrays.toString(arr2));
}
public static int[] test(int length , FunctionIn6 fun) {
return fun.buildArr(length);
}
}