public final This defineList(String key, List<?> values) {
        if (values.isEmpty()) {
            throw new IllegalArgumentException(
                    getClass().getSimpleName() + ".defineList was called with an empty list.");
        }
        // Uses stream match, cause the Java 9 ImmutableList implementation throws an NPE if asked `contains(null)`
        if (values.stream().anyMatch(Objects::isNull)) {
            throw new IllegalArgumentException(
                    getClass().getSimpleName() + ".defineList was called with a list containing null values.");
        }

        String value = values.stream()
                .map(Object::toString)
                .collect(joining(", "));

        return define(key, value);
    }
Define an attribute as the comma-separated {@link String} from the elements of the {@code values} argument.
<p>
Examples:
<pre>
List&lt;String&gt; columnNames = Arrays.asList("id", "name", "created_on");
List&lt;Object&gt; values = Arrays.asList(1, "Alice", LocalDate.now());
handle.createUpdate("insert into things (&lt;columnNames&gt;) values (&lt;values&gt;)")
    .defineList("columnNames", columnNames)
    .bindList("values", 1, values)
    .execute();

List&lt;String&gt; columnNames = Arrays.asList("id", "name", "created_on");
List&lt;Thing&gt; things = handle.createQuery("select &lt;columnNames&gt; from things")
    .bindList("columnNames", columnNames)
    .mapTo(Contact.class)
    .list();
</pre>

@param key    attribute name
@param values list of values that will be comma-spliced into the defined attribute value.
@return this
@throws IllegalArgumentException if the list is empty, or contains any null elements.
core/src/main/java/org/jdbi/v3/core/statement/SqlStatement.java