Короткий ответ: безопасно, если вы используете их безопасно :)
Язвительный ответ: скажите мне, что вы имеете в виду под чертами характера, и, может быть, я дам вам лучший ответ :)
Если серьезно, то термин «черта» не имеет четкого определения. Многие Java-разработчики больше всего знакомы с чертами, выраженными в Scala, но Scala - далеко не первый язык, имеющий черты, как по названию, так и по сути.
Например, в Scala трейты сохраняют состояние (могут иметь var
переменные); в Fortress это чистое поведение. Интерфейсы Java с методами по умолчанию не имеют состояния; Значит ли это, что они не черты характера? (Подсказка: это был вопрос с подвохом.)
Опять же, в Scala трейты составляются посредством линеаризации; если класс A
расширяет черты X
и Y
, то порядок , в котором X
и Y
смешиваются в определяет , как конфликты между X
иY
решены. В Java этого механизма линеаризации нет (он был отклонен отчасти потому, что он был слишком "не-Java-подобным").
Непосредственной причиной добавления методов по умолчанию к интерфейсам была поддержка эволюции интерфейса , но мы прекрасно понимали, что идем дальше этого. Считаете ли вы это «эволюцией интерфейса ++» или «чертами--» - это вопрос личного толкования. Итак, чтобы ответить на ваш вопрос о безопасности ... до тех пор, пока вы придерживаетесь того, что механизм фактически поддерживает, вместо того, чтобы пытаться желательно растянуть его до чего-то, что он не поддерживает, все должно быть в порядке.
Ключевой целью дизайна было то, что с точки зрения клиента интерфейса методы по умолчанию должны быть неотличимы от «обычных» методов интерфейса. Таким образом, значение метода по умолчанию интересно только разработчику и разработчику интерфейса.
Вот несколько вариантов использования, которые соответствуют целям дизайна:
Эволюция интерфейса. Здесь мы добавляем новый метод к существующему интерфейсу, который имеет разумную реализацию по умолчанию с точки зрения существующих методов в этом интерфейсе. Примером может быть добавление forEach
метода в Collection
, где реализация по умолчанию написана в терминах iterator()
метода.
«Необязательные» методы. Здесь разработчик интерфейса говорит: «Разработчикам не нужно реализовывать этот метод, если они хотят жить с ограничениями функциональности, которые влекут за собой». Например, Iterator.remove
было дано значение по умолчанию, которое выбрасывает UnsupportedOperationException
; поскольку подавляющее большинство реализаций в Iterator
любом случае имеют такое поведение, значение по умолчанию делает этот метод необязательным. (Если поведение from AbstractCollection
было выражено как значение по умолчанию Collection
, мы могли бы сделать то же самое для изменяющих методов.)
Методы удобства. Это методы, которые используются строго для удобства, опять же, как правило, реализуются в терминах методов класса, отличных от стандартных. logger()
Метод в первом примере является разумной иллюстрацией.
Комбинаторы. Это композиционные методы, которые создают новые экземпляры интерфейса на основе текущего экземпляра. Например, методы Predicate.and()
или Comparator.thenComparing()
являются примерами комбинаторов.
Если вы предоставляете реализацию по умолчанию, вы также должны предоставить некоторую спецификацию для нее (в JDK мы используем @implSpec
для этого тег javadoc), чтобы помочь разработчикам понять, хотят они переопределить метод или нет. Некоторые значения по умолчанию, такие как удобные методы и комбинаторы, почти никогда не отменяются; другие, например необязательные методы, часто переопределяются. Вам необходимо предоставить достаточную спецификацию (а не только документацию) о том, что обещает сделать стандарт по умолчанию, чтобы разработчик мог принять разумное решение о том, нужно ли им его переопределить.