Stream流、方法引用
一、Stream流
1. 两种获取Stream流的方式
java.util.stream.Stream<T>
是Java 8
新加入的最常用的流接口。(这并不是一个函数式接口)- 获取流的方式:
- 所有的
Collection
集合都可以通过stream
默认方法获取流。
default Stream<E> stream()
Stream
接口的静态方法of
可以获取数组对应的流。
static <T> Stream<T> of(T... values)
- 参数是一个可变参数,那么就可以传递一个数组。
import java.util.*;
import java.util.stream.Stream;
public class Test {
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();
Map<String,String> map = new HashMap<>();
Set<String> keySet = map.keySet();
Stream<String> stream3 = keySet.stream();
Collection<String> values = map.values();
Stream<String> stream4 = values.stream();
Set<Map.Entry<String, String>> entries = map.entrySet();
Stream<Map.Entry<String, String>> stream5 = entries.stream();
Stream<Integer> stream6 = Stream.of(1, 2, 3, 4, 5);
String[] arr = {"a","bb","ccc"};
Stream<String> stream7 = Stream.of(arr);
}
}
2. Stream流中的常用方法
- 逐一处理:forEach
Stream
流中的常用方法:forEach
void forEach(Consumer<? super T> action);
- 该方法接收一个
Consumer
接口函数,会将每一个流元素交给函数进行处理。 Consumer
接口是一个消费型的函数式接口,可以传递Lambda
表达式,消费数据。- 注意:
forEach
方法,用来遍历流中的数据。- 是一个终结方法,遍历之后就不能继续调用
Stream
流中的其他方法。
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
String[] strings = {"朱古力","猪猪侠","猪猪猪"};
Stream.of(strings).forEach(name->System.out.println(name));
}
}
- 过滤:filter
Stream
流中的常用方法:filter
,用于对Stream
流中的数据进行过滤。
Stream<T> filter(Predicate<? super T> predicate);
filter
方法的参数Predicate
是一个函数式接口,所以可以传递Lambda
表达式,对数据进行过滤。Predicate
中的抽象方法:
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
String[] strings = {"朱古力","猪猪侠","猪猪猪"};
Stream<String> stream = Stream.of(strings).filter(name -> name.startsWith("朱"));
stream.forEach(name -> System.out.println(name));
}
}
- Stream流的特点:
Stream
流属于管道流,只能被消费一次。- 第一个
Stream
流调用完毕方法,数据就会流转到下一个Stream
上,而这时第一个Stream
流已经使用完毕,就会关闭了,所以第一个Stream
流就不能再调用方法了。
- 映射:map
- 如果需要将流中的元素映射到另一个流中,可以使用
map
方法。 <R> Stream<R> map(Function<? super T, ? extends R> mapper);
- 该参数需要一个
Function
函数式接口,可以将当前流中的T
类型数据转换为另一种R
类型的流。 Function
中的抽象方法:
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
String[] strings = {"1","2","3","4","5"};
Stream<Integer> integerStream = Stream.of(strings).map(str -> Integer.parseInt(str));
integerStream.forEach(i -> System.out.println(i + 1));
}
}
- 统计个数:count
Stream
流中的常用方法count
:用于统计Stream
流中元素的个数。
count
方法是一个终结方法,返回值是一个long
类型的整数,所以不能再继续调用Stream
流中的其他方法了。
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
long count = list.stream().count();
System.out.println(count);
}
}
- 取用前几个:limit
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.stream().limit(3).forEach(i -> System.out.println(i));
}
}
- 跳过前几个:skip
Stream
流中的常用方法:skip
用于跳过元素。- 如果希望跳过前几个元素,可以使用
skip
方法获取一个截取之后的新流。
Stream<T> skip(long n);
- 如果流的当前长度大于
n
,则跳过前n
个,否则将会得到一个长度为0的空流。
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.stream().skip(3).forEach(i -> System.out.println(i));
}
}
- 组合:concat
Stream
流中的常用方法:concat
用于把流组合到一起。- 如果有两个流,希望合并称为一个流,那么可以使用
Stream
流中的静态方法concat
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b);
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
Stream<String> stream1 = Stream.of("zhuguli", "zhuzhuxia", "zhuzhuzhu");
Stream<String> stream2 = Stream.of("朱古力", "猪猪侠", "猪猪猪");
Stream<String> stream = Stream.concat(stream1, stream2);
stream.forEach(name -> System.out.println(name));
}
}
3. 练习
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class Test {
public static void main(String[] args) {
List<String> oneTeam = new ArrayList<>();
oneTeam.add("朱古力");
oneTeam.add("朱古");
oneTeam.add("朱古力力");
oneTeam.add("猪猪侠");
oneTeam.add("猪猪猪");
List<String> twoTeam = new ArrayList<>();
twoTeam.add("朱古古");
twoTeam.add("朱力力");
twoTeam.add("朱猪侠");
twoTeam.add("猪猪侠");
twoTeam.add("猪猪猪");
List<String> newOneTeam = new ArrayList<>();
oneTeam.stream().filter(name -> name.length()==3).limit(2).forEach(name -> newOneTeam.add(name));
List<String> newTwoTeam = new ArrayList<>();
twoTeam.stream().filter(name -> name.startsWith("朱")).skip(2).forEach(name -> newTwoTeam.add(name));
List<String> newTeam = new ArrayList<>();
Stream<String> newOneTeamStream = newOneTeam.stream();
Stream<String> newTwoTeamStream = newTwoTeam.stream();
Stream.concat(newOneTeamStream,newTwoTeamStream).forEach(name -> newTeam.add(name));
List<Person> people = new ArrayList<>();
newTeam.stream().forEach(name -> people.add(new Person(name)));
people.stream().forEach(person -> System.out.println(person));
}
}
二、方法引用
1. 方法引用符
- 双冒号
::
为引用运算符,而它所在的表达式被称为方法引用。如果 Lambda
要表达的函数方案已经存在于某个方法的实现中,那么则可以通过双冒号来引用该方法作为 Lambda
的替代者。
public interface PrintTable {
public abstract void print(String str);
}
public class Test {
public static void printString(PrintTable p) {
p.print("Hello,World");
}
public static void main(String[] args) {
printString((String str)->{
System.out.println(str);
});
printString(System.out::println);
}
}
2. 通过对象名引用成员方法
- 使用前提:对象名已经存在,成员方法也已经存在,就可以使用对象名引用成员方法。
public interface PrintTable {
public abstract void print(String str);
}
public class MethodRefObject {
public void printUpperCaseString(String str) {
System.out.println(str.toUpperCase());
}
}
public class Test {
public static void printTable(PrintTable p) {
p.print("hello");
}
public static void main(String[] args) {
printTable((s)->{
MethodRefObject obj = new MethodRefObject();
obj.printUpperCaseString(s);
});
MethodRefObject obj = new MethodRefObject();
printTable(obj::printUpperCaseString);
}
}
3. 通过类名引用静态方法
- 前提:类已经存在,静态成员方法也已经存在,就可以通过类名直接引用静态成员方法。
@FunctionalInterface
public interface Calcable {
public int calcAbs(int number);
}
public class Test {
public static int calc(int num, Calcable calc){
return calc.calcAbs(num);
}
public static void main(String[] args) {
int rs1 = calc(-5, (int num) -> {
return Math.abs(num);
});
System.out.println(rs1);
int rs2 = calc(-5, Math::abs);
System.out.println(rs2);
}
}
4. 通过super引用父类的成员方法
@FunctionalInterface
public interface Greetable {
public abstract void greet();
}
public class Humen {
public void sayHello(){
System.out.println("Hello,is Humen");
}
}
public class Men extends Humen {
@Override
public void sayHello() {
System.out.println("Hello,is Men");
}
public void method(Greetable g) {
g.greet();
}
public void show(){
method(()->{
Humen h = new Humen();
h.sayHello();
});
method(()->{
super.sayHello();
});
method(super::sayHello);
}
public static void main(String[] args) {
new Men().show();
}
}
5. 使用this引用本类成员方法
@FunctionalInterface
public interface Richable {
public void buy();
}
public class Husbend {
public void buyHouse(){
System.out.println("Buy a house!");
}
public void marry(Richable r) {
r.buy();
}
public void soHappy(){
marry(()->{
this.buyHouse();
});
marry(this::buyHouse);
}
public static void main(String[] args) {
new Husbend().soHappy();
}
}
6. 类的构造器引用
public class Person {
private String name;
public Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@FunctionalInterface
public interface PersonBuilder {
Person getPerson(String name);
}
public class Test {
public static void printName(String name, PersonBuilder pb) {
Person person = pb.getPerson(name);
System.out.println(person.getName());
}
public static void main(String[] args) {
printName("zhuguli",(name)->{
return new Person(name);
});
printName("zhuzhuxia",Person::new);
}
}
7. 数组的构造器引用
@FunctionalInterface
public interface ArrayBuilder {
int[] arrayBuilder(int length);
}
public class Test {
public static int[] getArray(int length, ArrayBuilder ab){
return ab.arrayBuilder(length);
}
public static void main(String[] args) {
int[] arr1 = getArray(10,(length)->{
return new int[length];
});
System.out.println(arr1.length);
int[] arr2 = getArray(20,int[]::new);
System.out.println(arr2.length);
}
}