狐的传说
有时,如果爆炸式循环使代码更具可读性,则不一定是一件坏事。我建议您将代码保持原样,因为稍后您会看到,如果您尝试对其进行压缩,则很可能会遇到更糟糕的情况。如果您坚持要继续阅读。我的想法很简单:您实际上是在尝试遍历多个掩码以用于您的匹配模式。在这种情况下,掩码为“是否使用id或默认值”。不掩饰任何东西,如果没有匹配,遮罩c,如果没有匹配项,遮罩b,如果不匹配,屏蔽bc,如果没有匹配项,屏蔽abc,如果没有匹配项,返回空值。因此,我们可以使用某种数据结构来存储掩码,如下所示: // true = use id (don't mask); false = use default (mask). List<ImmutableTriple<Boolean, Boolean, Boolean>> matchMasks = new ArrayList<>(); matchMasks.add(new ImmutableTriple<>(true, true, true)); matchMasks.add(new ImmutableTriple<>(true, true, false)); matchMasks.add(new ImmutableTriple<>(true, false, true)); matchMasks.add(new ImmutableTriple<>(true, false, false)); matchMasks.add(new ImmutableTriple<>(false, false, false));当然,你可以使用List的List,Array的Array,或任何明智的存储这个面具。现在,我们可以使用循环来压缩您的代码:private Integer match(int a, int b, int c){ Integer value = null; // Loop through match rules. for (ImmutableTriple<Boolean, Boolean, Boolean> mask : matchMasks) { // Check whether to apply mask. int aId = mask.getLeft() ? a : 0; int bId = mask.getMiddle() ? b : 0; int cId = mask.getRight() ? c : 0; // Try to match cache. value = cache.get(new ImmutableTriple<>(aId, bId, cId)); // Stop if match found. if (value != null) break; } return value;}全部归为一类:public class Test{ private HashMap<ImmutableTriple<Integer, Integer, Integer>, Integer> cache = <your table here>; private List<ImmutableTriple<Boolean, Boolean, Boolean>> matchMasks = new ArrayList<>(); public Test() { // true = use id (don't mask); false = use default (mask). this.matchMasks.add(new ImmutableTriple<>(true, true, true)); this.matchMasks.add(new ImmutableTriple<>(true, true, false)); this.matchMasks.add(new ImmutableTriple<>(true, false, true)); this.matchMasks.add(new ImmutableTriple<>(true, false, false)); this.matchMasks.add(new ImmutableTriple<>(false, false, false)); } private Integer match(int a, int b, int c) { Integer value = null; // Loop through match rules. for (ImmutableTriple<Boolean, Boolean, Boolean> mask : this.matchMasks) { // Check whether to apply mask. int aId = mask.getLeft() ? a : 0; int bId = mask.getMiddle() ? b : 0; int cId = mask.getRight() ? c : 0; // Try to match cache. value = this.cache.get(new ImmutableTriple<>(aId, bId, cId)); // Stop if match found. if (value != null) break; } return value; }}PS对于此特定情况,由于0 =默认值,因此可以为掩码使用1和0而不是true和false int aId = mask.getLeft() * a;,但这很简单。如您所见,尽管我们确实将代码“压缩”成一个循环,但其效果还是值得商de的。实际上,我认为该代码实际上不那么可读。因此,有时候,坚持使用爆炸循环并不一定很糟糕。
牛魔王的故事
您可以使用默认值为三胞胎的所有可能状态创建“掩码映射”:private static List<Integer[]> mask = new ArrayList<>();static { mask.add(new Integer[] {null, null, null}); mask.add(new Integer[] {0, null, null}); mask.add(new Integer[] {null, 0, null}); mask.add(new Integer[] {null, null, 0}); mask.add(new Integer[] {null, 0, 0}); mask.add(new Integer[] {0, null, 0}); mask.add(new Integer[] {0, 0, null}); mask.add(new Integer[] {0, 0, 0});}假设为null,表示必须填充键值。然后,您可以从此掩码创建三元组键的列表:List<Triple<Integer, Integer, Integer>> triples = mask.stream() .map(row -> genrateTriple(row, a, b, c)) .collect(Collectors.toList());generateTriplets的代码: private Triple<Integer, Integer, Integer> genrateTriple(Integer[] row, int... values) { int[] tripleElems = new int[3]; for (int i = 0; i < row.length; i++) { tripleElems[i] = row[i] == null ? values[i] : row[i]; } return new ImmutableTriple<>(tripleElems[0], tripleElems[1], tripleElems[2]);}并在搜索中使用它:return triples.stream() .map(triple -> cache.get(triple)) .findFirst() .orElse(null);但是我不确定这是否比您的“代码气味”;)好。编辑:当然,如果您避免创建中间集合,这会更有效(findFirst是短循环运算符):Integer result = mask.stream() .map(row -> genrateTriple(row, a, b, c)) .map(cache::get) .findFirst() .orElse(null);