在 Scala 中创建 Java 枚举

2022-09-02 23:07:11

我的工作场所一直在尝试从Java迁移到Scala来完成一些任务,它适用于我们正在做的事情。但是,某些预先存在的日志记录方法期望 .日志记录方法在 (Java) 基类中定义,子类可以定义自己的枚举,记录器将在多个线程/计算机中的所有实例中跟踪这些枚举。java.lang.Enum

它在Java中的工作方式如下:

public class JavaSubClass extends JavaBaseClass {
    enum Counters {
        BAD_THING,
        GOOD_THING
    }

    public void someDistributedTask() {
        // some work here
        if(terribleThing) {
            loggingMethod(Counters.BAD_THING)
        } else {
            loggingMethod(Counters.GOOD_THING)
            // more work here
        }
    }
}

然后,当任务完成时,我们可以看到

BAD_THING: 230
GOOD_THING: 10345

有没有办法在Scala中复制这一点,无论是通过创建Java还是从转换为?我尝试过直接扩展,但它似乎是密封的,因为我在控制台中收到错误:EnumEnumerationEnumEnum

error: constructor Enum in class Enum cannot be accessed in object $iw
Access to protected constructor Enum not permitted because
enclosing object $iw is not a subclass of 
class Enum in package lang where target is defined

答案 1

Java Enums

对于枚举类来说,名称比 - 每个枚举值表示一个单数计数器更好。CounterCounters

当javac编译一个类时,它:enum

  1. 编译为包含枚举的所有构造函数,方法,其他成员(如果有)的普通java类(例如)Counter
  2. 每个值 (, ) 都成为 (1) 的字段 - 类等于 (1) () 中的类:enumGOOD_THINGBAD_THINGpublic staticCounter

    // Java Code:
    class Counter {
        public static Counter GOOD_THING;
        public static Counter BAD_THING;
    
        // constructors, methods, fields as defined in the enum ...
    
    }
    
  3. 类中的初始化逻辑自动将每个值构造为单例对象enum

Scala Options

A. 引用来自 Scala 的 Java Enum

导入计数器,参考GOOD_THING和BAD_THING就像在java中一样,并且(如果您愿意)另外调用Enum类方法:

// Scala Code:
import JavaSubClass.Counter;

def someDistributedTask = {
    // some work here
    if (terribleThing) {
        loggingMethod(Counter.BAD_THING)
    } else {
        loggingMethod(Counter.GOOD_THING)
        // more work here
    }
}

// Other things you can do:
val GoodThing = Counter.valueOf("GOOD_THING")

Counter.values() foreach { // do something }

counter match {
  case Counter.GOOD_THING => "Hoorah"
  case Counter.BAD_THING => "Pfft"
  case _ => throw new RuntimeException("someone added a new value?")
}

优点:可以做java枚举所做的一切,并支持模式匹配。Disadvanges:因为基本特征不是,所以不会对任何执行模式匹配的代码进行类型检查,以确保涵盖详尽的情况。sealed

B. 使用 Scala 枚举

将java转换为等效的scala:enumEnumeration

// Scala Code:
object Counter extends Enumeration {
  type Counter = Value
  val GoodThing = Value("GoodThing") 
  val BadThing = Value("BadThing")
}

使用它:

// Scala Code:
import someScalaPackage.Counter;

def someDistributedTask = {
    // some work here
    if (terribleThing) {
        loggingMethod(Counter.BadThing)
    } else {
        loggingMethod(Counter.GoodThing)
        // more work here
    }
}

// Other things you can do:
val GoodThing = Counter.withName("GoodThing")
val label = Counter.BadThing.toString

Counter.values foreach { // do something }

myCounter match {
  case Counter.GOOD_THING => "Bully!"
  case Counter.BAD_THING => "Meh"
  case _ => throw new RuntimeException("someone added a new value?")
}

优点:Scala的方法和Java一样丰富,而且支持模式匹配。Disadvanges:不能做java所做的一切 - java enum被定义为一个具有任意构造函数,方法和允许的其他成员的类(即enum基型上的完整OO建模)。因为基本特征不是,所以任何进行模式匹配的代码都不会被类型化检查,以确保涵盖详尽的情况。EnumerationEnumenumsealed

C. 使用 Scala 案例类:

可以将 s 直接转换为案例对象(即单例对象,而不是案例类,它不是单例):enum

sealed trait Counter
object Counter {
  case object GoodThing extends Counter;
  case object BadThing extends Counter; 
}

使用它:

// Scala Code:
import someScalaPackage.Counter;

def someDistributedTask = {
    // some work here
    if (terribleThing) {
        loggingMethod(Counter.BadThing)
    } else {
        loggingMethod(Counter.GoodThing)
        // more work here
    }
}

// Other things you can do:
// NO!!   val GoodThing = Counter.withName("GoodThing")
val label = Counter.BadThing.toString

// NO!!   Counter.values foreach { // do something }

myCounter match {
  case Counter.GOOD_THING => "Bully!"
  case Counter.BAD_THING => "Meh"
  case _ => throw new RuntimeException("someone added a new value?")
}
  • 与枚举相比的优势:每个值可以具有不同的祖先或不同的 mixin 特征(只要每个值都符合类型计数器)。可以对性状计数器和每个值进行复杂的 OO 建模。然后可以使用每个不同值的所有不同案例对象参数进行任意复杂的模式匹配。通过具有基本特征,任何进行模式匹配的代码都会被类型化检查,以确保涵盖详尽的情况。(对您的要求没有用)。sealed
  • 枚举的缺点:不要“免费”获得枚举方法(即值,withName,应用程序)。可以通过将自定义实现添加到基类计数器来“修复”(有点麻烦,因为它是手动编码...)。

答案 2

如果你需要一个java枚举,那么你需要用Java编写它。在 Scala 中,您可以做一些事情来替换 的用例,但是在 Scala 中没有任何东西可以复制 Java 机制。EnumEnum