函数式接口
介绍
- 只有一个抽象方法的接口则称为函数式接口
- 声明函数时不做具体实现
- 调用时决定实现方式
函数式编程可以把函数当成一个入参,很像策略模式,不同场景,传入不同策略的具体实现。
四大函数式接口
先简单说明一下,当入参是函数式接口时,可以传入lamda表达式。
lamda表达式的语法: () -> {} 箭头左边入参,右边为具体实现。
Consumer,消费型接口
介绍:接收一个入参对其操作,无返回值。因为很像消费者,所以称为消费型接口。
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
实操案例 先定义一个带消费者接口的函数(方法)
/**
* 我们要消费一个double类型的对象:
* 第一个入参定义消费对象。
* 第二个则是我们要使用的消费者接口,至于怎么消费这里不做实现,具体实现在调入时传入。
* @param s
* @param fun
* @return
*/
public static void happy(double money,Consumer<Double> con){
con.accept(money);
}
调用刚刚定义的函数
public static void main(String[] args) {
//调用时对消费数据做具体实现
happy(2000,m -> System.out.println("在环球影城happy,花费了:"+m+"元"));
}
//打印结果:在环球影城happy,花费了:2000.0元
Supplier,供给型接口
介绍:接口方法无入参,带返回值,至于返回什么,由调用时传入。
@FunctionalInterface
public interface Supplier<T> {
T get();
}
实操案例 先定义一个带供给者接口的函数(方法)
/**
* 我们想产生指定个数的整数,并放入集合
* 第一个入参,是根据需求来控制想产生的整数的个数。
* 第二个入参,供给型接口,list添加的元素,就是此接口产生的,至于元素具体是什么,由调用时实现。
* @param supplier
* @return
*/
public static ArrayList<Integer> getList(int num,Supplier<Integer> supplier){
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < num; i++) {
list.add(supplier.get());
}
return list;
}
调用刚刚定义的函数
public static void main(String[] args) {
//1.向集合中添加5个元素
//2.至于添加的元素是什么,我们的实现为添加100内的随机数
System.out.println(getList(5,()->new Random().nextInt(100) + 1));
}
//打印结果:[30, 1, 81, 45, 29]
Function,函数型接口
介绍:接口方法由入参,有返回值。
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
实操案例 先定义一个带函数式接口
/**
* 用于处理字符串
* 第一个入参为我们要处理的字符串
* 第二个入参为函数式接口,至于如何处理入参,返回怎样的值,由调用式实现
* @param s
* @param fun
* @return
*/
public static String strHandler(String s, Function<String,String> fun){
return fun.apply(s);
}
调用刚刚定义的函数
public static void main(String[] args) {
//第一个入参是要处理的字符串,函数式接口的具体实现为截取入参字符串的前六位
System.out.println(strHandler("这是一个长度为13的字符串", s -> s.substring(0,6)));
}
//打印结果:这是一个长度
Predicate,断言型接口
介绍:传入一个入参返回一个布尔值。
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
实操案例 先定义一个带函数式接口
/**
* 将满足条件的字符串添加到新的集合中
* 第一个入参为要处理的集合
* 第二个入参为断言型接口,对入参进行判断,返回布尔值,至于怎么判断由调用者实现
*/
public static List<String> filterStr(List<String> list, Predicate<String> pre){
List<String> stringList = new ArrayList<>();
for (String str : list){
//满足断言实现则加入
if(pre.test(str)) {
stringList.add(str);
}
}
return stringList;
}
调用刚刚定义的函数
public static void main(String[] args) {
//待处理的集合
List<String> list = Arrays.asList("Hello","predicate","Lambda","www","ok");
//第一个入参,传入待处理的集合,第二个入参实现断言接口,长度大于3的字符串返回true
List<String> stringList = filterStr(list,s->s.length()>3);
System.out.println(stringList);
}
//打印结果:[Hello, predicate, Lambda]