Java 枚举的逻辑运算
Logical operations on Java enums
我有一个项目,在不同的场景中,我必须处理大型数据集的不同子集。按照我编写代码的方式,有一个 Collector
接口和一个 class DataCollector implements Collector
。 class DataCollector
使用 子集创建条件 实例化,这些条件是枚举。
假设数据集是一组 100 万个英语单词,我想处理由奇数个字母组成的单词子集。然后,我执行以下操作:
DataCollector dataCollector = new DataCollector(CollectionType.WORDS_OF_ODD_LENGTH);
Set<String> fourLetteredWords = dataCollector.collect();
其中 CollectionType
是枚举 class
enum CollectionType {
WORDS_OF_ODD_LENGTH,
WORDS_OF_EVEN_LENGTH,
STARTING_WITH_VOWEL,
STARTING_WITH_CONSONANT,
....
}
数据收集器根据实例化的枚举调用 java.util.Predicate
。
到目前为止,这种方法已经足够健壮和灵活了,但现在我面临着越来越复杂的场景(例如,收集以元音开头的偶数长度的单词)。我想避免为每个这样的场景添加新的 CollectionType
。我注意到,许多这些复杂的场景只是对更简单场景的逻辑操作(例如,condition_1 && (condition_2 || condition_3)
)。
最终用户是指定这些条件的人,我唯一的控制权是我可以指定一组这样的条件。如同,最终用户只能从 CollectionType
select。现在,我正试图从 select 只有一种条件的能力概括为 select 一种或多种条件的能力。为此,我需要像
这样的东西
DataCollector dataCollector = new DataCollector(WORDS_OF_ODD_LENGTH &&
STARTING_WITH_VOWEL);
有没有一种方法可以对我的枚举进行建模来执行此类操作?我对其他想法持开放态度(例如,我是否应该放弃这种基于枚举的方法以换取其他东西等)。
我建议你使用 Java 8,它有谓词和支持谓词的操作。
enum CollectionType implements Predicate<String> {
WORDS_OF_ODD_LENGTH(s -> s.length() % 2 != 0),
WORDS_OF_EVEN_LENGTH(WORDS_OF_ODD_LENGTH.negate()),
STARTING_WITH_VOWEL(s -> isVowel(s.charAt(0))),
STARTING_WITH_CONSONANT(STARTING_WITH_VOWEL.negate()),
COMPLEX_CHECK(CollectionType::complexCheck);
private final Predicate<String> predicate;
CollectionType(Predicate<String> predicate) {
this.predicate = predicate;
}
static boolean isVowel(char c) {
return "AEIOUaeiou".indexOf(c) >= 0;
}
public boolean test(String s) {
return predicate.test(s);
}
public static boolean complexCheck(String s) {
// many lines of code, calling many methods
}
}
你可以像这样写一个谓词
Predicate<String> p = WORDS_OF_ODD_LENGTH.and(STARTING_WITH_CONSONANT);
甚至以元音开头的五个字母单词
Predicate<String> p = STARTING_WITH_VOWEL.and(s -> s.length() == 5);
假设您想在读取文件时使用此过滤器,您可以这样做
List<String> oddWords = Files.lines(path).filter(WORDS_OF_ODD_LENGTH).collect(toList());
或者您可以在加载它们时将它们编入索引
Map<Integer, List<String>> wordsBySize = Files.lines(path)
.collect(groupBy(s -> s.length()));
即使您已将枚举设为谓词,您也可以像这样优化它的使用。
if (predicate == WORDS_OF_ODD_LENGTH || predicate == WORDS_OF_EVEN_LENGTH) {
// assume if the first word in a list of words of the same length
// then take all words of that length.
return wordsBySize.values().stream()
.filter(l -> predicate.test(l.get(0)))
.flatMap(l -> l.stream()).collect(toList());
} else {
return wordsBySize.values().stream()
.flatMap(l -> l.stream())
.filter(predicate)
.collect(toList());
}
即通过使用 enum
您可以识别一些谓词并针对它们进行优化。 (这是否是个好主意,我会留给你)
我有一个项目,在不同的场景中,我必须处理大型数据集的不同子集。按照我编写代码的方式,有一个 Collector
接口和一个 class DataCollector implements Collector
。 class DataCollector
使用 子集创建条件 实例化,这些条件是枚举。
假设数据集是一组 100 万个英语单词,我想处理由奇数个字母组成的单词子集。然后,我执行以下操作:
DataCollector dataCollector = new DataCollector(CollectionType.WORDS_OF_ODD_LENGTH);
Set<String> fourLetteredWords = dataCollector.collect();
其中 CollectionType
是枚举 class
enum CollectionType {
WORDS_OF_ODD_LENGTH,
WORDS_OF_EVEN_LENGTH,
STARTING_WITH_VOWEL,
STARTING_WITH_CONSONANT,
....
}
数据收集器根据实例化的枚举调用 java.util.Predicate
。
到目前为止,这种方法已经足够健壮和灵活了,但现在我面临着越来越复杂的场景(例如,收集以元音开头的偶数长度的单词)。我想避免为每个这样的场景添加新的 CollectionType
。我注意到,许多这些复杂的场景只是对更简单场景的逻辑操作(例如,condition_1 && (condition_2 || condition_3)
)。
最终用户是指定这些条件的人,我唯一的控制权是我可以指定一组这样的条件。如同,最终用户只能从 CollectionType
select。现在,我正试图从 select 只有一种条件的能力概括为 select 一种或多种条件的能力。为此,我需要像
DataCollector dataCollector = new DataCollector(WORDS_OF_ODD_LENGTH &&
STARTING_WITH_VOWEL);
有没有一种方法可以对我的枚举进行建模来执行此类操作?我对其他想法持开放态度(例如,我是否应该放弃这种基于枚举的方法以换取其他东西等)。
我建议你使用 Java 8,它有谓词和支持谓词的操作。
enum CollectionType implements Predicate<String> {
WORDS_OF_ODD_LENGTH(s -> s.length() % 2 != 0),
WORDS_OF_EVEN_LENGTH(WORDS_OF_ODD_LENGTH.negate()),
STARTING_WITH_VOWEL(s -> isVowel(s.charAt(0))),
STARTING_WITH_CONSONANT(STARTING_WITH_VOWEL.negate()),
COMPLEX_CHECK(CollectionType::complexCheck);
private final Predicate<String> predicate;
CollectionType(Predicate<String> predicate) {
this.predicate = predicate;
}
static boolean isVowel(char c) {
return "AEIOUaeiou".indexOf(c) >= 0;
}
public boolean test(String s) {
return predicate.test(s);
}
public static boolean complexCheck(String s) {
// many lines of code, calling many methods
}
}
你可以像这样写一个谓词
Predicate<String> p = WORDS_OF_ODD_LENGTH.and(STARTING_WITH_CONSONANT);
甚至以元音开头的五个字母单词
Predicate<String> p = STARTING_WITH_VOWEL.and(s -> s.length() == 5);
假设您想在读取文件时使用此过滤器,您可以这样做
List<String> oddWords = Files.lines(path).filter(WORDS_OF_ODD_LENGTH).collect(toList());
或者您可以在加载它们时将它们编入索引
Map<Integer, List<String>> wordsBySize = Files.lines(path)
.collect(groupBy(s -> s.length()));
即使您已将枚举设为谓词,您也可以像这样优化它的使用。
if (predicate == WORDS_OF_ODD_LENGTH || predicate == WORDS_OF_EVEN_LENGTH) {
// assume if the first word in a list of words of the same length
// then take all words of that length.
return wordsBySize.values().stream()
.filter(l -> predicate.test(l.get(0)))
.flatMap(l -> l.stream()).collect(toList());
} else {
return wordsBySize.values().stream()
.flatMap(l -> l.stream())
.filter(predicate)
.collect(toList());
}
即通过使用 enum
您可以识别一些谓词并针对它们进行优化。 (这是否是个好主意,我会留给你)