private synchronized void initIfNeeded() {
      if (recommendedSubFamily == null) {
        recommendedPlainSubFamilies = new HashMap<>();
        recommendedBoldSubFamilies = new HashMap<>();
        italics = new LinkedHashMap<>();
        OurWeightMap nonItalicsByWeight = new OurWeightMap();
        OurWeightMap italicsByWeight = new OurWeightMap();
        for (Map.Entry<String, Font> e : members.entrySet()) {
          String subFamily = e.getKey();
          Font font = e.getValue();
          int weight = getWeight(font);
          boolean isItalic = isItalic(subFamily);
          if (VERBOSE_LOGGING) {
            LOG.info(family + "(" + subFamily + "): weight=" + weight + (isItalic ? ", italic" : ""));
          }
          (isItalic ? italicsByWeight : nonItalicsByWeight).putValue(weight, subFamily);
        }
        OurWeightMap baseSet = nonItalicsByWeight.isEmpty() ? italicsByWeight : nonItalicsByWeight;

        final class Candidate {
          final int desiredWeight;
          String bestSubFamily;
          int bestDistance = Integer.MAX_VALUE;

          private Candidate(String defaultSubFamily, int desiredWeight) {
            bestSubFamily = defaultSubFamily;
            this.desiredWeight = desiredWeight;
          }

          private void updateIfBetterMatch(int weight, String subFamily) {
            int newMetric = Math.abs(desiredWeight - weight);
            if (newMetric < bestDistance) {
              bestDistance = newMetric;
              bestSubFamily = subFamily;
            }
          }
        }

        Candidate preferred = new Candidate(null, PREFERRED_MAIN_WEIGHT);
        Map<String, Candidate> candidates = new HashMap<>();
        baseSet.forEach((weight, subFamily) -> {
          preferred.updateIfBetterMatch(weight, subFamily);

          String italicSubFamily = null;
          if (baseSet == italicsByWeight) {
            italicSubFamily = subFamily;
          }
          else {
            Collection<String> italicSubFamilyCandidates = italicsByWeight.get(weight);
            for (String italicCandidate : italicSubFamilyCandidates) {
              if (italicSubFamily == null || isMatchingItalic(subFamily, italicCandidate)) {
                italicSubFamily = italicCandidate;
              }
            }
          }
          italics.put(subFamily, italicSubFamily == null ? members.get(subFamily).deriveFont(SYNTHETIC_ITALICS_TRANSFORM)
                                                         : members.get(italicSubFamily));

          candidates.forEach((original, candidate) -> candidate.updateIfBetterMatch(weight, subFamily));
          candidates.put(subFamily, new Candidate(subFamily, weight + PREFERRED_BOLD_WEIGHT_DIFF));
        });
        recommendedSubFamily = preferred.bestSubFamily;
        candidates.forEach((original, boldCandidate) -> recommendedBoldSubFamilies.put(original, boldCandidate.bestSubFamily));

        candidates.clear();
        baseSet.forEachDescending((weight, subFamily) -> {
          candidates.forEach((original, candidate) -> candidate.updateIfBetterMatch(weight, subFamily));
          candidates.put(subFamily, new Candidate(subFamily, weight - PREFERRED_BOLD_WEIGHT_DIFF));
        });
        candidates.forEach((original, plainCandidate) -> recommendedPlainSubFamilies.put(original, plainCandidate.bestSubFamily));
      }
    }
private synchronized void initIfNeeded()