Получение карты Scala из свойств Java

Я пытался вставить переменные среды в scala-скрипт, используя java-итераторы и/или перечисления, и понял, что доктор Франкенштейн может претендовать на отцовство, поэтому вместо этого я взломал следующее из уродливого дерева:

import java.util.Map.Entry
import System._

val propSet = getProperties().entrySet().toArray()
val props   = (0 until propSet.size).foldLeft(Map[String, String]()){(m, i) =>
  val e = propSet(i).asInstanceOf[Entry[String, String]]
  m + (e.getKey() -> e.getValue())
}

Например, чтобы распечатать указанную ту же среду

props.keySet.toList.sortWith(_ < _).foreach{k =>
  println(k+(" " * (30 - k.length))+" = "+props(k))
}

Пожалуйста, не принимайтесь за полировку этого t$#d, просто покажите мне драгоценный камень scala, который, как я уверен, существует для этой ситуации (т.е. свойства java -> scala.Map), заранее спасибо ;@)


person Don Mackenzie    schedule 06.01.2010    source источник
comment
Нет, Ruby слишком крут для меня, думаю, это была копия C++ Gems Стэна Липпмана на полке, которая привлекла мое внимание.   -  person Don Mackenzie    schedule 07.01.2010


Ответы (6)


Скала 2.7:

val props = Map() ++ scala.collection.jcl.Conversions.convertMap(System.getProperties).elements

Хотя это требует некоторого приведения типов. Позвольте мне еще немного поработать над этим.

val props = Map() ++ scala.collection.jcl.Conversions.convertMap(System.getProperties).elements.asInstanceOf[Iterator[(String, String)]]

Хорошо, это было легко. Позвольте мне работать над 2.8 сейчас ...

import scala.collection.JavaConversions.asMap
val props = System.getProperties() : scala.collection.mutable.Map[AnyRef, AnyRef] // or
val props = System.getProperties().asInstanceOf[java.util.Map[String, String]] : scala.collection.mutable.Map[String, String] // way too many repetitions of types
val props = asMap(System.getProperties().asInstanceOf[java.util.Map[String, String]])

Многословие, конечно, можно уменьшить парой импортов. Прежде всего, обратите внимание, что Map будет изменяемой картой в версии 2.8. С другой стороны, если вы конвертируете карту обратно, вы получите исходный объект.

Теперь я понятия не имею, почему Properties реализует Map<Object, Object>, учитывая, что в javadocs четко указано, что ключ и значение равны String, но вот так. Необходимость приведения типов делает неявный вариант гораздо менее привлекательным. В этом случае альтернатива является наиболее лаконичной из них.

ИЗМЕНИТЬ

Scala 2.8 только что получила неявное преобразование из Properties в mutable.Map[String,String], что делает большую часть этого кода спорным.

person Daniel C. Sobral    schedule 06.01.2010
comment
Кстати, это первый раз, когда я делаю преобразование коллекций Java ‹-› Scala. В прошлый раз, когда я пытался, у меня не было достаточно опыта, чтобы заставить его работать. И я не только получил шанс преодолеть свое предыдущее поражение, но и нахожу эту конкретную проблему очень интересной, так как я время от времени просматриваю свойства системы! - person Daniel C. Sobral; 07.01.2010
comment
Спасибо, Даниил, я рассмотрю твой ответ позже. Я рад, что спровоцировал ваш интерес к этой теме. - person Don Mackenzie; 07.01.2010
comment
@Daniel, я подозреваю, что это та жемчужина, которую я искал, просто стыдно за состав, тем более что свойства должны реализовывать Map[String, String]. Эти конверсии - большая находка для меня. - person Don Mackenzie; 07.01.2010
comment
Просто для ясности: приведение — это реализация ошибки свойств в Java, а не в Scala. - person Daniel C. Sobral; 07.01.2010
comment
Даниэль, хаотический добрый эльф-маг, побеждает старого, грубого, злодейского зверя, созданного Java Properties. Извините, но ваш первый комментарий напомнил мне РПГ... - person Travis Schneeberger; 08.01.2010
comment
Нет проблем, но я скорее законно-хороший гном-боец, хоть и выгляжу как эльф. :-) - person Daniel C. Sobral; 08.01.2010
comment
Этот ответ устарел (к сожалению, как и в Scala) - person iwein; 19.01.2012

