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);
  }

}
posted @ 2023-06-01 12:03  无以铭川  阅读(51)  评论(0)    收藏  举报