Введение
В этом разделе рассматривается, как использовать код 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