java中函数式编程的一些测试
Java中函数式编程的一些测试
在上一篇文章中, 提及了java中的函数式编程, 但缺少了一些相关的代码, 这里补充一下.
注意, 本文中的代码并不代表最佳实践, 只是提供一种思路, 其中有很多代码并没有实际价值!
树反转
static class TreeNode {
private final int val;
private TreeNode left;
private TreeNode right;
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
@Override
public String toString() {
return "[" + val + "," + left + "," + right + ']';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TreeNode treeNode = (TreeNode) o;
return Objects.equals(val, treeNode.val)
&& Objects.equals(left, treeNode.left)
&& Objects.equals(right, treeNode.right);
}
@Override
public int hashCode() {
return Objects.hash(val, left, right);
}
}
// 创建从源树到目标树的转换函数, 将左树映射到右树, 右树映射到左树
private TreeNode newReverseTree(TreeNode root) {
if (root == null) {
return null;
}
return new TreeNode(root.val, newReverseTree(root.right), newReverseTree(root.left));
}
// 原地反转
private void reverseTree(TreeNode root) {
if (root == null) {
return;
}
var left = root.left;
root.left = root.right;
root.right = left;
reverseTree(root.left);
reverseTree(root.right);
}
@Test
public void testTreeReverse() {
// 构造 [0,1,2,3,4,5,6]的树
var root = new TreeNode(0, null, null);
root.left = new TreeNode(1, null, null);
root.right = new TreeNode(2, null, null);
root.left.left = new TreeNode(3, null, null);
root.left.right = new TreeNode(4, null, null);
root.right.left = new TreeNode(5, null, null);
root.right.right = new TreeNode(6, null, null);
// 使用新建反转
var newRoot = newReverseTree(root);
// 使用原地反转
reverseTree(root);
// 遍历比较两棵树的值
assert Objects.equals(root, newRoot);
// [0, 2, 1, 6, 5, 4, 3]
assert Objects.equals(
root,
new TreeNode(
0,
new TreeNode(2, new TreeNode(6), new TreeNode(5)),
new TreeNode(1, new TreeNode(4), new TreeNode(3))));
}
数据处理
// 遍历, 并将长度大于3的结果添加到目标list中
private void addLengthGt3(List<String> list, List<String> result) {
for (String s : list) {
if (s.length() > 3) {
result.add(s);
}
}
}
// 从源list中映射出长度大于3的list
private List<String> filterLengthGt3(List<String> list) {
return list.stream().filter(s -> s.length() > 3).toList();
}
@Test
public void testFilterLengthGt3() {
var target = new ArrayList<String>();
var list = List.of("a", "ab", "abc", "abcd", "abcde");
addLengthGt3(list, target);
var lengthGt3 = filterLengthGt3(list);
assert target.equals(lengthGt3);
assert target.equals(List.of("abcd", "abcde"));
}
科里化
@Test
public void testCurryAdd() {
// x, y -> x + y
@SuppressWarnings("Convert2MethodRef")
BinaryOperator<Integer> add = (x, y) -> x + y;
// x -> y -> x + y
Function<Integer, Function<Integer, Integer>> curryAdd = x -> y -> x + y;
assert Objects.equals(curryAdd.apply(1).apply(2), add.apply(1, 2));
}
// 参数准备
private static <T, A, R> Function<A, R> prepare(BiFunction<T, A, R> func, T obj) {
return a -> func.apply(obj, a);
}
// 反转函数的参数列表
private static <T, A, R> BiFunction<A, T, R> flip(BiFunction<T, A, R> func) {
return (a, t) -> func.apply(t, a);
}
/** 科里化 */
@Test
public void testCurryPrepareCopy() {
// 复制数组的函数
BiFunction<int[], Integer, int[]> baseFunc = Arrays::copyOf;
// 固定数组为[1,2,3,4,5], 从数组中复制前n个元素的函数
var copyFormArray = prepare(baseFunc, new int[] {1, 2, 3, 4, 5});
assert Arrays.equals(copyFormArray.apply(3), new int[] {1, 2, 3});
assert Arrays.equals(copyFormArray.apply(2), new int[] {1, 2});
// 从数组中复制前3个元素的函数
var copyTop3 = prepare(flip(baseFunc), 3);
assert Arrays.equals(copyTop3.apply(new int[] {1, 2, 3, 4, 5}), new int[] {1, 2, 3});
assert Arrays.equals(copyTop3.apply(new int[] {1, 2, 4, 5}), new int[] {1, 2, 4});
}
Optional
@Test
public void testStrLen() {
assert strlen0(1234) == strlen1(1234);
assert strlen0("1234") == strlen1("1234");
}
private int strlen0(Object obj) {
return Optional.ofNullable(obj)
.filter(String.class::isInstance)
.map(String.class::cast)
.map(String::length)
.orElse(0);
}
private int strlen1(Object obj) {
if (obj instanceof String str) {
return str.length();
}
return 0;
}
函数组合
private static <T, A, R> Function<? super T, ? extends R> pipe(
Function<? super T, ? extends A> function1, Function<? super A, ? extends R> function2) {
return function1.andThen(function2);
}
@Test
public void testFuncCompose() {
// 组合数字转字符串和乘以2的函数
var pipe = Tests.<String, Integer, Integer>pipe(Integer::parseInt, x -> x * 2);
assert pipe.apply("1") == 2;
assert pipe.apply("2") == Integer.parseInt("2") * 2;
}
@Test
public void testListFilter() {
var list = List.of("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
var filtered = listFilter(list);
var funcFiltered = listFilterFunc().apply(list);
assert Arrays.equals(filtered, funcFiltered);
assert Arrays.equals(filtered, new int[] {2, 4, 6, 8, 10});
}
private int[] listFilter(List<String> list) {
return list.stream().mapToInt(Integer::parseInt).map(x -> x * 2).filter(x -> x <= 10).toArray();
}
/** 函数的组合 通过构造从集合转换为数组的函数, 实现对应操作. */
private Function<? super Collection<String>, int[]> listFilterFunc() {
// String -> Integer
Function<String, Integer> parseInt = Integer::parseInt;
// String -> Integer
ToIntFunction<String> toIntFunction = pipe(parseInt, (x) -> x * 2)::apply;
// (String -> Integer, Stream<String>) -> IntStream
var mapToInt = Tests.<Stream<String>, ToIntFunction<String>, IntStream>flip(Stream::mapToInt);
// (Stream<String>, IntStream) -> IntStream
var stringStreamToIntStreamFunction = prepare(mapToInt, toIntFunction);
// (Integer -> Boolean, IntStream, IntStream) -> IntStream
var intStreamFilterFunc = flip(IntStream::filter);
// (IntStream, IntStream) -> IntStream
var intStreamFilter = prepare(intStreamFilterFunc, (x) -> x <= 10);
// (Collection<String>, Stream<String>) -> IntStream
Function<Collection<String>, Stream<String>> function = Collection::stream;
return function
// Collection<String> -> IntStream
.andThen(stringStreamToIntStreamFunction)
// IntStream -> IntStream
.andThen(intStreamFilter)
// IntStream -> int[]
.andThen(IntStream::toArray);
}
全部代码
class Tests {
static class TreeNode {
private final int val;
private TreeNode left;
private TreeNode right;
TreeNode(int val) {
this.val = val;
}
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
@Override
public String toString() {
return "[" + val + "," + left + "," + right + ']';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TreeNode treeNode = (TreeNode) o;
return Objects.equals(val, treeNode.val)
&& Objects.equals(left, treeNode.left)
&& Objects.equals(right, treeNode.right);
}
@Override
public int hashCode() {
return Objects.hash(val, left, right);
}
}
// 创建从源树到目标树的转换函数, 将左树映射到右树, 右树映射到左树
private TreeNode newReverseTree(TreeNode root) {
if (root == null) {
return null;
}
return new TreeNode(root.val, newReverseTree(root.right), newReverseTree(root.left));
}
// 原地反转
private void reverseTree(TreeNode root) {
if (root == null) {
return;
}
var left = root.left;
root.left = root.right;
root.right = left;
reverseTree(root.left);
reverseTree(root.right);
}
@Test
public void testTreeReverse() {
// 构造 [0,1,2,3,4,5,6]的树
var root = new TreeNode(0, null, null);
root.left = new TreeNode(1, null, null);
root.right = new TreeNode(2, null, null);
root.left.left = new TreeNode(3, null, null);
root.left.right = new TreeNode(4, null, null);
root.right.left = new TreeNode(5, null, null);
root.right.right = new TreeNode(6, null, null);
// 使用新建反转
var newRoot = newReverseTree(root);
// 使用原地反转
reverseTree(root);
// 遍历比较两棵树的值
assert Objects.equals(root, newRoot);
// [0, 2, 1, 6, 5, 4, 3]
assert Objects.equals(
root,
new TreeNode(
0,
new TreeNode(2, new TreeNode(6), new TreeNode(5)),
new TreeNode(1, new TreeNode(4), new TreeNode(3))));
}
// 遍历, 并将长度大于3的结果添加到目标list中
private void addLengthGt3(List<String> list, List<String> result) {
for (String s : list) {
if (s.length() > 3) {
result.add(s);
}
}
}
// 从源list中映射出长度大于3的list
private List<String> filterLengthGt3(List<String> list) {
return list.stream().filter(s -> s.length() > 3).toList();
}
@Test
public void testFilterLengthGt3() {
var target = new ArrayList<String>();
var list = List.of("a", "ab", "abc", "abcd", "abcde");
addLengthGt3(list, target);
var lengthGt3 = filterLengthGt3(list);
assert target.equals(lengthGt3);
assert target.equals(List.of("abcd", "abcde"));
}
// 参数准备
private static <T, A, R> Function<A, R> prepare(BiFunction<T, A, R> func, T obj) {
return a -> func.apply(obj, a);
}
// 反转函数的参数列表
private static <T, A, R> BiFunction<A, T, R> flip(BiFunction<T, A, R> func) {
return (a, t) -> func.apply(t, a);
}
/** 科里化 */
@Test
public void testCurryPrepareCopy() {
// 复制数组的函数
BiFunction<int[], Integer, int[]> baseFunc = Arrays::copyOf;
// 固定数组为[1,2,3,4,5], 从数组中复制前n个元素的函数
var copyFormArray = prepare(baseFunc, new int[] {1, 2, 3, 4, 5});
assert Arrays.equals(copyFormArray.apply(3), new int[] {1, 2, 3});
assert Arrays.equals(copyFormArray.apply(2), new int[] {1, 2});
// 从数组中复制前3个元素的函数
var copyTop3 = prepare(flip(baseFunc), 3);
assert Arrays.equals(copyTop3.apply(new int[] {1, 2, 3, 4, 5}), new int[] {1, 2, 3});
assert Arrays.equals(copyTop3.apply(new int[] {1, 2, 4, 5}), new int[] {1, 2, 4});
}
/** 科里化 */
@Test
public void testCurryAdd() {
// x, y -> x + y
@SuppressWarnings("Convert2MethodRef")
BinaryOperator<Integer> add = (x, y) -> x + y;
// x -> y -> x + y
Function<Integer, Function<Integer, Integer>> curryAdd = x -> y -> x + y;
assert Objects.equals(curryAdd.apply(1).apply(2), add.apply(1, 2));
}
@Test
public void testStrLen() {
assert strlen0(1234) == strlen1(1234);
assert strlen0("1234") == strlen1("1234");
}
private int strlen0(Object obj) {
return Optional.ofNullable(obj)
.filter(String.class::isInstance)
.map(String.class::cast)
.map(String::length)
.orElse(0);
}
private int strlen1(Object obj) {
if (obj instanceof String str) {
return str.length();
}
return 0;
}
private static <T, A, R> Function<? super T, ? extends R> pipe(
Function<? super T, ? extends A> function1, Function<? super A, ? extends R> function2) {
return function1.andThen(function2);
}
@Test
public void testFuncCompose() {
// 组合数字转字符串和乘以2的函数
var pipe = Tests.<String, Integer, Integer>pipe(Integer::parseInt, x -> x * 2);
assert pipe.apply("1") == 2;
assert pipe.apply("2") == Integer.parseInt("2") * 2;
}
@Test
public void testListFilter() {
var list = List.of("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
var filtered = listFilter(list);
var funcFiltered = listFilterFunc().apply(list);
assert Arrays.equals(filtered, funcFiltered);
assert Arrays.equals(filtered, new int[] {2, 4, 6, 8, 10});
}
private int[] listFilter(List<String> list) {
return list.stream().mapToInt(Integer::parseInt).map(x -> x * 2).filter(x -> x <= 10).toArray();
}
/** 函数的组合 通过构造从集合转换为数组的函数, 实现对应操作. */
private Function<? super Collection<String>, int[]> listFilterFunc() {
// String -> Integer
Function<String, Integer> parseInt = Integer::parseInt;
// String -> Integer
ToIntFunction<String> toIntFunction = pipe(parseInt, (x) -> x * 2)::apply;
// (String -> Integer, Stream<String>) -> IntStream
var mapToInt = Tests.<Stream<String>, ToIntFunction<String>, IntStream>flip(Stream::mapToInt);
// (Stream<String>, IntStream) -> IntStream
var stringStreamToIntStreamFunction = prepare(mapToInt, toIntFunction);
// (Integer -> Boolean, IntStream, IntStream) -> IntStream
var intStreamFilterFunc = flip(IntStream::filter);
// (IntStream, IntStream) -> IntStream
var intStreamFilter = prepare(intStreamFilterFunc, (x) -> x <= 10);
// (Collection<String>, Stream<String>) -> IntStream
Function<Collection<String>, Stream<String>> function = Collection::stream;
return function
// Collection<String> -> IntStream
.andThen(stringStreamToIntStreamFunction)
// IntStream -> IntStream
.andThen(intStreamFilter)
// IntStream -> int[]
.andThen(IntStream::toArray);
}
}

浙公网安备 33010602011771号