当前位置: 首页 > news >正文

Java 8的函数式接口使用示例

什么是函数式接口

有且只有一个抽象方法的接口被称为函数式接口,函数式接口适用于函数式编程的场景,Lambda就是Java中函数式编程的体现,可以使用Lambda表达式创建一个函数式接口的对象,一定要确保接口中有且只有一个抽象方法,这样Lambda才能顺利的进行推导。

与@Override 注解的作用类似,Java 8中专门为函数式接口引入了一个新的注解:@FunctionalInterface 。该注解可用于一个接口的定义上,一旦使用该注解来定义接口,编译器将会强制检查该接口是否确实有且仅有一个抽象方法(equal和hashcode方法不算),否则将会报错。但是这个注解不是必须的,只要符合函数式接口的定义,那么这个接口就是函数式接口。

Consumer<T>: 消费型接口

Consumer通过名字可以看出它是一个消费函数式接口,主要针对的是消费(1…n 入参, 无返回)这个场景,它的代码定义如下:

@FunctionalInterface
public interface Consumer<T> {void accept(T t);
}

通过泛型 T 定义了一个入参,但是没有返回值,它代表你可以针对这个入参做一些自定义逻辑,比较典型的例子是forEach方法。
例子:

List<String> list = Lists.newArrayList("1", "2", "3", "4", "5", "6");
list.foreach(System.out::println); //打印数组

Supplier<T>: 供给型接口

Supplier通过名字比较难看出来它是一个场景的函数式接口,它主要针对的是说获取(无入参,有返回)这个场景,它的代码定义如下:

@FunctionalInterface
public interface Supplier<T> {T get();
}

通过泛型 T 定义了一个返回值类型,但是没有入参,它代表你可以针对调用方获取某个值,比较典型的例子是 Stream中的collect方法,通过自定义传入我们想要取得的某种对象进行对象收集。
例子:

List<String> list = Lists.newArrayList("1", "2", "3", "4", "5", "6");
List<String> newList = list.stream().filter(x -> x >= 2).collect(Collectors.toList()); 
// 将大于等于2的数重新收集成一个集合,其中Collectors.toList()的函数原型为 
// new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,(left, right) -> { left.addAll(right); return left; },CH_ID)
// 原型中的ArrayList::new即为Supplier类型

Function<T,R>: 函数型接口

Function接口的名字不太能轻易看出来它的场景,它主要针对的则是 转换(有入参,有返回,其中T是入参,R是返回)这个场景,其实说转换可能也不太正确,它是一个覆盖范围比较广的场景,你也可以理解为扩展版的Consumer,接口定义如下:

@FunctionalInterface
public interface Function<T, R> {R apply(T t);
}

通过一个入参T进行自定义逻辑处理,最终得到一个出参R,比较典型的例子是Stream中的map系列方法和reduce系列方法。
例子:

List<String> list = Lists.newArrayList("1", "2", "3", "4", "5", "6");
List<Integet> newList = list.stream().map(Integer::parseInt).collect(Collectors.toList());
// map将list中所有的元素的类型由 String 通过 Integer.parseInt的方式转换为Intger。 简单来说就是A => B;/*** 权益转换*/
private final Function<BenefitDTO,BenefitResponse> BENEFIT_RESPONSE_CONVERTOR = benefitDTO -> {BenefitResponse benefitResponse = new BenefitResponse();benefitResponse.setId(benefitDTO.getBenefitId());benefitResponse.setBenefitName(benefitDTO.getBenefitName());benefitResponse.setStartTime(benefitDTO.getStartTime());benefitResponse.setEndTime(benefitDTO.getEndTime());benefitResponse.setChannel(benefitDTO.getBenefitChannel());benefitResponse.setSellerId(benefitDTO.getSellerId());return benefitResponse;
};List<BenefitResponse> benefitResponseList = benefitList.stream().map(BENEFIT_RESPONSE_CONVERTOR).collect(Collectors.toList());

