将枚举值与类字段匹配

时间:2020-01-16 18:38:31

标签: java oop java-8 enums switch-statement

我在JAVA中有一个枚举和POJO类。在枚举类中,每个枚举值都与POJO类的变量匹配...然后,我想在两个类之间创建一个关系。

枚举类别:

10

POJO类:

public enum MyEnum
{
   FIELD1,
   FIELD2,
   FIELD3,
   ...
}

然后,当我尝试匹配两个类的这些字段时,我实现了如下代码:

public class MyPojo
{
   private String field1;
   private String field2_not_ref;
   private String field3;
   ...
}

我认为这不是一个好的/明确的解决方案。有什么建议吗?

6 个答案:

答案 0 :(得分:5)

与在枚举上定义方法相比,为了避免反射(该过程可能较慢并且使事情更简洁),您可以创建一个枚举,其枚举的字段使用MyPojo并返回String

public enum MyEnum {
    FIELD1(MyPojo::getField1),
    FIELD2(MyPojo::getField2),
    FIELD3(MyPojo::getField3);

    private final Function<MyPojo, String> getField;

    MyEnum(Function<MyPojo, String> getField) {
        this.getField = getField;
    }
}

然后您可以通过以下方式调用它:

public static void main(String[] args) {
    MyPojo myPojo = new MyPojo("f1", "f2", "f3");
    System.out.println(MyEnum.FIELD2.getGetField().apply(myPojo));
}

如果不想通过Function方法将其用作apply变量,则可以在enum上创建一个函数,即可以做到这一点:

public enum MyEnum {
    FIELD1(MyPojo::getField1),
    FIELD2(MyPojo::getField2),
    FIELD3(MyPojo::getField3);

    private final Function<MyPojo, String> getField;

    MyEnum(Function<MyPojo, String> getField) {
        this.getField = getField;
    }

    String getFieldFromMyPojo(MyPojo myPojo) { return getField.apply(myPojo); }
}

并像这样调用它:

public static void main(String[] args) {
    MyPojo myPojo = new MyPojo("f1", "f2", "f3");
    System.out.println(MyEnum.FIELD2.getFieldFromMyPojo(myPojo));
}

为简洁起见,省略了字母和二传手。

答案 1 :(得分:2)

还有另一种方法:

在enum中定义一个抽象方法,并为每个enum字段覆盖:

public enum MyEnum {
    FIELD1 {
        @Override
        public String getFromPojo(MyPojo myPojo) {
            return myPojo.getField1();
        }
    },
    FIELD2 {
        @Override
        public String getFromPojo(MyPojo myPojo) {
            return myPojo.getField2();
        }
    },
    FIELD3 {
        @Override
        public String getFromPojo(MyPojo myPojo) {
            return myPojo.getField3();
        }
    };

    public abstract String getFromPojo(MyPojo myPojo);
}

对于类MyPojo定义字段的获取方法:

还定义方法matchMethod的方式来处理对枚举的责任(如果您愿意,这不是强制性的,因为枚举可以自行解决该字段)。

public class MyPojo {

    private String field1;
    private String field2;
    private String field3;

    public MyPojo(String field1, String field2, String field3) {
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
    }

    public String getField1() {
        return field1;
    }

    public String getField2() {
        return field2;
    }

    public String getField3() {
        return field3;
    }

    public String matchMethod(MyEnum myEnum) {
        return myEnum.getFromPojo(this);
    }
}

现在,在“主要”方法中,您可以使用以下方法:

 MyPojo p1 = new MyPojo("p1", "p2", "p3");
 MyPojo p2 = new MyPojo("k1", "k2", "k3");

 System.out.println(MyEnum.FIELD1.getFromPojo(p1));
 System.out.println(MyEnum.FIELD2.getFromPojo(p1));
 System.out.println(MyEnum.FIELD3.getFromPojo(p1));

 System.out.println(MyEnum.FIELD1.getFromPojo(p2));
 System.out.println(MyEnum.FIELD2.getFromPojo(p2));
 System.out.println(MyEnum.FIELD3.getFromPojo(p2));

 // in addition, if you've defined 'matchMethod' on POJO
 System.out.println(p1.matchMethod(MyEnum.FIELD1));
 System.out.println(p1.matchMethod(MyEnum.FIELD2));
 System.out.println(p1.matchMethod(MyEnum.FIELD3));

 System.out.println(p2.matchMethod(MyEnum.FIELD1));
 System.out.println(p2.matchMethod(MyEnum.FIELD2));
 System.out.println(p2.matchMethod(MyEnum.FIELD3));     

此打印:

p1
p2
p3
k1
k2
k3
// and optionally...
p1
p2
p3
k1
k2
k3

答案 2 :(得分:2)

您可以使用反射。这是一个示例:

