1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Javaの新機能たちはScalaでコンパイルできるかの検証

Last updated at Posted at 2023-05-02

はじめに

Scalaを使用している方々はほぼ全てのコードをScalaで書くでしょう。
しかしBetter JavaとしてScalaを使っている人には、時にJavaのライブラリの制約によってJavaをScalaのプロジェクトに入れなければならない場合があります。
そのような場合に、Javaの最近導入された機能たちがScala環境でコンパイルできるかを検証します。

この記事は2023/05/02時点での内容です。

compileOrderの話はしません。JavaもScalaも相互に参照している前提です。
片方への参照がない場合はJavaThenScalaScalaThenJavaの適切な方を設定すれば正しくコンパイルされます。
この記事ではcompileOrder := CompileOrder.Mixedの設定です。

環境

Java

$ java --version
openjdk 17.0.7 2023-04-18
OpenJDK Runtime Environment Temurin-17.0.7+7 (build 17.0.7+7)
OpenJDK 64-Bit Server VM Temurin-17.0.7+7 (build 17.0.7+7, mixed mode)

SBT

$ sbt --version
sbt version in this project: 1.8.2
sbt script version: 1.8.2

Scala

  • 2.13.10
  • 3.2.2

対象の機能

  • var
  • private method in interface
  • Pattern Matching for instanceof
  • Records
  • Sealed Classes
  • Switch Expressions
  • Text Blocks

各機能の詳細は省きます。

参考

コード

private method in interface
public interface HasPrivate {
    default double pow(Position position) {
        return Math.pow(position.x(), this.internalParameter());
    }

    private double internalParameter() {
        return 3d;
    }

    static void main(String[] args) {
        var hasPrivate = new HasPrivate() {
        };
        System.out.println(hasPrivate.pow(new Position(2, 2)));
    }
}
Pattern Matching for instanceof
import java.time.LocalTime;
import java.util.List;
import java.util.Map;

public class PatternMatch {
    public static void main(String[] args) {
        var something = returnSomething(LocalTime.now());
        if (something instanceof String s) {
            System.out.println("String! " + s);
        } else if (something instanceof List<?>) {
            System.out.println("List" + something.getClass());
        } else if (something instanceof Map<?, ?> m && m.isEmpty()) {
            System.out.println("Empty map, " + m.getClass());
        } else if (something instanceof Position p) {
            System.out.println(p);
        } else {
            throw new IllegalStateException("What?");
        }
    }

    private static Object returnSomething(LocalTime time) {
        return switch (time.getNano() % 5) {
            case 0, 1 -> "a";
            case 2 -> List.of();
            case 3 -> Map.of();
            case 4 -> new Position(time.getHour(), time.getMinute());
            default -> throw new AssertionError("unreachable");
        };
    }
}
Records
public record RecordExample(Position pos) {
    public RecordExample {
        if (this.pos().x() < 0 || this.pos().y() < 0)
            throw new IllegalArgumentException("coordinate must be 0 or positive");
    }

    public RecordExample(int x, int y) {
        this(Position.apply(x, y));
    }

    public static void main(String[] args) {
        var pos = new RecordExample(0, 0);
        System.out.println(pos);
    }
}
Sealed Classes
public sealed class SealedExample {

    public static void main(String[] args) {
        var example = new SealedExample();
        System.out.println(example.getClass());
        System.out.println(new Child1().getClass());
        System.out.println(new Child2().getClass());
        System.out.println(example.new Child3().getClass());
    }

    public static final class Child1 extends SealedExample {
    }

    public static non-sealed class Child2 extends SealedExample {
    }

    non-sealed class Child3 extends SealedExample {
    }
}
Sealed Classes of Scala
sealed class ScalaSealedClass {
  class Child3 extends ScalaSealedClass
}

object ScalaSealedClass {
  final class Child1 extends ScalaSealedClass

  class Child2 extends ScalaSealedClass

  def main(args: Array[String]): Unit = {
    val example = new ScalaSealedClass
    val c1 = new Child1
    val c2 = new Child2
    val c3 = new example.Child3
    println(c1.getClass)
    println(c2.getClass)
    println(c3.getClass)
  }
}

Switch Expressions
import java.time.LocalDate;
import java.time.LocalTime;

public class SwitchExpression {
    public static void main(String[] args) {
        int a = switch (LocalTime.now().getSecond() % 3) {
            case 0 -> 4;
            case 1 -> {
                int min = LocalTime.now().getMinute();
                yield min + LocalTime.now().getSecond();
            }
            case 2 -> 2;
            default -> throw new AssertionError("unreachable");
        };
        System.out.println("Count: " + a);

        switch (LocalDate.now().getDayOfWeek()) {
            case SATURDAY, SUNDAY:
                System.out.println("Holiday!");
            case FRIDAY:
                System.out.println("Before holiday");
            default:
                System.out.println("Work");
        }
    }
}
Text Blocks
public class TextBlock {
    public static void main(String[] args) {
        System.out.println("""
            This is an example of multi line string.
            This file may be called from scala file.""");
    }
}

呼び出し元


case class Position(x: Int, y: Int)

object CompileCheckMain {

  def main(args: Array[String]): Unit = {
    // Compile error in 3.2.2
    println("-" * 10 + "RecordExample" + "-" * 10)
    RecordExample.main(args)
    println("-" * 10 + "HasPrivate" + "-" * 10)
    HasPrivate.main(args)
    println("-" * 10 + "PatternMatch" + "-" * 10)
    PatternMatch.main(args)
    // Compile error in both 2.13.10 and 3.2.2
    println("-" * 10 + "SealedExample" + "-" * 10)
    SealedExample.main(args)
    // Of course, scala sealed class can compile
    println("-" * 10 + "ScalaSealedClass" + "-" * 10)
    ScalaSealedClass.main(args)
    println("-" * 10 + "SwitchExpression" + "-" * 10)
    SwitchExpression.main(args)
    println("-" * 10 + "TextBlock" + "-" * 10)
    TextBlock.main(args)
  }
}

結果

実行結果

2.13.10

コンパイルできない部分(sealed class)はコード上でコメントアウトして実行しています。

----------RecordExample----------
RecordExample[pos=Position(0,0)]
----------HasPrivate----------
8.0
----------PatternMatch----------
Position(23,29)
----------ScalaSealedClass----------
class jp.co.yumemi.koma.ScalaSealedClass$Child1
class jp.co.yumemi.koma.ScalaSealedClass$Child2
class jp.co.yumemi.koma.ScalaSealedClass$Child3
----------SwitchExpression----------
Count: 2
Work
----------TextBlock----------
This is an example of multi line string.
This file may be called from scala file.

3.2.2

コンパイルできない部分(record, sealed class)はコード上でコメントアウトして実行しています。

----------HasPrivate----------
8.0
----------PatternMatch----------
Position(23,29)
----------ScalaSealedClass----------
class jp.co.yumemi.koma.ScalaSealedClass$Child1
class jp.co.yumemi.koma.ScalaSealedClass$Child2
class jp.co.yumemi.koma.ScalaSealedClass$Child3
----------SwitchExpression----------
Count: 2
Work
----------TextBlock----------
This is an example of multi line string.
This file may be called from scala file.

まとめ

Function 2.13.10 3.2.2
var
private method in interface
Pattern Matching for instanceof
Records
Sealed Classes
Switch Expressions
Text Blocks

Recordが3.2.2でサポートされておらず、JavaのSealed classは現状のバージョンではサポートされていませんでした。
Sealed classはInterfaceであっても同じ結果となります。

備考

動作確認のリポジトリ

2.13

3

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?