简介
**函数式接口(Functional Interface)**就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。
函数式接口可以被隐式转换为 lambda 表达式,常与流一起用于对集合的操作。
**流(Stream)**是一个来自数据源的元素队列,Stream不会存储元素,而是按需计算。
函数式接口(Functional Interface)
常用的函数式接口有Supplier、Consumer、Predicate、Function等。
- Supplier< T > :是一个生产型接口,包含一个无参有返回值的方法 < T > get(),用来获取一个泛型参数指定类型的对象数据,生产一个数据。
public class Demo1 {
public static void main(String[] args) {
//第一种写法,直接实例化接口
Supplier<String> supplier = () -> "abc";
String result1 = supplier.get();
System.out.println(result1);
//第二种写法,作为方法的参数动态生产不同数据类型的数据
String result2 = invoke(()->"test");
Integer result3 = invoke(()->10);
System.out.print(result2 + "\n" + result3);
}
private static <T> T invoke(Supplier<T> supplier){
return supplier.get();
}
}
- Consumer< T >:是一个消费型的接口,包含一个有参无返回值的方法 void accept(T t),用于接收一个需要消费掉的指定泛型的数据。
(1)另外包含有一个默认方法 Consumer< T > andThen(Consumer< ? super T > after),可以实现将多个消费数据的操作进行组合。
public class Demo2 {
public static void main(String[] args) {
//第一种写法,直接实例化接口
String s1 = "123";
Consumer<String> consumer = a->System.out.println(a);
consumer.accept(s1);
//第二种写法,作为方法的参数消费数据
String s2 = "456";
String s3 = "789";
invoke1(s2,a->System.out.println(a));
invoke1(s3,a->System.out.println(a));
invoke2(s2,s-> System.out.println("1."+s), s-> System.out.println("2."+s));
}
private static void invoke1(String b, Consumer<String> con){
con.accept(b);
}
private static void invoke2(String b, Consumer<String> con1, Consumer<String> con2){
//con1消费完后con2再消费
con1.andThen(con2).accept(b);
}
}
- Predicate< T >:是一个判断型接口,包含一个有参有返回值的方法 boolean test(T t),使用传入的数据进行判断操作。
有三个默认方法:与、或、非三种逻辑判断的方法:
(1)Predicate< T > and(Predicate< ? super T > other),与;
(2)Predicate< T > or(Predicate< ? super T > other),或;
(3)Predicate< T > negate(),非。.
public class Demo3 {
public static void main(String[] args) {
//第一种写法,直接实例化接口
Predicate<String> pre1=(t)->t.equals("good");
Predicate<String> pre2=(t)->t.endsWith("d");
boolean result1 = pre1.test("good");
System.out.println(result1);
boolean result2 = pre1.negate().test("good");
System.out.println(result2);
boolean result3 = pre1.and(pre2).test("good");
System.out.println(result3);
boolean result4 = pre1.or(pre2).test("good");
System.out.println(result4);
System.out.println("-------------------------------");
//第二种写法,作为方法的参数对传入的数据进行判断
int m = 10;
invoke1(m, n->n < 10);//false
invoke2(m, n->n == 10, n->n < 10);//false
invoke3(m, n->n == 10, n->n < 10);//true
invoke4(m, n->n == 10, n->n < 10);//false
}
private static void invoke1(Integer n,Predicate<Integer> pre){
boolean result1 = pre.test(n);
System.out.println(result1);
}
private static void invoke2(Integer n,Predicate<Integer> pre1, Predicate<Integer> pre2){
boolean result2 = pre1.and(pre2).test(n);
System.out.println(result2);
}
private static void invoke3(Integer n,Predicate<Integer> pre1, Predicate<Integer> pre2){
boolean result3 = pre1.or(pre2).test(n);
System.out.println(result3);
}
private static void invoke4(Integer n,Predicate<Integer> pre1, Predicate<Integer> pre2){
boolean result4 = pre1.negate().or(pre2).test(n);
System.out.println(result4);
}
}
- Function< T , R >:由前一种数据类型的数据获得后一种数据类型的数据,包含有一个有参有返回值的方法 R apply(T t),根据 T 类型得到 R 类型。
(1)包含一个默认方法 Function< T, R > andThen(Function<? super T> after),可以对多个Function接口进行组合操作。
public class Demo4 {
public static void main(String[] args) {
//第一种写法
Function<String,Boolean> function = n->n.equals("one");
Boolean result = function.apply("two");//false
System.out.println(result);
System.out.println("----------------------");
//第二种写法
String n = "one";
invoke1(n, s->s.equals("one"));//true
invoke2(n, s1->s1.equals("two"), s2->{
if(s2){
return "three";
}else{
return "two";
}
});//false->"two"
}
private static void invoke1(String s, Function<String, Boolean> function){
Boolean result = function.apply(s);
System.out.println(result);
}
private static void invoke2(String s, Function<String, Boolean> function1, Function<Boolean, String> function2){
String result = function1.andThen(function2).apply(s);//先String->Boolean,再Boolean->String
System.out.println(result);
}
}
流(Stream)
一般与函数式接口配合用在对集合操作的简化上。
- 获取流:
(1)所有Collection集合都可以通过默认方法 stream() 获取流;
ArrayList<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
(2)Stream 接口的静态方法 of 可以获取数组或集合对应的流。static < T > Stream < T > of(T…value).
int[] str = new int[10];
ArrayList<String> list1 = new ArrayList<>();
Stream<int[]> str1 = Stream.of(str);
Stream<ArrayList<String>> stream1 = Stream.of(list1);
- 流的常用方法:
(1)void forEach(Consumer<? super T> action):是一个终结方法,参数使用消费型接口。用于遍历。
(2)long count():终结方法,计算流中元素的个数。
(3)Stream< T > filter(Predicate<? super T > predicate):过滤,根据条件过滤流,参数使用Predicate函数式接口。
(4)< R > Stream< R > map(Function<? super T, ? extends R> mapper):映射,将 T 类型数据转换成 R 类型数据。参数使用Function函数式接口。
(5)Stream< T > limit(long maxSize):截取,截取前 maxSize 个元素组成新的流,若集合当前长度大于参数则进行截取,否则不进行操作。
(6)Stream< T > skip(long n):跳过,跳过前 n 个,去剩余元素组成新的流,若流的长度大于 n,则跳过前 n 个,否则将会得到一个长度为 0 空流。
(7)static < T > Stream< T > concat(Stream<? extends T> a, Stream<? extends T> b):将两个流组合成一个新的流。
public class Demo2 {
public static void main(String[] args) {
//Collection集合如ArrayList
ArrayList<Integer> list = new ArrayList<>();
list.add(0);
list.add(1);
list.add(2);
list.add(3);
list.add(4);
Stream<Integer> stream1 = list.stream();
stream1.forEach(a->System.out.println(a));//遍历
System.out.println("-------------------------");
Stream<Integer> stream2 = list.stream();
long count = stream2.count();//统计
System.out.println("list集合的元素个数:"+count);
System.out.println("-------------------------");
Stream<Integer> stream8 = list.stream();
stream8.filter(f->f==1).forEach(f-> System.out.println(f));//过滤,只保留1
System.out.println("-------------------------");
Stream<Integer> stream3 = list.stream();
stream3.map(b->b==4).forEach(b-> System.out.println(b));//映射
System.out.println("-------------------------");
Stream<Integer> stream4 = list.stream();
stream4.limit(2).forEach(c-> System.out.println(c));//截取
System.out.println("-------------------------");
Stream<Integer> stream5 = list.stream();
stream5.skip(2).forEach(d-> System.out.println(d));//跳过
System.out.println("-------------------------");
Stream<Integer> stream6 = list.stream();//第一个流
HashSet<Integer> set = new HashSet<>();
set.add(10);
set.add(20);
set.add(30);
Stream<Integer> stream7 = set.stream();//第二个流
Stream<Integer> concat = Stream.concat(stream6, stream7);//合并
concat.forEach(e-> System.out.println(e));
System.out.println("-------------------------");
//Map集合获取流的方法
HashMap<Integer,String> map = new HashMap<>();
//1.获取键,存储到Set集合中
Set<Integer> keySet = map.keySet();
Stream<Integer> stream9 = keySet.stream();
//2.获取值,存储到Collection集合中
Collection<String> values = map.values();
Stream<String> stream10 = values.stream();
//3.获取键值对(键与值的映射关系 entrySet)
Set<Map.Entry<Integer, String>> entries = map.entrySet();
Stream<Map.Entry<Integer, String>> stream11 = entries.stream();
}
}
一个流可同时使用多个非终结方法,可以极大简化代码的数量,但一个流只能使用一次,且调用终结方法后不能再调用其他流的方法。