Search code examples
javajava-8java-stream

Use Java Stream features - if multiple statements to be executed within the loop


How to Use Java Stream features - if multiple statements to be executed within the loop: The code snippet:

PDAcroForm pdAcroForm = pdfDocument.getDocumentCatalog().getAcroForm();
JSONObject jsonData = new JSONObject(pdfdata);

String[] specialChars = {" ", "-", ".", "(", ")", "/", "*"};
String[] specialCharsReplaceWith = {"_", "_1_", "_2_", "_3_", "_4_", "_5_", "_6_"};

for (PDField pdField : pdAcroForm.getFields()) {
    
    String fieldName = pdField.getFullyQualifiedName();
    System.out.println("fieldName:" + fieldName);

    for(int i = 0; i < specialChars.length; i++) {
        fieldName = fieldName.trim().replace(specialChars[i], specialCharsReplaceWith[i]);
    }

    if(StringUtils.isNotEmpty(fieldName)) {
        fieldName = fieldName.substring(0, 1).toLowerCase().concat(fieldName.substring(1));
    }

    if (jsonData.has(fieldName)) {
        String value = jsonData.getString(fieldName);
        pdField.setValue(value);
        pdField.setReadOnly(true);
    }
}

any suggestions?


Solution

  • Yes, since you need both the PDFField and the resulting json field name in the end, a Stream does not seem appropriate. I would make it look something like

    pdAcroForm.getFields().forEach(pdField -> {
     Optional.of(jsonFieldMapper.getFieldName(pdField))
       .filter(jsonData::has)
       .map(jsonData::getString)
       .ifPresent(jsonValue -> {
         pdField.setValue(jsonValue);
         pdField.setReadOnly(true);
       });
    });
    

    and extract the whole replacement and substringing into the jsonFieldMapper.

    EDIT: I just realized that your question is just as much about "the whole replacement", so how can we make that into a Stream?

    Each of the individual replacements are a Function<String, String>, and we can fold them into a single one using a Stream by

    Stream<Function<String, String>> replacements = Stream.of(
      s -> s.replace(" ", "_"),
      s -> s.replace("-", "_1_")
      //, ...
    );
    Function<String, String> replaceAll = replacements.reduce(UnaryOperator.identity(), (r1, r2) -> r1.andThen(r2));
    

    which you could then use as String replaced = replaceAll.apply(pdField.getFullyQualifiedName()).

    I'd argue it's not more readable than just going with a for loop:

    String fieldName = pdField.getFullyQualifiedName();
    for (Replacement r : List.of(
     replacement(" ", "_"),
     replacement("-", "-1"),...) {
     fieldName = r.apply(fieldName);
    }
    // with
    UnaryOperator<String> replacement(String replace, String with) {
     String replaceIn -> replaceIn.replace(with);
    }
    

    Side Note: I'd guess you need a replaceAll though.