函数式接口
函数式接口是有且仅有一个抽象方法的接口,通过@FunctionalInterface来检测(自定义函数式接口时可以不要,只要满足条件就是函数式接口)。Java中函数式编程体现就是Lambda表达式,所以函数式接口就是适用于Lambda使用的接口。
有两个抽象方法就会报错。
- 函数式接口作为方法的参数,如果方法的参数是一个函数式接口,我们可以用Lambda表达式作为参数传递
- 函数式接口作为方法的返回值,如果一个方法的返回值是一个函数式接口,我们可以把一个Lambda表达式作为结果返回
常用的函数式接口
jdk8在java.util.function包下预定义了大量的函数式接口,下面介绍一下其中比较常用的四个接口,主要是配合Stream流使用。
-
Supplier接口
java.util.function.Supplier接口也被称为生产型接口,包含一个无参的方法 T get(),我们想要什么,get方法就可以返回什么。使用Supplier接口作为方法的参数。 -
Consumer接口
java.util.function.Consumer也被称为消费型接口,包含一个常用的方法 void accept(T t),用来消费一个指定泛型的数据。“消费"就是"操作”,至于怎么操作,就看重写accept方法之后,方法体怎么写了。 -
Function接口
java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据,常用的R apply(T t)方法会根据类型T参数获取类型R的结果
- Predicate接口
java.util.function.Predicate接口是判断型接口,常用的方法boolean test(T t)用于判断的方法,返回值为boolean型
常用函数式接口配合Stream流的使用
Stream流是一种流式编程(编程方式),用起来非常方便,缺点是代码可读性降低,它可以看做是流水线。
常用Stream流获取的方式
- 针对集合Collection中的方法,Stream stream()
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三");
list.add("李四");
list.add("王五");
Stream<String> stream = list.stream();
}
}
- 针对数组Stream接口中的静态方法,static Stream of(T… values)
public class Main {
public static void main(String[] args) {
Stream<String> stream = Stream.of("张三", "李四", "王五");
System.out.println(stream);
}
}
Stream的方法
void forEach(Consumer<? super T> action)
:void forEach(Consumer<? super T> action); 用来遍历。
public class Main {
public static void main(String[] args) {
foreach();
}
private static void foreach() {
Stream<String> stream = Stream.of("张三", "李四", "王五");
stream.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
stream.forEach(s-> System.out.println(s));
}
}
forEach方法是一个终结方法,使用完之后,Stream流不能用,所以使用一个forEach方法就行。
long count()
:用来统计元素个数,也是终结方法
public class Main {
public static void main(String[] args) {
count();
}
private static void count() {
Stream<String> stream = Stream.of("张三","李四","王五");
long count = stream.count();
System.out.println("count = " + count);
}
}
Stream中的Stream<T> filter(Predicate<? super T> predicate)
方法:根据某个条件进行元素过滤返回一个新的Stream流对象
如下可以体会使用“.”符号的流式编程思想,过滤出来长度等于三的名字,并打印
public class Main {
public static void main(String[] args) {
filter();
}
private static void filter() {
Stream<String> stream = Stream.of("张三", "李四", "王五", "哈哈哈", "嘿嘿嘿");
stream.filter(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.length() == 2;
}
}).forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
}
}
使用Lambda简化
public class Main {
public static void main(String[] args) {
filter();
}
private static void filter() {
Stream<String> stream = Stream.of("张三", "李四", "王五", "哈哈哈", "嘿嘿嘿");
stream.filter(s -> s.length()==2).forEach(s -> System.out.println(s));
}
}
Stream<T> limit(long maxSize)
:获取Stream流对象中的前n个元素,返回一个新的Stream流对象
public class Main {
public static void main(String[] args) {
limit();
}
private static void limit() {
Stream<String> stream = Stream.of("张三", "李四", "王五", "哈哈哈", "嘿嘿嘿");
stream.limit(3).forEach(s -> System.out.println(s));
}
}
Stream<T> skip(long n)
:跳过Stream流对象中的前n个元素,返回一个新的Stream流对象
跳过流对象中的前3个元素
public class Main {
public static void main(String[] args) {
skip();
}
private static void skip() {
Stream<String> stream = Stream.of("张三", "李四", "王五", "哈哈哈", "嘿嘿嘿");
stream.skip(2).forEach(s -> System.out.println(s));
}
}
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)
:两个流合成一个流
public class Main {
public static void main(String[] args) {
concat();
}
private static void concat() {
Stream<String> stream1 = Stream.of("张三", "李四", "王五");
Stream<String> stream2 = Stream.of("哈哈哈", "嘿嘿嘿");
Stream.concat(stream1, stream2).forEach(s -> System.out.println(s));
}
}
<R, A> R collect(Collector<? super T, A, R> collector)
:Stream接口方法collect():将Stream流变成集合
public class Main {
public static void main(String[] args) {
collect();
}
private static void collect() {
Stream<String> stream = Stream.of("张三", "李四", "王五", "哈哈哈", "嘿嘿嘿");
Set<String> strings = stream.collect(Collectors.toSet());
System.out.println(strings);
}
}
Stream<T> distinct()
:元素去重复,依赖hashCode和equals方法。
public class Main {
public static void main(String[] args) {
distinct();
}
private static void distinct() {
Stream<Student> stream = Stream.of(new Student(10,"张三" ), new Student(66, "李四"), new Student(888, "张三"),new Student(66, "李四"));
stream.distinct().forEach(person -> System.out.println(person));
}
}
Stream<R> map(Function<T,R> mapper)
:转换流中的数据类型
public class Main {
public static void main(String[] args) {
map();
}
private static void map() {
Stream<Integer> stream = Stream.of(6,66,666,888);
stream.map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) {
return integer+""; //转换成字符串
}
}).forEach(s -> System.out.println(s+"哈哈"));
}
}