First, it looks like all the examples in this
thread are using combinations, not permutations. Using different permutations of the same combination would be a very bad idea, I think - very confusing, and leading to way too many method overloads.
I agree with Stephan's approach. Use a limited number of overloads and a very consistent order, so there's no confusion.
I would (almost) never advocate using varargs of a more general type to handle different argument orders. With default arguments you usually want the different types of the argument to make it obvious which overload is being called - you don't want people switching the order around and still getting a valid vararg call. That's very confusing.
Why would you want optional arguments in the first place? Well, to avoid needing to spell out every parameter in cases where it's usually not needed. A good example is something like Collectors.joining(), where you most always want to specify the delimiter you're joining with, but often don't want or need to specify a prefix and suffix. So you can have things like
The last would be better in a language with named parameter invocation, e.g. Kotlin's
This is a case where a little more verbosity really helps readability, I think. The later parameters in a method with defaults are usually the ones that aren't used as much, so people may not remember what they are. It's nice to be able to spell those out if you want to.