1.Stream流常用方法
- Stream流是一个集合元素的函数模型,既不是集合,也不是数据结构,其本身并不存储任何元素,仅按需计算
- Stream流函数模型每一步并没有处理集合元素,仅当终结方法count执行时,模型才会执行操作(得益于Lambda的延迟执行特性)
- Pipelining: 中间操作都会返回流对象本身
- 内部迭代:流可以直接调用遍历方法,不同于Iterator或者增强for的集合外部迭代方式
①获取方法
//所有的Collection集合都可以通过stream默认方法获取流;
public interface Collection<E> extends Iterable<E> {
default Stream<E> stream()
return StreamSupport.stream(spliterator(), false);
}
//Stream接口的静态方法of可以获取数组对应的流
public interface Stream<T> {
public static<T> Stream<T> of(T... values)
return Arrays.stream(values);
}
1.把单列集合转换为Stream流
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
Stream<String> strmList = list.stream();
Stream<String> strmSet = set.stream();
2.把双列集合转换为Stream流
Map<String,String> map = new HashMap<>();
Set<String> keySet = map.keySet();//获取键,存储到一个Set集合中
Collection<String> values = map.values();//获取值,存储到一个Collection集合中
Stream<String> strmMapk = keySet.stream();
Stream<String> strmMapv = values.stream();
//获取键值对(键与值的映射关系 entrySet)
Set<Map.Entry<String, String>> entries = map.entrySet();
Stream<Map.Entry<String, String>> strmEtry = entries.stream();
//把数组转换为Stream流
Stream<Integer> integerStream = Stream.of(1, 2, 3, 4, 5);
Integer[] arr = {1,2,3,4,5};
String[] arr2 = {"a","bb","ccc"};
Stream<Integer> stream7 = Stream.of(arr);
Stream<String> stream8 = Stream.of(arr2);
②操作方法
void forEach(Consumer<? super T> action);
public interface Consumer<T> void accept(T t);//消费接口
Stream<T> filter(Predicate<? super T> predicate);
public interface Predicate<T> boolean test(T t);//判断接口
<R> Stream<R> map(Function<? super T, ? extends R> mapper);
public interface Function<T, R> R apply(T t);//转换接口
long count();//个数
Stream<T> limit(long maxSize);//截取方法
Stream<T> skip(long n);//跳过方法
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)//把两个流合并成为一个流
Stream<String> stream1 = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
Stream<String> stream2 = stream1.filter( name->name.startsWith("张"));
stream2.forEach(name-> System.out.println(name));
Stream<String> stream1 = Stream.of("1", "2", "3", "4");
//把字符串类型映射为Integer类型
Stream<Integer> stream2 = stream1.map( s-> Integer.parseInt(s));
long num = stream2.count();
Stream<Integer> stream3 = stream2.limit(3); //1 2 3
Stream<Integer> stream3 = stream2.skip(3); //4
Stream<String> stream1 = Stream.of("张三丰", "张翠山", "赵敏", "周芷若", "张无忌");
Stream<String> stream2 = Stream.of("美羊羊","喜洋洋","懒洋洋","灰太狼","红太狼");
Stream<String> concat = Stream.concat(stream1, stream2);
concat.forEach(name-> System.out.println(name));
forEach count都是终结方法
//IllegalStateException: stream has already been operated upon or closed
stream1.forEach(name-> System.out.println(name));//已关闭,无法使用
2.方法引用
在Lambda中所指定的操作方案,已经有地方存在相同方案,那是否还有必要再写重复逻辑?
@FunctionalInterface
public interface Printable { void print(String str); }
private static void printString(Printable data) {
data.print("Hello, World!");
}
printString(s ‐> System.out.println(s));
- printString 方法只管调用Printable 接口的print 方法,而并不管print 方法如何实现字符串打印
- 经Lambda,继而传递给System.out.println 方法去处理
问题在于
:然而打印字符串有现成的操作方案System.out对象中的println(String) 方法。既然Lambda希望做的事情就是调用println(String) 方法,又何必手动调用呢?直接让System.out 中的println 方法来取代Lambda
printString(System.out::println);
//函数式接口是Lambda的基础,而方法引用是Lambda的孪生兄弟
- System.out对象是已经存在的,println方法也是已经存在的,
- 所以我们可以使用使用System.out方法直接引用(调用)println方法
①通过对象引用成员方法 / 类引用静态方法
- 前提是:对象 类 成员方法 静态方法
均存在
!
1.成员方法是已经存在的printUpperCaseString
public class MethodRefObject {
public void printUpperCase(String str) { System.out.println(str.toUpperCase());}
}
@FunctionalInterface
public interface Printable { void print(String str); }
2.对象是已经存在的MethodRerObject
那么当需要使用这个printUpperCase成员方法来替代Printable接口
的Lambda的时候,则可以通过对象名引用成员方法
private static void printString(Printable lambda) {
lambda.print("Hello");
}
printString((s)->{
MethodRerObject obj = new MethodRerObject();
obj.printUpperCaseString(s);
});
MethodRefObject obj = new MethodRefObject();
printString(obj::printUpperCase);
public final class Math {
public static int abs(int a)
}
@FunctionalInterface
public interface Calcable { int calsAbs(int number); }
public static int method(int number,Calcable c){
return c.calsAbs(number);
}
int number = method(-10,(n)->{ return Math.abs(n); });
System.out.println(number);
/*
使用方法引用优化Lambda表达式
Math类是存在的
abs计算绝对值的静态方法也是已经存在的
所以我们可以直接通过类名引用静态方法
*/
int number2 = method(-10,Math::abs);//n -> Math.abs(n)
System.out.println(number2);
}
②通过super / this引用父 / 本类成员方法
public class Human {
public void sayHello(){ System.out.println("Hello 我是Human!");}
}
@FunctionalInterface
public interface Greetable { void greet(); }
public class Man extends Human{
@Override
public void sayHello() { System.out.println("Hello 我是Man!");}
//定义一个方法参数传递Greetable接口
public void method(Greetable g){ g.greet(); }
public void show(){
method(()->{ Human h = new Human(); h.sayHello(); });
method(()->{ super.sayHello(); });
method(()->{ this.sayHello(); });
/*
使用super引用类的成员方法
super是已经存在的
父类的成员方法sayHello也是已经存在的
所以我们可以直接使用super引用父类的成员方法
*/
method(super::sayHello);
method(this::sayHello);
}
new Man().show();
③类 / 数组 的构造器引用
public class Person {
private String name;
...
public Person() { }
public Person(String name) { this.name = name; }
}
@FunctionalInterface
public interface Born {
//定义一个方法,根据传递的姓名,创建Person对象返回
Person builderPerson(String name);
}
//定义一个方法,参数传递姓名和PersonBuilder接口,方法中通过姓名创建Person对象
public static void printName(String name,Born pb){
Person person = pb.builderPerson(name);
System.out.println(person.getName());
}
//调用printName方法,方法的参数PersonBuilder接口是一个函数式接口,可以传递Lambda
printName("迪丽热巴",(String name)->{ return new Person(name); });
/*
使用方法引用优化Lambda表达式
构造方法new Person(String name) 已知
创建对象已知 new
就可以使用Person引用new创建对象
*/
printName("古力娜扎",Person::new);//使用Person类的带参构造方法,通过传递的姓名创建对象
@FunctionalInterface
public interface ArrayBuilder { int[] builderArray(int length); }
//定义一个创建int类型数组的方法,参数传递数组的长度,返回创建好的int类型数组
public static int[] createArray(int length, ArrayBuilder ab){
return ab.builderArray(length);
}
//调用createArray方法,传递数组的长度和Lambda表达式
int[] arr1 = createArray(10,(len)->{ return new int[len]; });
/*
使用方法引用优化Lambda表达式
已知创建的就是int[]数组
数组的长度也是已知的
就可以使用方法引用
int[]引用new,根据参数传递的长度来创建数组
*/
int[] arr2 =createArray(10,int[]::new);