Cleaning a list of data in Java8

If modifying the list in-place is allowed, you could use

public <T> List<T> cleanData(List<T> data, List<Function<T, T>> cleanOps) {
    cleanOps.stream().reduce(Function::andThen).ifPresent(f -> data.replaceAll(f::apply));
    return data;
}

andThen combines two Function instances and if at least one function was present, i.e. the cleanOps list is not empty, the resulting combined function will be applied to all list elements and the elements replaced by the result, using replaceAll.

Unfortunately, replaceAll requires a UnaryOperator<T> rather than a Function<T,T>, despite being functionally equivalent, so we have to use the adapter f::apply.

Since these function types are equivalent, we could change the list to List<UnaryOperator<T>>, but then, we have to face the fact that there is no specialized andThen implementation for UnaryOperator, so we would need:

public <T> List<T> cleanData(List<T> data, List<UnaryOperator<T>> cleanOps) {
    cleanOps.stream()
        .reduce((f1,f2) -> t -> f2.apply(f1.apply(t)))
        .ifPresent(data::replaceAll);
    return data;
}

The caller’s source changes to

List<UnaryOperator<String>> cleanOps = new ArrayList<>();
cleanOps.add(String::toLowerCase);
cleanOps.add(str -> str.replaceAll(" ", ""));
List<String> data = new ArrayList<>();
data.add("John Doe");
data.add("Jane Doe");
System.out.println(cleanData(data, cleanOps));

then.

As a side note, there is no need for a construct like

System.out.println(Arrays.toString(cleanData(data, cleanOps).toArray()));

as the toString() method of a List produces exactly the same output. Since the println(Object) method calls toString() implicitly, you can just use

System.out.println(cleanData(data, cleanOps));

It looks like you need to use List.replaceAll(), which replaces each element of this list with the result of applying the given operator to that element.

public <T> List<T> cleanString(List<T> data, List<Function<T, T>> cleanOps) {
    data.replaceAll(str -> {
        T cleanData = str;
        for (Function<T,T> function : cleanOps) {
            cleanData = function.apply(cleanData);
        }
        return cleanData;
    });
    return data;
}

I'd rename the method, though, since it's generic, so it doesn't necessarily process a List of Strings.