我需要对一些文本数据进行大量不同的预处理,预处理由几个简单的正则表达式函数组成,这些函数都写在类 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);
有没有更好的方法可以解决这个问题?
答案 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
函数,并在循环中依次应用它们。