refactored to use StringJoiner