java - 在 Java 集合和类型转换中实现简单的类似函数式的范例

标签 java generics collections casting functional-programming

我最近开始在 Scala 中工作,这是我第一次真正接触函数式范例。尽管我是 Java 的忠实粉丝,并且我承认它有时缺乏函数范式。

这就是为什么我最近启动了一个小型宠物项目,看看在某种程度上是否可以用 Java 实现这样的事情。

我从对数组列表的简单修改开始,这就是我到目前为止所做的:

<小时/>

任何集合都需要实现的接口(interface),以便为其元素提供应用功能:

public interface Functionalizable<E> {
    public Collection<E> apply(Function<E> f);
}

定义在单个元素上应用函数的方法的接口(interface):

public interface Function<E> {
    public E apply(E e);
}

由数组列表支持的具体类,允许在其元素上应用函数:

public class FunctionArrayList<E> implements List<E>, Functionalizable<E> {
    private List<E> list;

    //implemented methods from `List` interface and ctors

    @Override
    public List<E> apply(Function<E> f) {

        List<E> applied = new FunctionArrayList<>(this.list.size());

        for (E e : this.list) {
            applied.add(f.apply(e));
        }

        return applied;
    }
}

我已经为 Integer 编写了一个小测试方法,它工作正常:

代码:

    List<Integer> listOfIntegersBefore = new FunctionArrayList<>();
    listOfIntegersBefore.add(-1);
    listOfIntegersBefore.add(0);
    listOfIntegersBefore.add(1);
    listOfIntegersBefore.add(2);
    listOfIntegersBefore.add(3);
    listOfIntegersBefore.add(4);

    System.out.println("Before<Integer>: " + listOfIntegersBefore.toString());

    List<Integer> listOfIntegersAfter = ((FunctionArrayList<Integer>) listOfIntegersBefore).apply(new Function<Integer>() {

        @Override
        public Integer apply(Integer e) {
            return (e + 1);
        }
    });

    System.out.println("After<Integer> : " + listOfIntegersAfter.toString());

输出:

Before<Integer>: [-1, 0, 1, 2, 3, 4]
After<Integer> : [0, 1, 2, 3, 4, 5]
<小时/>

但是,当我尝试使用 List 进行更复杂的操作时,我最终会遇到很多类型转换,这是我不喜欢的(并且我想尽可能避免它)。
代码:

    List<List<Integer>> listOfListOfIntegersBefore = new FunctionArrayList<>();

    List<Integer> temp = new FunctionArrayList<>();
    temp.add(1);
    listOfListOfIntegersBefore.add(temp);

    temp = new FunctionArrayList<>();
    temp.add(1);
    temp.add(2);
    listOfListOfIntegersBefore.add(temp);

    temp = new FunctionArrayList<>();
    temp.add(1);
    temp.add(2);
    temp.add(3);
    listOfListOfIntegersBefore.add(temp);

    temp = new FunctionArrayList<>();
    temp.add(1);
    temp.add(2);
    temp.add(3);
    temp.add(4);
    listOfListOfIntegersBefore.add(temp);

    List<List<Integer>> listOfListOfIntegersAfter = (List<List<Integer>>) ((Functionalizable<List<Integer>>) listOfListOfIntegersBefore).apply(new Function<List<Integer>>() {

        @Override
        public List<Integer> apply(List<Integer> e) {
            List<Integer> list = new FunctionArrayList<>(e);

            return ((FunctionArrayList<Integer>) list).apply(new Function<Integer>() {

                @Override
                public Integer apply(Integer e) {
                    return (e + 1);
                }
            });
        }
    });
    System.out.println("Before<List<Integer>>: " + listOfListOfIntegersBefore);
    System.out.println("After<List<Integer>> : " + listOfListOfIntegersAfter);

输出:

Before<List<Integer>>: [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]]
After<List<Integer>> : [[2], [2, 3], [2, 3, 4], [2, 3, 4, 5]]
<小时/>

正如我已经提到的,我想避免强制转换。另外,Eclipse 警告我关于 Type safety: Unchecked cast from List<List<Integer>> to Functionalizable<List<Integer>>在这一行:

List<List<Integer>> listOfListOfIntegersAfter = (List<List<Integer>>) ((Functionalizable<List<Integer>>) listOfListOfIntegersBefore).apply(new Function<List<Integer>>() {
    ...
}

有没有一种优雅的方式来实现这一点?

最佳答案

你让自己的生活变得艰难。

List<List<Integer>> listOfListOfIntegersBefore = new FunctionArrayList<>();
[...]
((FunctionArrayList<Integer>) listOfIntegersBefore).apply

为什么不首先将其存储为 FunctionArrayList 呢? 当然你必须这样转换。

无论如何,我发现将每个列表包装在功能列表中有点烦人,我宁愿使用简单的静态方法来做到这一点:

public interface F<S, T> { T apply(S s); }


public final class FunctionalStuff {
  private FunctionalStuff() {}


  public <S, T> static List<T> map(Collection<? extends S> collection,
                                   F<? super S, ? extends T> func) {
    final List<T> result = new ArrayList<T>(collection.size()); 
    for (S source : collection)
      result.add(func.apply(source)); 
    return result;
  }


  public <S, T> static List<S> filter(Collection<? extends S> collection,
                                      F<? super S, Boolean> predicate) {
    final List<T> result = new ArrayList<T>(collection.size()); 
    for (S source : collection)
      if (predicate.apply(source))
        result.add(source); 
    return result; 
  }

  // etc etc.
}

无论如何,请注意:我不建议您在 Java 中进行函数式编码。等待 Java 8 中添加的闭包。

或者使用包含函数式风格的语言:Scala、Javascript、Clojure、Lisp、Mathematica 等等,它们有很多!即使是 c(++) 在这方面似乎也没有 Java 那么烦人。

关于java - 在 Java 集合和类型转换中实现简单的类似函数式的范例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11484235/

相关文章:

Java:转换 ByteBuffer 多维数组

java - java中stream、collect、forEach组合的代码流程

generics - 尝试在父类的Dart中捕获错误

java - 如何解释这种看似不一致的 Java 可变参数行为?

python - 线程安全的有序集合

kotlin - 基于条件在 Kotlin 中创建列表

java - 为什么 Collections.sort 使用合并排序而不是快速排序?

java - 在没有巨大列表参数的情况下重写 Hibernate 查询

java - eclipse-microprofiles 配置抛出 No ConfigProviderResolver 实现被发现

Java 和泛型。 0不是数字吗?