Скала 2.10.3

import scala.collection.JavaConverters._

//Create a variable to store the properties in
val props = new Properties

//Open a file stream to read the file
val fileStream = new FileInputStream(new File(fileName))
props.load(fileStream)
fileStream.close()

//Print the contents of the properties file as a map
println(props.asScala.toMap)
person Sarath    schedule 25.02.2014
comment
Привет Сарат. Спасибо за вклад в сайт. Мы предпочитаем, чтобы ответы на StackOverflow содержали немного больше объяснений, чем просто размещение кода. Попробуйте прочитать это руководство по публикации хороших ответов для получения дополнительной помощи :) - person starsplusplus; 25.02.2014

В Scala 2.9.1 это решается неявными преобразованиями внутри collection.JavaConversions._ . В других ответах используются устаревшие функции. Подробности задокументированы здесь. Это соответствующий фрагмент этой страницы:

scala> import collection.JavaConversions._  
import collection.JavaConversions._

scala> import collection.mutable._
import collection.mutable._
scala> val jul: java.util.List[Int] = ArrayBuffer(1, 2, 3)
jul: java.util.List[Int] = [1, 2, 3]
scala> val buf: Seq[Int] = jul
buf: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 3)
scala> val m: java.util.Map[String, Int] = HashMap("abc" -> 1, "hello" -> 2)
m: java.util.Map[String,Int] = {hello=2, abc=1} 

Чтобы перейти от изменяемой карты к неизменяемой карте, нужно вызвать для нее метод toMap.

person iwein    schedule 19.01.2012
comment
Спасибо за обновление, Даниэль внес правку в свой ответ, в которой упоминаются эти имплициты. По иронии судьбы доступ к окружению в scala 2.10 будет еще более простым, просто используйте неизменяемую карту, возвращаемую методом sys.env. - person Don Mackenzie; 21.01.2012
comment
Только что понял, что это было преобразование свойств в карту Scala, о которой я просил, однако в Scala 2.10 также есть метод sys.props для доступа к системным свойствам. - person Don Mackenzie; 21.01.2012
comment
Редактирование в ответе Дэниела касается Scala 2.8, и оно снова изменилось в 2.9... Я знаю, что это сбивает с толку. - person iwein; 28.04.2012

В Scala 2.8.1 вы можете сделать это с помощью asScalaMap(m : java.util.Map[A, B]) более лаконичным способом:

var props = asScalaMap(System.getProperties())

props.keySet.toList.sortWith(_ < _).foreach { k =>
  println(k + (" " * (30 - k.length)) + " = " + props(k))
}
person Vitalii Fedorenko    schedule 02.02.2011
comment
Спасибо, Виталий, я взглянул на asScalaMap, а также есть версия asScalaMap, которая позволяет неявное преобразование из экземпляра свойств Java в изменяемую карту Scala [String, String]. - person Don Mackenzie; 05.02.2011

В Скала 2.13.2:

import scala.jdk.javaapi.CollectionConverters._

val props = asScala(System.getProperties)
person Ava    schedule 16.06.2020

Похоже, что в самой последней версии Scala (2.10.2 на момент написания этого ответа) предпочтительным способом сделать это является использование явного .asScala из scala.collection.JavaConverters:

import scala.collection.JavaConverters._

val props = System.getProperties().asScala

assert(props.isInstanceOf[Map[String, String]])
person Erik Kaplun    schedule 10.09.2013
comment
Это лучший ответ ИМО. Спасибо. - person Jabba; 24.02.2018