Best way to record excluded results using the Stream API

I am wondering if there is a way to rewrite code like this

public static void main(String[] args) {
    final List<String> dataCollection = Collections.emptyList();
    final Set<String> someValues = new HashSet<>();
    final Iterator<String> iterator = dataCollection.iterator();
    while (iterator.hasNext()) {
        final String dataItem = iterator.next();
        // imagine some calculations
        String calculatedData = dataItem;
        if (!someValues.contains(calculatedData)) {
            logger.error("Skipped data {} because of ...#1", dataItem);
            iterator.remove();
            continue;
        }

        for (char element : dataItem.toCharArray()) {
            // imagine some other calculations
            if (element > 100) {
                logger.error("Skipped data {} because of ...#2", dataItem);
                iterator.remove();
                break;
            }
        }
    }
}

with the StreamAPI, so that the element excluded after filtering has been registered. peek () does not work in this case, because it either performs an action with each element before the filter, or after it with the rest of the elements.

So far I have managed to create it by registering in lambda, but it seems verbose, inconvenient and looks like a side effect. We can wrap it inside some method, but it will hide this code a little

public static void main(String[] args) {
    final List<String> dataCollection = Collections.emptyList();
    final Set<String> someValues = new HashSet<>();
    final Iterator<String> iterator = dataCollection.iterator();

    dataCollection.stream()
            .filter(byCondition1(someValues))
            .filter(byCondition2())
            .collect(Collectors.toList());
}

private static Predicate<String> byCondition1(Set<String> someValues) {
    return dataItem -> {
        final boolean remain = someValues.contains(dataItem);
        if (!remain) {
            logger.error("Skipped data {} because of ...#1", dataItem);
        }
        return remain;
    };
}

private static Predicate<String> byCondition2() {
    return dataItem -> {
        for (char element : dataItem.toCharArray()) {
            // imagine some other calculations
            if (element > 100) {
                logger.error("Skipped data {} because of element {}...#2", dataItem, element);
                return false;
            }
        }
        return true;
    };
}

I hope there is a better way.

+4
source share
2 answers

Assuming transmission is extraordinary, this may be feasible.

List<String> dataCollection = Arrays.asList("FOO", "hello", "VALID", "123", "BAR", "bla");
Set<String> someValues = new HashSet<>(Arrays.asList("FOO", "BAR"));

Predicate<String> firstPredicate  = string -> !someValues.contains(string);
Predicate<String> secondPredicate = string -> string.chars().noneMatch(c -> c>100);

List<String> result;

if(!logger.isLoggable(Level.WARNING)) {
    result = dataCollection.stream()
           .filter(firstPredicate)
           .filter(secondPredicate)
           .collect(Collectors.toList());
}
else {
    Map<Boolean, List<String>> map = dataCollection.stream()
        .collect(Collectors.partitioningBy(firstPredicate));
    if(!map.get(false).isEmpty())
        logger.log(Level.WARNING, "Skipped data {0} because of ...#1", map.get(false));
    map = map.get(true).stream()
        .collect(Collectors.partitioningBy(secondPredicate));
    if(!map.get(false).isEmpty())
        logger.log(Level.WARNING, "Skipped data {0} because of ...#2", map.get(false));
    result = map.get(true);
}

API java.util.logging - , , . , , , . , , ,

Sep 26, 2017 11:00:46 AM LoggingExample main
WARNUNG: Skipped data [FOO, BAR] because of ...#1
Sep 26, 2017 11:00:46 AM LoggingExample main
WARNUNG: Skipped data [hello, bla] because of ...#2

[VALID, 123], .

+3

, , OP . -, - :

final Predicate<String> loggingFilter = dataItem -> {
    final String calculatedData = dataItem; // imagine some calculations
    if (!someValues.contains(calculatedData)) {
        logger.error("Skipped data {} because of ...#1", dataItem);
        return false;
    }         
    final OptionalInt element = dataItem.chars().filter(ch -> ch > 100).findAny();
    if (element.isPresent()) {
        logger.error("Skipped data {} because of element {}...#2", dataItem, element.getAsInt());
        return false;
    }
    return true;
};

dataCollection.stream().filter(loggingFilter).collect(Collectors.toList());

, : ", " - . . , , , API , if(...); if(...).

+2

Source: https://habr.com/ru/post/1686388/


All Articles