Любопытно, что вы используете Java HashSet
- в Scala нет addAll
- и в этом нет необходимости.
Итак, я собираюсь прокомментировать различные дизайнерские решения и то, как они отличаются от Java до Scala. Во-первых,
val pathKeys = HashSet[PathKey]()
Idiomatic Scala обычно не ссылается на класс, реализующий интерфейс, так как интерфейс имеет фабрику. Так что вы обычно просто используете Set[PathKey]()
. Кроме того, это, очевидно, фабрика Scala, поскольку здесь нет ключевого слова new
, что означает, что остальная часть кода не будет работать, поскольку в 1011 Scala Set
нет addAll
.
pathKeys.addAll(targetPath.getRequiredPathKeys)
Здесь вы не используете targetPath.getRequiredPathKeys
напрямую, поскольку Java Set
является изменяемым. Scala Set
по умолчанию является неизменным, что делает его бесполезным - вы можете просто использовать targetPath.getRequirePathKeys
в качестве базового набора, не добавляя его элементы в другую коллекцию.
С точки зрения производительности, Scala-подобные функциональные языки - используют постоянные структуры данных в своих реализациях неизменяемых коллекций. Это означает, что он повторно использует части одной структуры данных для создания производной структуры данных, а не копирует все каждый раз, когда вы создаете новую структуру данных. Это возможно только из-за гарантий неизменности.
В любом случае, вы можете просто сделать это:
val pathKeys = targetPath.getRequiredPathKeys
Далее
for (accessTemp <- accessPaths) {
pathKeys.addAll(accessTemp.getRequiredPathKeys)
}
Во-первых, идиоматическое использование для понимания должно возвращать значение, то есть для получения. Вышеупомянутое использование должно быть ограничено только побочными эффектами вашего кода. Чтобы быть более понятным, вышесказанное можно сделать в два этапа:
// Get all required Path Keys
val requiredPathKeys = for {
accessPath <- accessPaths
requiredPathKey <- accessPath.getRequiredPathKeys
} yield requiredPathKey
// Then add them
pathKeys.addAll(requiredPathKeys)
Однако, учитывая, что вы не addAll
вещи в Scala Set
, вам нужно либо сделать pathKeys
a var
, либо использовать изменяемую структуру данных, либо просто изменить порядок:
val requiredPathKeys = for {
accessPath <- accessPaths
requiredPathKey <- accessPath.getRequiredPathKeys
} yield requiredPathKey
val pathKeys = targetPath.getRequiredPathKeys ++ requiredPathKeys
Заметьте, однако, повторение getRequiredPathKeys
. Функциональные программисты ненавидят повторение. Иногда слишком, на мой взгляд, но в этом случае его легко удалить:
val pathKeys = for {
accessPath <- accessPaths + targetPath
requiredPathKey <- accessPath.getRequiredPathKeys
} yield requiredPathKey
Приведенный выше код предлагает еще одно улучшение. Если вы увидите этот вопрос о Scala для понимания, вы увидите, что вышеизложенное эквивалентно
val pathKeys = (accessPaths + targetPath).flatMap( accessPath =>
accessPath.getRequiredPathKeys.map( requiredPathKey => requiredPathKey ))
map
в конце избыточен, так как ничего не делает. Фактически, всякий раз, когда yield
возвращает просто простой идентификатор, в выражении появляется избыточный map
. Удаление этого дает нам:
val pathKeys = (accessPaths + targetPath).flatMap(accessPath =>
accessPath.getRequiredPathKeys)
Или, используя синтаксис параметров анонимной функции Scala,
val pathKeys = (accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
Наконец,
return pathKeys
Ключевое слово return
в Scala используется для обозначения исключения в рабочем процессе - точки, в которой выполнение метода прерывается вместо завершения до конца. Не то чтобы это не бесполезно, но, как и сами исключения, его нельзя использовать без причины. Здесь вы должны были использовать
pathKeys
Но на этом этапе ваш код стал просто двумя строками:
val pathKeys = (accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
pathKeys
Что делает назначение val
полностью избыточным. Таким образом, вы можете уменьшить его до:
(accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
Таким образом, метод становится
def getAllRequiredPathKeys: Set[PathKey] = {
(accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
}
Теперь, я знаю, я сказал "наконец" там, но есть еще один лакомый кусочек соглашения Scala, который нужно применить. Всякий раз, когда метод содержит одно выражение вместо нескольких операторов, соглашение заключается в том, чтобы опустить фигурные скобки. Другими словами, сделайте это:
def getAllRequiredPathKeys: Set[PathKey] =
(accessPaths + targetPath).flatMap(_.getRequiredPathKeys)
Или, если позволяет пространство, поместите все в одну строку. На самом деле, если вы удалите getAllRequiredPathKeys
тип, он будет хорошо вписываться. С другой стороны, явные типы возврата для открытого метода приветствуются.
Так что это даст вам неизменный Скала Set
. Допустим, ваш ввод и вывод должны быть в Java Set
. В этом случае я не вижу ничего, что можно было бы сделать, чтобы упростить ваш код, если только вы не захотели конвертировать между наборами Java и Scala. Вы можете сделать это так:
trait PathTemplate {
def getRequiredPathKeys:java.util.Set[PathKey]
}
import scala.collection.JavaConverters._
class MyClass(accessPaths:java.util.Set[PathTemplate], targetPath:PathTemplate){
def getAllRequiredPathKeys: java.util.Set[PathKey] =
(accessPaths.asScala + targetPath).flatMap(_.getRequiredPathKeys.asScala).asJava
}
Это, однако, использует Scala mutable Set
, что означает, что каждая операция, создающая новый Set
, будет копировать все содержимое старого Set
.