Home > Back-end >  How to pass an Arbitrary number of Parameterized Functions into constructor without compiler Warning
How to pass an Arbitrary number of Parameterized Functions into constructor without compiler Warning

Time:04-16

I have a Test class and a Writer class.

The Writer class does nothing but writes a string to a StringBuilder, nothing more. It also is allowed to have "transformers". Meaning, in the constructor of the Writer class, you can pass any number of lambda functions to add additional processing to a string you are writing.

For example, like String::toLowerCase.

I want to be able to pass multiple of these "transformers" into the constructor of the writer.

I have the below code:

///Writer Class   Writer(Function<String, String>... someFunctions) {
abstract class Writer {
  Function<String, String>[] functions;

  Writer(Function<String, String>... someFunctions) {
    functions = someFunctions;
  }

}

///Test Class
    @Test
    default void WriterTestWriteThere() throws IOException {
        Writer writer = createWriter();
        writer.write("There");
        writer.close();

        assertEquals("There", getContents());
    }

    @Test
    default void WriterTestTwoTransformerFunctions() throws IOException {
        Writer writer = createWriter(
                text -> text.replaceAll("sometext", "s*****"),
                String::toUpperCase
        );
        writer.write("This is somethext!");
        writer.close();

        assertEquals("THIS IS S*****!", getContents());
    }

However, the compiler issues multiple warnings.

Possible heap pollution from parameterized vararg type - error-message for the constructor of the Writer class.

Unchecked generics array creation for varargs parameter - error-message for the Test class when the Writer instance is being created.

I cannot use @SafeVarargs or @SuppressWarnings

I have looked everywhere online, but cannot get a solid answer as to why these warnings are created, other than that the Java compiler does not like parameterized arguments being passed into a list. So, raises my question.

What can I use to fix it?

I need to be able to pass multiple functions into the writer class to transform the text as those functions want, and have no warnings. I have experimented with other Java utility classes other than Function, but I can't seem to find what I need.

CodePudding user response:

I cannot use @SafeVarargs or @SuppressWarnings

As you probably know, arrays and generics don't play well together.

Arrays are covariant, i.e. method specifies Number[] - you can pass as an argument Integer[], Double[], BigInteger[], etc.

Generics are invariant, i.e. if the declared parameter is a List<Number> - you can pass only List<Number>.

When you are passing an argument into the method that expects varargs they will be wrapped by an array. Therefore, the compiler isn't able to inure type-safety when you're mixing varargs and generics, and it warns you about possible heap pollution since it's impossible to verify whether the type of arguments will match.

You have to eliminate the need to create a generic array.

The best option is to combine all functions into a single one before passing into a constructor of Writer.

Function<String, String> f1 = String::toUpperCase;
Function<String, String> f2 = text -> text.replaceAll("somethext", "s*****");
Function<String, String> f3 = text -> text.replaceAll("\\p{Punct}", "&");

Function<String, String> combined = f1.andThen(f2).andThen(f3);

And Writer should have a field of type Function<String, String> but not, an array of functions.

public class Writer {
    private Function<String, String> function;

    public Writer(Function<String, String> function) {
        this.function = function;
    }
}
  • Related