Java中的函数式编程(五)Java集合框架中的高阶函数
写在前面
Java 8中的集合框架
|
接口名
|
Java8新加入的方法
|
|
Collection
|
forEach(), removeIf(), stream(), parallelStream()
|
|
List
|
replaceAll(), sort()
|
|
Map
|
forEach(), replaceAll(), compute(), computeIfAbsent(), computeIfPresent(), merge()
|
一个函数,如果它有一个或多个参数是函数类型的,或者它的返回值是函数类型的,那么我们称这个函数为高阶函数。
public class Container implements Collection { ... }
升级到Java 8后,因为Collection中新增了方法 forEach,假设没有默认方法,之前的类 Container 将编译失败。
Collection中的高阶函数
1. forEach
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
它的作用是遍历集合中的每一个元素,然后依次对每个元素执行参数 action 指定的动作。参数 action 是一个 Consumer 类型的函数式接口,我们可以通过lambda表达式或方法引用来实现一个 Consumer 。因此,在Java 8或以后的版本中,不要用 for 语句来迭代 Collection 了,不妨使用 forEach 方法。
示例代码如下:
public static void collectionForEach() {
Collection<String> list = Arrays.asList("Guangdong", "Zhejiang", "Jiangsu");
// for 语句
for (String s : list) {
System.out.println(s);
}
// forEach 方法 + lambda表达式
list.forEach(s -> System.out.println(s));
// forEach 方法 + 方法引用
list.forEach(System.out::println);
}
2. removeIf
default boolean removeIf(Predicate<? super E> filter) { ... }
removeIf的作用是遍历集合中的每一个元素,然后依次对每个元素进行指定的过滤操作。filter 参数是一个 Predicate 类型的函数式接口。
示例代码如下,假定我们要过滤掉以字母 G 开头的省份:
public static void collectionRemoveIf() {
List<String> provinces = new ArrayList<>(Arrays.asList("Guangdong", "Jiangsu", "Guangxi", "Jiangxi", "Shandong"));
boolean removed = provinces.removeIf(s -> {
return s.startsWith("G");
});
System.out.println(removed);
System.out.println(provinces);
}
上述代码输出为:
3. replaceAll
default void replaceAll(UnaryOperator<E> operator) { ... }
replaceAll方法的作用是对集合中的每个元素执行 operator 指定的计算,并用计算结果替换原来的元素。参数 operator 是类型为 UnaryOperator 的函数式接口,它的参数和返回值类型是相同的。
public static void listReplaceAll() {
List<String> provinces = Arrays.asList("Guangdong", "Jiangsu", "Guangxi", "Jiangxi", "Shandong");
provinces.replaceAll(s -> s.toUpperCase());
System.out.println(provinces);
}
上述代码的输出为:
4. sort
default void sort(Comparator<? super E> c) { ... }
sort方法是根据比较器 c 指定的排序规则,对 List 中的元素进行排序。参数 c 的类型是Comparator,同样是一个函数式接口。
public static void listSort() {
List<String> list = Arrays.asList("Guangdong", "Zhejiang", "Jiangsu", "Xizang", "Fujian", "Hunan", "Guangxi");
// 对省份进行排序,首先按照长度排序,如果长度一样,则按照字母顺序排序
list.sort((first, second) -> {
int lenDiff = first.length() - second.length();
return lenDiff == 0 ? first.compareTo(second) : lenDiff;
});
list.forEach(s -> System.out.println(s));
}
上述代码的输出为:
5. stream 和 parallelStream
Map中的高阶函数
1. forEach
default void forEach(BiConsumer<? super K, ? super V> action) { ... }
可以看到,Map的forEach方法的作用是遍历Map中所有的键值对,并执行参数 action 指定的操作。参数 action 的类型是函数式接口 BiConsumer,要求有2个参数,分别代表键值对的key和value。
public static void mapForEach() {
Map<String, String> cityMap = new HashMap<>();
cityMap.put("Guangdong", "Guangzhou");
cityMap.put("Zhejiang", "Hangzhou");
cityMap.put("Jiangsu", "Nanjing");
cityMap.forEach((key, value) -> {
System.out.println(String.format("%s 的省会是 %s", key, value));
});
}
上述代码的输出为:
2. replaceAll
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) { ... }
public static void mapReplaceAll() {
Map<String, String> cityMap = new HashMap<>();
cityMap.put("Guangdong", "Guangzhou");
cityMap.put("Zhejiang", "Hangzhou");
cityMap.put("Jiangsu", "Nanjing");
// 将省府的拼音转换为大写
cityMap.replaceAll((key, value) -> {
return value.toUpperCase();
});
cityMap.forEach((key, value) -> {
System.out.println(String.format("%s 的省会大写是 %s", key, value));
});
}
3. compute
default V compute(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) { ... }
示例代码如下:
public static void mapCompute() {
Map<String, String> cityMap = new HashMap<>();
cityMap.put("Guangdong", "null");
cityMap.put("Zhejiang", "Hangzhou");
cityMap.put("Jiangsu", "null");
// 稍显复杂的语句,先调用 forEach 遍历 cityMap 中的键,然后根据原有的键值对计算新的值
Set keys = new HashSet<>(cityMap.keySet());
keys.forEach(key -> {
cityMap.compute(key, (k, v) -> {
// 如果是 Guangdong,则返回 Guangzhou
if ("Guangdong".equals(k)) {
return "Guangzhou";
}
// 如果旧的键值对中,值是字符串 "null" ,则返回 null。
// 这意味着 cityMap 会删除对应的key
if ("null".equals(v)) {
return null;
}
// 否则,返回原来的 value 值
return v;
});
});
cityMap.forEach((key, value) -> {
System.out.println(String.format("%s 的省会是 %s", key, value));
});
}
上述代码的输出为:
4. computeIfPresent
default V computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
V oldValue;
if ((oldValue = get(key)) != null) {
V newValue = remappingFunction.apply(key, oldValue);
if (newValue != null) {
put(key, newValue);
return newValue;
} else {
remove(key);
return null;
}
} else {
return null;
}
}
5. computeIfAbsent
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
} return v;
}
public static void mapComputeIfAbsent() {
Map<String, Integer> staffMap = new HashMap<>();
staffMap.put("Lilei", 24);
staffMap.put("Hanmeimei", 22);
staffMap.put("Liming", 24);
staffMap.put("Jim", 22);
staffMap.put("David", 24);
Map<Integer, List<String>> staffInvertMap = new HashMap<>();
staffMap.forEach((key, value) -> {
// 以年龄为键,构建一个新的Map
// 以 22 岁为例:
// 如果 staffInvertMap 之前不存在 22 岁对应的映射关系,
// 则新建一个 "年龄 -> ArrayList<String>" 的映射,并且把新建的 ArrayList 返回。
// 如果 staffInvertMap 已经存在 22 岁对应的映射关系了,则将已存在的 ArrayList 返回。
List<String> nameList = staffInvertMap.computeIfAbsent(value, age -> {
// 对于同一个 age,这句代码只会执行一次
return new ArrayList<>();
});
nameList.add(key);
});
System.out.println(staffInvertMap);
}
6. merge
default V merge(K key, V value,
BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
Objects.requireNonNull(value);
V oldValue = get(key);
V newValue = (oldValue == null) ? value :
remappingFunction.apply(oldValue, value);
if(newValue == null) {
remove(key);
} else {
put(key, newValue);
}
return newValue;
}
public static void mapMerge() {
Map<String, String> staffMap = new HashMap<>();
staffMap.put("Lilei", "性别男 ");
// 等价于 staffMap.merge("Lilei", "年龄 24", String::concat)
// oldValue 即之前添加的值 “性别男 ”,value 即merge函数的第二个参数 “年龄24”
staffMap.merge("Lilei", " 年龄24", (oldValue, value) -> oldValue.concat(value));
staffMap.merge("Hanmeimei", "年龄22", String::concat);
System.out.println(staffMap);
}
结语
Java中的函数式编程(五)Java集合框架中的高阶函数的更多相关文章
- JavaScript ES6函数式编程(一):闭包与高阶函数
函数式编程的历史 函数的第一原则是要小,第二原则则是要更小 -- ROBERT C. MARTIN 解释一下上面那句话,就是我们常说的一个函数只做一件事,比如:将字符串首字母和尾字母都改成大写,我们此 ...
- Java 中的函数式编程(Functional Programming):Lambda 初识
Java 8 发布带来的一个主要特性就是对函数式编程的支持. 而 Lambda 表达式就是一个新的并且很重要的一个概念. 它提供了一个简单并且很简洁的编码方式. 首先从几个简单的 Lambda 表达式 ...
- 为什么函数式编程在Java中很危险?
摘要:函数式编程这个不温不火的语言由来已久.有人说,这一年它会很火,尽管它很难,这也正是你需要学习的理由.那么,为什么函数式编程在Java中很危险呢?也许这个疑问普遍存在于很多程序员的脑中,作者Ell ...
- 浅谈Java 8的函数式编程
函数式编程语言是什么? 函数式编程语言的核心是它以处理数据的方式处理代码.这意味着函数应该是第一等级(First-class)的值,并且能够被赋值给变量,传递给函数等等.(转载自http://xz.p ...
- 随便聊聊 Java 8 的函数式编程
函数式编程(Functional Programming) 首先,我们来了解一个叫做"编程范式"的概念. 什么是"编程范式"呢?简单来说就是指导我们编程的方法论 ...
- Java集合框架中的快速失败(fail—fast)机制
fail-fast机制,即快速失败机制,是java集合框架中的一种错误检测机制.多线程下用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加.删除),则会抛出Concurre ...
- Java函数式编程:二、高阶函数,闭包,函数组合以及柯里化
承接上文:Java函数式编程:一.函数式接口,lambda表达式和方法引用 这次来聊聊函数式编程中其他的几个比较重要的概念和技术,从而使得我们能更深刻的掌握Java中的函数式编程. 本篇博客主要聊聊以 ...
- 第49节:Java集合框架中底层文档的List与Set
Java集合框架中的List与Set // 简书作者:达叔小生 Collection -> Set 无序不重复 -> 无序HashSet,需要排序TreeSet -> List 有序 ...
- 牛客网Java刷题知识点之Java 集合框架的构成、集合框架中的迭代器Iterator、集合框架中的集合接口Collection(List和Set)、集合框架中的Map集合
不多说,直接上干货! 集合框架中包含了大量集合接口.这些接口的实现类和操作它们的算法. 集合容器因为内部的数据结构不同,有多种具体容器. 不断的向上抽取,就形成了集合框架. Map是一次添加一对元素. ...
随机推荐
- vue element-ui 做分页功能之封装
在 vue 项目中的 components 中 创建一个 文件夹,文件夹里创建一个 name(这个名字你随意取).vue <template> <div class=" ...
- Java基础(三)——内部类
一.内部类 内部类(Inner Class)就是定义在一个类里面的类.与之对应,包含内部类的类被称为外部类.内部类可以用private修饰. 1.为什么要定义内部类?或者内部类的作用是什么? 内部类提 ...
- Django实现基本的页面分页
1.视图views.py from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage def index(requ ...
- Mysql - You can't specify target table '表名' for update in FROM clause 错误解决办法
背景 在MySQL中,写SQL语句的时候 ,可能会遇到 You can't specify target table '表名' for update in FROM clause 这样的错误 错误含义 ...
- 关于Golang的学习路线
基础 安装golang环境 Golang基础,流程控制,函数,方法,面向对象 网络编程(自己做一个简单的tcp的聊天室,websocket,http,命令行工具) 并发(可以看一下并发爬虫或者下载器的 ...
- python库--tensorflow--数学函数
官方API(需FQ) 中文API 方法 返回值类型 参数 说明 算数运算符 .add() Tensor x, y, name=N 加法(若x,y都为tensor, 数据类型需一致, 以下所有x,y都如 ...
- 我下载了python所有包,用以备份,有需要的自提
1.背景 我最近准备把1985年-2019年的全国30m分辨率土地利用数据按照地级市进行裁剪与归纳,这需要用到Geopandas对shp数据进行批量操作.在安装Geopandas的python包时,遇 ...
- Jmeter系列(34)- Jmeter优化常识
Jmeter UI页面是调试脚本的,运行脚本使用命令行运行:Windows使用batch,Linux使用shell Jmeter减少使用各类监听控件,吃内存.CPU:用后置处理去拿log文件,生成图表 ...
- Kotlin协程入门
开发环境 IntelliJ IDEA 2021.2.2 (Community Edition) Kotlin: 212-1.5.10-release-IJ5284.40 介绍Kotlin中的协程.用一 ...
- python学习笔记(十五)-异常处理
money = input('输入多少钱:') months = input('还几个月:') try: res = calc(int(money),int(months)) except ZeroD ...