是否有任何Map的Java实现,哪些键是Regex模式。这种数据结构有可能吗? 找到了几个手工制作的解决方案,如https://wiki.apache.org/jakarta/RegexpKeyedMap,但我想要一个经过良好测试的库。
作为客户,我想要这个
map.put('^RESOURCE.*', () -> { /* some action*/});
map.put('USER|ACCOUNT', () -> { /* do action*/}};
map.put('PRODUCT', () -> { /* do action */}};
例如。
String entityType = 'RESOURCE_TYPE_1';
.....
Supplier<MyBatisMapper> action = mapers.get(entityType)
MyBatisMapper mapper = action.get();
mapper.update(entity);
它将用作静态配置。因此删除功能并不重要。
EDITED
目前我们的项目中有几个大型交换机,任务使条件更复杂。喜欢(伪代码):
switch (type) {
case 'USER' || 'ACCOUNT' : doAction();
case startsWith('RESOURCE'): doAnotherAction();
...
/* another 10-15 cases */
}
我怀疑什么是最佳方法。有几个想法,但没有一个看起来很好:
我在groovy中解决了这个问题非常容易,
def configuration = [
[matcher: { it.startsWith('RESOURCE' }, action: { /* */}],
[matcher: { it == 'USER' || it == 'ACCOUNT' }, action: { /* */}]
]
...
def result = configuration.find({ it.matcher(type)}).action();
但对于Java来说,这样的解决方案太脏了(由于类型转换)。
答案 0 :(得分:1)
Map
有一个相当复杂的合同,很难(或不可能)正确地遵循您描述的数据结构。例如,实现.entrySet()
没有任何有意义的方法,因为有无限的有效密钥。此外,这个&#34; map&#34;的行为并不真正符合Map
的概念目的,因为查找很昂贵(可能 O(nk),其中 k 是复杂的图案)。
我建议避免实施Map
,而是定义一个专门的类,它只支持您需要的行为。这可能类似于:
/**
* Associates a series of regular expressions with values, allowing the values
* to be looked up by strings that match a pattern.
*
* Note this is a linear-time operation, and that patterns are checked in
* insertion order.
*/
public class RegexLookup<V> {
// Pattern doesn't override .equals()/.hashCode(), so it can't be the map key
// use a LinkedHashMap to ensure ordered search
private final LinkedHashMap<String, Pattern> patterns = new HashMap<>();
private final HashMap<String, V> values = new HashMap<>();
/** Associates a regular expression with a value */
public void putPattern(String regex, V value) {
putPattern(Pattern.compile(regex), regex);
}
/** Associates a regular expression with a value */
public void putPattern(Pattern pattern, V value) {
patterns.put(pattern.pattern(), pattern);
values.put(pattern.pattern(), value);
}
/**
* Looks for a pattern matching the given string, and returns the associated
* value. If not match is found, returns {@link Optional#absent}.
*/
public Optional<V> find(String string) {
for (Entry<String, Pattern> e : patterns.entrySet()) {
if (e.getValue().matcher(string).matches()) {
return Optional.of(values.get(e.getKey()));
}
}
return Optional.absent();
}
/** Returns a read-only view of the underlying pattern:value mapping. */
public Map<String, V> asPatternMap() {
return Collections.unmodifiableMap(values);
}
}
组合而不是遗产有许多好处。除了不需要实现完整的Map
合同外,我们还可以为我们的方法提供更清晰的名称和更好的签名。 .find()
清楚地传达了我们正在进行可能代价高昂的搜索,与.get()
不同,这通常意味着速度很快。
您的示例最终会看起来像这样(您可能希望标准functional interface作为V
类型,但这取决于您的需求):
RegexLookup<...> configuration = new RegexLookup();
configuration.putPattern('^RESOURCE.*', () -> { /* some action*/});
configuration.putPattern('USER|ACCOUNT', () -> { /* do action*/}};
configuration.putPattern('PRODUCT', () -> { /* do action */}};
然后您可以使用以下命令检索操作:
Optional<...> action = configuration.find(someString);
对此实现进行了一些可能的改进,可能允许我们做得比 O(nk)更好,例如构建联合({{1}模式和基本上进行二进制搜索,但进行额外的正则表达式搜索的开销可能不值得(复杂性变为 O(log(n)* k ^ 2),我认为,所以我绝对想要比上述实现更复杂的基准测试。