Java中的函数链

时间:2016-02-10 22:54:38

标签: java

我需要对一些文本数据进行大量不同的预处理,预处理由几个简单的正则表达式函数组成,这些函数都写在类 Filters 中,它们都接受一个String并返回格式化的String。到目前为止,在需要一些预处理的不同类中,我创建了一个新函数,其中我有一堆对 Filters 的调用,它们看起来像这样:

private static String filter(String text) {
    text = Filters.removeURL(text);
    text = Filters.removeEmoticons(text);
    text = Filters.removeRepeatedWhitespace(text);
    ....
    return text;
}

由于这是非常重复的(我会调用大约90%相同的函数,但每个类的2-3会有所不同),我想知道是否有更好的方法可以做到这一点,在Python中你可以举例如函数在一个列表中并迭代它,调用每个函数,我意识到这在Java中是不可能的,那么在Java中这样做的最佳方法是什么?

我在考虑为每个函数定义一个带有值的枚举,然后使用我想运行的函数调用带有枚举数组的过滤器中的主函数,如下所示:

enum Filter {
    REMOVE_URL, REMOVE_EMOTICONS, REMOVE_REPEATED_WHITESPACE
}


public static String filter(String text, Filter... filters) {
    for(Filter filter: filters) {
        switch (filter) {
            case REMOVE_URL:
                text = removeURL(text);
                break;

            case REMOVE_EMOTICONS:
                text = removeEmoticons(text);
                break;
        }
    }

    return text;
}

然后我可以简单地调用:

而不是定义顶部显示的函数
filter("some text", Filter.REMOVE_URL, Filter.REMOVE_EMOTICONS, Filter.REMOVE_REPEATED_WHITESPACE);

有没有更好的方法可以解决这个问题?

3 个答案:

答案 0 :(得分:3)

鉴于您已经实现了 if( map.get(customerId).size() ==0){ map.put( customerId, new ArrayList<Order>()); } map.get(customerId).add(order); } 实用程序类,您可以轻松定义过滤器函数列表

Filters

然后评估:

List<Function<String,String>> filterList = new ArrayList<>();
filterList.add(Filters::removeUrl);
filterList.add(Filters::removeRepeatedWhitespace);
...

这种变化,更容易处理:

定义

 String text = ...
 for (Function<String,String> f : filterList)
      text = f.apply(text);

然后使用

public static String filter(String text, Function<String,String>... filters) 
{
    for (Function<String,String> f : filters)
        text = f.apply(text);
    return text;
}

答案 1 :(得分:2)

你可以很容易地在Java 8中这样做,就像@tobias_k所说的那样,但即使没有它,你也可以这样做:

public class FunctionExample {

    public interface FilterFunction {
        String apply(String text);
    }

    public static class RemoveSpaces implements  FilterFunction {
        public String apply(String text) {
            return text.replaceAll("\\s+", "");
        }
    }

    public static class LowerCase implements  FilterFunction {
        public String apply(String text) {
            return text.toLowerCase();
        }
    }

    static String filter(String text, FilterFunction...filters) {
        for (FilterFunction fn : filters) {
            text = fn.apply(text);
        }
        return text;
    }

    static FilterFunction LOWERCASE_FILTER = new LowerCase();
    static FilterFunction REMOVE_SPACES_FILTER = new RemoveSpaces();


    public static void main(String[] args) {
        String s = "Some Text";

        System.out.println(filter(s, LOWERCASE_FILTER, REMOVE_SPACES_FILTER));
    }
}

答案 2 :(得分:2)

另一种方法是向enum Filter添加一个方法,并为每个枚举文字实现该方法。这也适用于早期版本的Java。这与您当前的代码最接近,并且具有定义数量的可能过滤器的效果。

enum Filter {
    TRIM {
        public String apply(String s) {
            return s.trim();
        }
    }, 
    UPPERCASE {
        public String apply(String s) {
            return s.toUpperCase();
        }
    };
    public abstract String apply(String s);
}

public static String applyAll(String s, Filter... filters) {
    for (Filter f : filters) {
        s = f.apply(s);
    }
    return s;
}

public static void main(String[] args) {
    String s = "   Hello World   ";
    System.out.println(applyAll(s, Filter.TRIM, Filter.UPPERCASE));
}

但是,如果您使用的是Java 8,则只需使用Function<String, String>列表即可使代码更加灵活。如果你不喜欢一直写Function<String, String>,你也可以定义自己的界面,扩展它:

interface Filter extends Function<String, String> {}

然后,您可以用不同的方式定义这些函数:使用方法引用,单行和多行lambda表达式,匿名类,或者从其他函数构造它们:

Filter TRIM = String::trim; // method reference
Filter UPPERCASE = s -> s.toUpperCase(); // one-line lambda
Filter DO_STUFF = (String s) -> { // multi-line lambda
    // do more complex stuff
    return s + s;
};
Filter MORE_STUFF = new Filter() { // anonymous inner class
    // in case you need internal state
    public String apply(String s) {
        // even more complex calculations
        return s.replace("foo", "bar");
    };
};
Function<String, String> TRIM_UPPER = TRIM.andThen(UPPERCASE); // chain functions

然后,您可以像枚举一样将它们传递给applyAll函数,并在循环中依次应用它们。