Predicate<T>: 断言型接口

Predicate主要针对的是判断(有入参,有返回,凡是返回的类型固定为Boolean。可以说Function是包含Predicate的 )这个场景,它的代码定义如下:

@FunctionalInterface
public interface Predicate<T> {boolean test(T t);
}

通过泛型 T 定义了一个入参,返回了一个布尔值,它代表你可以传入一段判断逻辑的函数,比较典型的例子是Stream中的filter方法。

List<String> list = Lists.newArrayList("1", "2", "3", "4", "5", "6");
List<String> newList = list.stream().filter(x -> x >= 2).collect(Collectors.toList()); 
// 将大于等于2的数重新收集成一个集合,filter中的 x -> x >= 2就是Predicate接口

Bi类型接口

BiConsumer、BiFunction、BiPrediate是Consumer、Function、Predicate 的扩展,可以传入多个参数,没有BiSupplier是因为Supplier没有入参。

BiConsumer接口接收两个泛型参数,对这两个参数做消费处理;使用这个函数式接口的终端操作常用的是遍历map。

@FunctionalInterface
public interface BiConsumer<T, U> {/*** Performs this operation on the given arguments.* @param t the first input argument* @param u the second input argument*/void accept(T t, U u);
}

Map接口的终端操作,forEach的参数就是BiConsumer函数接口,对HashMap的数据进行消费,示例如下。

Map<String, String> map = new HashMap<>();
map.put("a", "a");
map.put("b", "b");
map.put("c", "c");
map.put("d", "d");
map.forEach((k, v) -> {System.out.println(k+,+v);
});

操作基本数据类型的接口

IntConsumer、IntFunction、IntPredicate、IntSupplier、LongConsumer、LongFunction、LongPredicate、LongSupplier、DoubleConsumer、DoubleFunction、DoublePredicate、DoubleSupplier。

其实常用的函数式接口就那四大接口Consumer、Function、Prediate、Supplier,其他的函数式接口就不一一列举了,可以去java.util.function包下看源码。

http://www.lryc.cn/news/7900.html

相关文章:

  • 2023年企业如何改善员工体验?为什么员工体验很重要?
  • 设计模式:桥接模式让抽象和实现解耦,各自独立变化
  • C++学习记录——십 STL初级认识、标准库string类
  • 【redis】redis缓存与数据库的一致性
  • XCP实战系列介绍12-基于Vector_Davinci工具的XCP配置介绍(一)
  • Unity Material详解
  • 碰撞检测算法分类
  • 代码随想录第十二天(
  • 电源模块 DC-DC直流升压正负高压输出12v24v转±110V±150V±220V±250V±300V±600V
  • 【动画图解】这个值取对了,ViewPager2才能纵享丝滑
  • CSDN每日一练:小豚鼠搬家
  • Dockerfile命令及实践构建一个网站
  • [VMware]Ubuntu18.04 网络图标消失
  • 国产C2000,P2P替代TMS320F280049C,独立双核32位CPU,主频高达400MHz
  • 二十五、Gtk4-多线程分析
  • JVM基础学习
  • ASML逆袭史:人、资金、技术,缺一不可
  • MongoDB 覆盖索引查询
  • Flink Checkpoint 中的Aligned Checkpoint 和 Unaligned Checkpoint
  • C++快速入门
  • ubuntu18.04 network有线网络图标缺失解决记录
  • java对象克隆和面向对象的设计原则
  • 传透式血氧仪设计方案
  • 让逆向工程师们头疼的代码混淆,就像永远也走不出的“浪浪山”
  • 【拓展】基于机器学习的心脏病预测方法(14)——心脏病数据集补充
  • 深度解读Webpack中的loader原理
  • 2023年全国最新二级建造师精选真题及答案
  • 为什么现代企业发展离不开CRM系统的助力
  • vb.net计算之.net core基础(1)-获取农历和天气
  • 设计模式之代理模式详解和应用