public String matchMethod(MyEnum myenum, Map<MyEnum, String> enumToFieldMap) throws NoSuchFieldException, IllegalAccessException {
    String customFieldName = enumToFieldMap.get(myenum);
    if (customFieldName == null) { // custom field name not found, use default mapping
        return (String) this.getClass().getDeclaredField(myenum.name().toLowerCase()).get(this);
    } // custom field name found in config
    return (String) this.getClass().getDeclaredField(customFieldName).get(this);
}

public String matchMethod(MyEnum myEnum) throws NoSuchFieldException, IllegalAccessException {
    return matchMethod(myEnum, Collections.EMPTY_MAP);
}

使用反射有一些缺点,例如类型安全性或可追溯性,但是在这种情况下,我认为我会选择此选项。

另一个,更灵活的选择是将反射与自定义注释结合使用:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyEnumRef {
    MyEnum value();
}

和通用界面:

public interface Pojo {
}

现在,声明新的Pojo变得更加简单明了,并且可读性也越来越强(至少对于某些人而言)。在实际的映射(配置)完成的地方也很明显。

public class MyPojo implements Pojo {
    @MyEnumRef(MyEnum.FIELD1)
    private String field1;
    @MyEnumRef(MyEnum.FIELD2)
    private String field2;
    @MyEnumRef(MyEnum.FIELD3)
    private String field3;
}

public class MyOtherPojo implements Pojo {
    @MyEnumRef(MyEnum.FIELD1)
    private String field1;
    @MyEnumRef(MyEnum.FIELD2)
    private String field2;
}

一种简单的方法来统治所有人:

public String matchMethod(MyEnum myEnum, Pojo myPojo) throws IllegalAccessException {
        for (Field field : myPojo.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(MyEnumRef.class) && field.getAnnotation(MyEnumRef.class).value() == myEnum) {
                field.setAccessible(true);
                return (String) field.get(myPojo);
            }
        }
        return "";
    }

使用Pojo的哪种实现都无关紧要。添加新的Pojos时没有开销。示例:

private void run() throws IllegalAccessException {
    System.out.println(">>" + matchMethod(MyEnum.FIELD2, new MyPojo("f1", "f2", "f3")));
    System.out.println(">>" + matchMethod(MyEnum.FIELD1, new MyOtherPojo("o1", "o2")));
}

答案 3 :(得分:1)

此解决方案仅适用于static字段,因为枚举始终为static

我可以想象的一种方法是:

public enum MyEnum
{
   private String field;

   public String getField()
   { return this.field; }


   MyEnum(String field)
   {
      this.field = field;
   }

   FIELD1(field1),
   FIELD2(field2),
   FIELD3(field3),
   ...
}

如果需要,您甚至可以使其通用:

public enum MyEnum<T>
{
   private T field;

   public T getField()
   { return this.field; }


   MyEnum(T field)
   {
      this.field = field;
   }

   FIELD1(field1),
   FIELD2(field2),
   FIELD3(field3),
   ...
}

答案 4 :(得分:1)

这是另一种方法,它确实具有一个间接级别(注册),但没有修改枚举。

这需要Java 8+,因为它使用lambda表达式:

import java.util.EnumMap;
import java.util.function.Function;

enum MyEnum {
  FIELD1, FIELD2, FIELD3;
}

class MyPojo {
  private String field1, field2, field3;

  public MyPojo(String f1, String f2, String f3) {
    this.field1 = f1;
    this.field2 = f2;
    this.field3 = f3;
  }
  private static EnumMap<MyEnum, Function<MyPojo, String>> registry = new EnumMap(MyEnum.class);
  static {
    registry.put(MyEnum.FIELD1, p -> p.field1);
    registry.put(MyEnum.FIELD2, p -> p.field2);
    registry.put(MyEnum.FIELD3, p -> p.field3);
  }

  public String matchMethod(MyEnum e) {
    return registry.get(e).apply(this);
  }
}

class Main {
  public static void main(String[] args) {
    MyPojo p1 = new MyPojo("a", "b", "c");
    MyPojo p2 = new MyPojo("x", "y", "z");
    System.out.println(p1.matchMethod(MyEnum.FIELD1));
    System.out.println(p1.matchMethod(MyEnum.FIELD2));
    System.out.println(p1.matchMethod(MyEnum.FIELD3));

    System.out.println(p2.matchMethod(MyEnum.FIELD1));
    System.out.println(p2.matchMethod(MyEnum.FIELD2));
    System.out.println(p2.matchMethod(MyEnum.FIELD3));
  }
}

此打印:

a
b
c
x
y
z

答案 5 :(得分:0)

有多种选择(包括使用reflection),但是在简单的情况下,这些字段都是相同的类型(此处为fn capitalize_first(s: &str) -> String { let mut chars = s.chars(); chars .next() .map(|first_letter| first_letter.to_uppercase()) .into_iter() .flatten() .chain(chars) .collect() } ),我的建议是存储感兴趣的值改为使用EnumMap

transcribe.start_transcription_job(
    TranscriptionJobName=job_name,
    Media={'MediaFileUri': job_uri},
    MediaFormat='mp3',
    LanguageCode='en-US'
)
相关问题