Статьи

Скала: назовите меня по имени, пожалуйста?

В Java, когда фреймворки, такие как log4J, становились популярными в архитектурах Java, было обычным явлением видеть такой код:

1
2
3
4
if (logger.isEnabledFor(Logger.INFO)) {
   // Ok to log now.
   logger.info('ok' + 'to' + 'concatenate'  + 'string' + 'to' + 'log' + 'message');
}

Перед выполнением любой конкатенации строк считалось, что рекомендуется всегда проверять, включено ли ведение журнала на соответствующем уровне. Я даже помню, как десять лет назад работал над проектом (инструмент настройки радиосети 3G для Ericsson), в котором объединение строк для ведения журнала фактически привело к заметному снижению производительности.

С тех пор JVM были оптимизированы, и закон Мура продолжился, так что конкатенация строк не так беспокоит, как раньше. Многие фреймворки (например, Hibernate ), если вы проверите исходный код, вы увидите код регистрации, где нет проверки, чтобы увидеть, включено ли ведение журнала и происходит ли объединение строк независимо. Однако давайте представим, что конкатенация — это проблема производительности. Что мы действительно хотели бы сделать, так это убрать необходимость в операторах if , чтобы остановить раздувание кода. Суть проблемы в том, что в Java, когда вы вызываете метод с параметрами, все значения параметров вычисляются до вызова метода. Вот почему заявление if необходимо.

1
2
simpleComputation(expensiveComputation());// In Java, the expensive computation is called first.
logger.log(Level.INFO, 'Log this ' + message);// In Java, the String concatenation happens first

Scala предоставляет механизм, с помощью которого вы можете отложить оценку параметров. Это называется по имени .

1
def log(level: Level, message: => String) = if (logger.level.intValue >= level.intValue) logger.log(level, msg)

=> Перед типом String означает, что параметр String не оценивается до вызова функции журнала. Вместо этого есть проверка, чтобы подтвердить, что значение уровня регистратора находится в соответствующем значении, и если так, то строка будет затем оценена. Эта проверка происходит внутри функции log поэтому нет необходимости ставить проверку перед каждым ее вызовом. Что насчет повторного использования кода?

Что-нибудь еще?

Да, когда используется передача по имени, параметр, который передается по имени, оценивается не один раз, а каждый раз, когда на него ссылаются в функции, которой он передается. Давайте посмотрим на другой пример

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
scala> def nanoTime() = {
     |   println(">>nanoTime()")
     |   System.nanoTime // returns nanoTime
     | }
nanoTime: ()Long
  
scala> def printTime(time: => Long) = {    // => indicates a by name parameter
     |   println(">> printTime()")
     |   println("time= " + time)
     |   println("second time=" + time)
     |   println("third time=" + time)
     | }
printTime: (time: => Long)Unit
  
  
scala> printTime(nanoTime())
  
>> printTime()
>>nanoTime()
time= 518263321668117
>>nanoTime()
second time=518263324003767
>>nanoTime()
third time=518263324624587

В этом примере мы видим, что nanoTime () выполняется не один раз, а каждый раз, когда на него ссылаются в функции printTime , printTime она передается. Это означает, что она выполняется три раза в этой функции, и, следовательно, мы получаем три разных раза. «До следующего раза, береги себя.

Ссылка: Scala: назовите меня по имени, пожалуйста? от нашего партнера JCG Алекса Стейвли в блоге Techlin в Дублине .