Введение
В этом разделе рассматривается, как использовать код Java в Scala и, наоборот, как использовать код Scala в Java.
В целом, использование Java-кода в Scala довольно простое. Есть лишь несколько моментов, когда может появиться желание использовать утилиты Scala для преобразования концепций Java в Scala, в том числе:
- Классы коллекций Java
- Java класс
Optional
Аналогично, если вы пишете код Java и хотите использовать концепции Scala,
вам потребуется преобразовать коллекции Scala и Scala класс Option
.
В следующих разделах демонстрируются наиболее распространенные преобразования, которые вам могут понадобиться:
- Как использовать коллекции Java в Scala
- Как использовать Java
Optional
в Scala - Расширение Java интерфейсов в Scala
- Как использовать коллекции Scala в Java
- Как использовать Scala
Option
в Java - Как использовать трейты Scala в Java
- Как обрабатывать методы Scala, которые вызывают исключения в коде Java
- Как использовать vararg-параметры Scala в Java
- Создание альтернативных имен для использования методов Scala в Java
Обратите внимание: примеры Java в этом разделе предполагают, что вы используете Java 11 или более позднюю версию.
Как использовать коллекции Java в Scala
Когда вы пишете код на Scala, а API либо требует, либо создает класс коллекции Java (из пакета java.util
),
тогда допустимо напрямую использовать или создавать коллекцию, как в Java.
Однако для идиоматического использования в Scala, например, для циклов for
по коллекции
или для применения функций высшего порядка, таких как map
и filter
,
вы можете создать прокси, который будет вести себя как коллекция Scala.
Вот пример того, как это работает.
Учитывая следующий API, который возвращает java.util.List[String]
:
public interface Foo {
static java.util.List<String> getStrings() {
return List.of("a", "b", "c");
}
}
Вы можете преобразовать этот Java список в Scala Seq
,
используя утилиты преобразования из Scala объекта scala.jdk.CollectionConverters
:
import scala.jdk.CollectionConverters._
import scala.collection.mutable
def testList() = {
println("Using a Java List in Scala")
val javaList: java.util.List[String] = Foo.getStrings()
val scalaSeq: mutable.Seq[String] = javaList.asScala
for (s <- scalaSeq) println(s)
}
import scala.jdk.CollectionConverters.*
import scala.collection.mutable
def testList() =
println("Using a Java List in Scala")
val javaList: java.util.List[String] = Foo.getStrings()
val scalaSeq: mutable.Seq[String] = javaList.asScala
for s <- scalaSeq do println(s)
В приведенном выше коде создается оболочка javaList.asScala
,
которая адаптирует java.util.List
к коллекции Scala mutable.Seq
.
Как использовать Java Optional
в Scala
Когда вы взаимодействуете с API, который использует класс java.util.Optional
в коде Scala,
его можно создавать и использовать, как в Java.
Однако для идиоматического использования в Scala, например использования в for
,
вы можете преобразовать его в Scala Option
.
Чтобы продемонстрировать это, вот Java API, который возвращает значение типа Optional[String]
:
public interface Bar {
static java.util.Optional<String> optionalString() {
return Optional.of("hello");
}
}
Сначала импортируйте всё из объекта scala.jdk.OptionConverters
,
а затем используйте метод toScala
для преобразования Optional
значения в Scala Option
:
import java.util.Optional
import scala.jdk.OptionConverters._
val javaOptString: Optional[String] = Bar.optionalString
val scalaOptString: Option[String] = javaOptString.toScala
import java.util.Optional
import scala.jdk.OptionConverters.*
val javaOptString: Optional[String] = Bar.optionalString
val scalaOptString: Option[String] = javaOptString.toScala
Расширение Java интерфейсов в Scala
Если вам нужно использовать Java интерфейсы в коде Scala, расширяйте их так, как если бы они были трейтами Scala. Например, учитывая эти три Java интерфейса:
public interface Animal {
void speak();
}
public interface Wagging {
void wag();
}
public interface Running {
// an implemented method
default void run() {
System.out.println("I’m running");
}
}
вы можете создать класс Dog
в Scala так же, как если бы вы использовали трейты.
Поскольку у run
есть реализация по умолчанию, вам нужно реализовать только методы speak
и wag
:
class Dog extends Animal with Wagging with Running {
def speak = println("Woof")
def wag = println("Tail is wagging")
}
def useJavaInterfaceInScala = {
val d = new Dog()
d.speak
d.wag
d.run
}
class Dog extends Animal, Wagging, Running:
def speak = println("Woof")
def wag = println("Tail is wagging")
def useJavaInterfaceInScala =
val d = Dog()
d.speak
d.wag
d.run
Также обратите внимание, что в Scala методы Java, определенные с пустыми списками параметров,
можно вызывать либо так же, как в Java, .wag()
,
либо вы можете отказаться от использования круглых скобок .wag
.
Как использовать коллекции Scala в Java
Если вам нужно использовать класс коллекции Scala в своем Java-коде,
используйте методы Scala объекта scala.jdk.javaapi.CollectionConverters
в своем Java-коде,
для корректной работы конверсии.
Например, предположим, что Scala API возвращает List[String]
, как следующем примере:
object Baz {
val strings: List[String] = List("a", "b", "c")
}
object Baz:
val strings: List[String] = List("a", "b", "c")
Вы можете получить доступ к Scala List
в Java-коде следующим образом:
import scala.jdk.javaapi.CollectionConverters;
// получить доступ к методу `strings` с помощью `Baz.strings()`
scala.collection.immutable.List<String> xs = Baz.strings();
java.util.List<String> listOfStrings = CollectionConverters.asJava(xs);
for (String s: listOfStrings) {
System.out.println(s);
}
Этот код можно сократить, но показаны полные шаги, чтобы продемонстрировать, как работает процесс.
Обязательно обратите внимание, что хотя Baz
имеет поле с именем strings
,
в Java оно отображается как метод, поэтому его следует вызывать в круглых скобках .strings()
.
Как использовать Scala Option
в Java
Если вам нужно использовать Scala Option
в коде Java,
вы можете преобразовать значение Option
в значение Java Optional
,
используя метод toJava
объекта Scala scala.jdk.javaapi.OptionConverters
.
Например, предположим, что Scala API возвращает Option[String]
, как следующем примере:
object Qux {
val optString: Option[String] = Option("hello")
}
object Qux:
val optString: Option[String] = Option("hello")
Затем вы можете получить доступ к Scala Option
в своем Java-коде следующим образом:
import java.util.Optional;
import scala.Option;
import scala.jdk.javaapi.OptionConverters;
Option<String> scalaOptString = Qux.optString();
Optional<String> javaOptString = OptionConverters.toJava(scalaOptString);
Этот код можно сократить, но показаны полные шаги, чтобы продемонстрировать, как работает процесс.
Обязательно обратите внимание, что хотя Qux
имеет поле с именем optString
,
в Java оно отображается как метод, поэтому его следует вызывать в круглых скобках .optString()
.
Как использовать трейты Scala в Java
Начиная с Java 8, вы можете использовать трейт Scala точно так же, как Java интерфейс, даже если этот трейт реализует методы. Например, учитывая эти два трейта Scala, один с реализованным методом, а другой только с интерфейсом:
trait ScalaAddTrait {
def sum(x: Int, y: Int) = x + y // реализован
}
trait ScalaMultiplyTrait {
def multiply(x: Int, y: Int): Int // абстрактный
}
trait ScalaAddTrait:
def sum(x: Int, y: Int) = x + y // реализован
trait ScalaMultiplyTrait:
def multiply(x: Int, y: Int): Int // абстрактный
Класс Java может реализовать оба этих интерфейса и определить метод multiply
:
class JavaMath implements ScalaAddTrait, ScalaMultiplyTrait {
public int multiply(int a, int b) {
return a * b;
}
}
JavaMath jm = new JavaMath();
System.out.println(jm.sum(3,4)); // 7
System.out.println(jm.multiply(3,4)); // 12
Как обрабатывать методы Scala, которые вызывают исключения в коде Java
Когда вы пишете код на Scala, используя идиомы программирования Scala,
вы никогда не напишете метод, который генерирует исключение.
Но если по какой-то причине у вас есть метод Scala, который генерирует исключение,
и вы хотите, чтобы разработчики Java могли использовать этот метод,
добавьте аннотацию @throws
к вашему методу Scala,
чтобы Java потребители знали, какие исключения он может генерировать.
Например, следующий Scala метод exceptionThrower
аннотирован, чтобы объявить, что он выдает Exception
:
object SExceptionThrower {
@throws[Exception]
def exceptionThrower =
throw new Exception("Idiomatic Scala methods don’t throw exceptions")
}
object SExceptionThrower:
@throws[Exception]
def exceptionThrower =
throw Exception("Idiomatic Scala methods don’t throw exceptions")
В результате вам придется обрабатывать исключение в своем Java-коде. Например, этот код не скомпилируется из-за необработанного исключения:
// не скомпилируется, потому что исключение не обработано
public class ScalaExceptionsInJava {
public static void main(String[] args) {
SExceptionThrower.exceptionThrower();
}
}
Компилятор выдает следующую ошибку:
[error] ScalaExceptionsInJava: unreported exception java.lang.Exception;
must be caught or declared to be thrown
[error] SExceptionThrower.exceptionThrower()
Хорошо — это то, что вы хотите: аннотация сообщает компилятору Java, что exceptionThrower
может выдать исключение.
Теперь, когда вы пишете код на Java, вы должны обрабатывать исключение с помощью блока try
или объявлять, что ваш Java метод генерирует исключение.
И наоборот, если вы укажите аннотацию Scala метода exceptionThrower
, код Java будет скомпилирован.
Вероятно, это не то, что вам нужно, поскольку Java код может не учитывать метод Scala, выдающий исключение.
Как использовать vararg-параметры Scala в Java
Если метод Scala имеет неопределенное количество параметров и вы хотите использовать этот метод в Java,
отметьте Scala метод аннотацией @varargs
.
Например, метод printAll
в этом Scala классе объявляет vararg-поле String*
:
import scala.annotation.varargs
object VarargsPrinter {
@varargs def printAll(args: String*): Unit = args.foreach(println)
}
import scala.annotation.varargs
object VarargsPrinter:
@varargs def printAll(args: String*): Unit = args.foreach(println)
Поскольку printAll
объявлен с аннотацией @varargs
, его можно вызвать из Java программы
с переменным количеством параметров, как показано в этом примере:
public class JVarargs {
public static void main(String[] args) {
VarargsPrinter.printAll("Hello", "world");
}
}
Запуск кода приводит к следующему выводу:
Hello
world
Создание альтернативных имен для использования методов Scala в Java
В Scala вы можете создать имя метода, используя символический знак:
def +(a: Int, b: Int) = a + b
Такое имя метода корректно работать в Java не будет,
но в Scala вы можете предоставить “альтернативное” имя метода с аннотацией targetName
,
которая будет именем метода при использовании из Java:
import scala.annotation.targetName
object Adder {
@targetName("add") def +(a: Int, b: Int) = a + b
}
import scala.annotation.targetName
object Adder:
@targetName("add") def +(a: Int, b: Int) = a + b
Теперь в вашем Java-коде вы можете использовать псевдоним метода add
:
int x = Adder.add(1,1);
System.out.printf("x = %d\n", x);
Contributors to this page:
Contents
- Введение
- Возможности Scala
- Почему Scala 3?
- Почувствуй Scala
- Пример 'Hello, World!'
- REPL
- Переменные и типы данных
- Структуры управления
- Моделирование данных
- Методы
- Функции первого класса
- Одноэлементные объекты
- Коллекции
- Контекстные абстракции
- Верхнеуровневые определения
- Обзор
- Первый взгляд на типы
- Интерполяция строк
- Структуры управления
- Моделирование предметной области
- Инструменты
- Моделирование ООП
- Моделирование ФП
- Методы
- Особенности методов
- Main методы в Scala 3
- Обзор
- Функции
- Анонимные функции
- Параметры функции
- Eta расширение
- Функции высшего порядка
- Собственный map
- Создание метода, возвращающего функцию
- Обзор
- Пакеты и импорт
- Коллекции в Scala
- Типы коллекций
- Методы в коллекциях
- Обзор
- Функциональное программирование
- Что такое функциональное программирование?
- Неизменяемые значения
- Чистые функции
- Функции — это значения
- Функциональная обработка ошибок
- Обзор
- Типы и система типов
- Определение типов
- Параметризованные типы
- Пересечение типов
- Объединение типов
- Алгебраические типы данных
- Вариантность
- Непрозрачные типы
- Структурные типы
- Зависимые типы функций
- Другие типы
- Контекстные абстракции
- Методы расширения
- Параметры контекста
- Контекстные границы
- Given импорты
- Классы типов
- Многостороннее равенство
- Неявное преобразование типов
- Обзор
- Параллелизм
- Scala утилиты
- Сборка и тестирование проектов Scala с помощью Sbt
- Рабочие листы
- Взаимодействие с Java