gpt4 book ai didi

java - 将 toString 与对象创建相关联

转载 作者:行者123 更新时间:2023-12-03 23:01:59 25 4
gpt4 key购买 nike

我有一个相当基本的 Java 类,其中包含一些类变量。我已经覆盖 toString() 为我提供了一个字符串输出(最终将输出到一个文本文件)。
我正在尝试优雅地创建一种方法,让我使用此字符串输出来重新创建具有以前设置的所有变量的对象。这个类看起来像这样:

public class Report {

private String itemA;
private String itemB;
private String itemC;

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Items are::");
sb.append("\nItem A is: ").append(itemA);
sb.append("\nItem B is: ").append(itemB);
sb.append("\nItem C is: ").append(itemC);
return sb.toString();
}
}
这就是我可以使用反射来解决它的方法:
public class Report {

private String itemA;
private String itemB;
private String itemC;

private final Map<String, String> MAPPING = new HashMap<>();

public Report(String itemA, String itemB, String itemC) {
this.itemA = itemA;
this.itemB = itemB;
this.itemC = itemC;

MAPPING.put("Item A is: ", "itemA");
MAPPING.put("Item B is: ", "itemB");
MAPPING.put("Item C is: ", "itemC");
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Items are::");

MAPPING.entrySet().forEach(entry -> {
sb.append("\n").append(entry.getKey()).append(BeanUtils.getProperty(this, entry.getValue()));
});

return sb.toString();
}


public Report createReportFromString(String reportString) {
List<String> reportLines = Arrays.asList(reportString.split("\n"));
HashMap<String, String> stringObjectRelationship = new HashMap<>();

reportLines.forEach(reportLine -> {
Optional<String> matchingKey = MAPPING.keySet().stream().filter(reportLine::contains).findFirst();
matchingKey.ifPresent(key -> {stringObjectRelationship.put(MAPPING.get(key), reportLine.split(key)[1]);});
});

stringObjectRelationship.forEach((variableName, variableValue) -> BeanUtils.setProperty(this, variableName, variableValue));
return this;
}
}
我基本上想将报告中的键(“Item A 是:”)与相应变量的名称(“itemA”)相关联,并在 toString() 方法和 createReportFromString(String string) 方法中使用这种关系。现在,在执行此操作时,可能会抛出许多可能的异常,需要处理或抛出 - 然后它看起来不像我想要的那么优雅。
我不知道这是否可以在没有反射的情况下完成 - 或者我可以重新安排这个类(class)以使这成为可能?
我无法改变的是 toString() 中字符串输出的结构。

最佳答案

反射具有多种特征:

  • 在运行时自动发现程序的特性
  • 支持处理编译时未知的特性
  • 提供程序功能的抽象(例如方法或字段)

  • 您的方法表明您不想要自动发现,因为您明确指定了三个元素。这是一件好事,因为它使您的程序在 future 的更改方面更加健壮,因为处理自动发现的潜在未知程序元素将破坏编译器的任何帮助,因为它无法告诉您何时存在不匹配。
    您只需要第三点,即对报告元素的抽象。您可以自己创建这样的抽象,根据您的用例量身定制,无需反射,这将更健壮,甚至更高效:
    public class Report {
    static final class Element {
    final String header;
    final Function<Report,String> getter;
    final BiConsumer<Report,String> setter;
    final Pattern pattern;
    Element(String header,
    Function<Report, String> getter, BiConsumer<Report, String> setter) {
    this.header = header;
    this.getter = getter;
    this.setter = setter;
    pattern = Pattern.compile("^\\Q"+header+"\\E(.*?)$", Pattern.MULTILINE);
    }
    }
    static final List<Element> ELEMENTS = List.of(
    new Element("Item A is: ", Report::getItemA, Report::setItemA),
    new Element("Item B is: ", Report::getItemB, Report::setItemB),
    new Element("Item C is: ", Report::getItemC, Report::setItemC));

    private String itemA, itemB, itemC;

    public Report(String itemA, String itemB, String itemC) {
    this.itemA = itemA;
    this.itemB = itemB;
    this.itemC = itemC;
    }
    @Override public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("Items are:");
    ELEMENTS.forEach(e ->
    sb.append('\n').append(e.header).append(e.getter.apply(this)));
    return sb.toString();
    }
    public static Report createReportFromString(String reportString) {
    return new Report("", "", "").setValuesFromString(reportString);
    }
    public Report setValuesFromString(String reportString) {
    Matcher m = null;
    for(Element e: ELEMENTS) {
    if(m == null) m = e.pattern.matcher(reportString);
    else m.usePattern(e.pattern).reset();

    if(!m.find())
    throw new IllegalArgumentException("missing \""+e.header+'"');
    e.setter.accept(this, m.group(1));
    }
    return this;
    }
    public String getItemA() {
    return itemA;
    }
    public void setItemA(String itemA) {
    this.itemA = itemA;
    }
    public String getItemB() {
    return itemB;
    }
    public void setItemB(String itemB) {
    this.itemB = itemB;
    }
    public String getItemC() {
    return itemC;
    }
    public void setItemC(String itemC) {
    this.itemC = itemC;
    }
    }
    这适用于 Java 的开箱即用功能,不需要另一个库来简化操作。
    请注意,我更改了代码模式,如 createReportFromString是修改已存在对象的方法的误导性名称。我使用工厂方法的名称来真正创建一个新对象,并添加了另一种设置对象值的方法(作为 toString 的直接对应部分)。
    如果您仍在使用 Java 8,您可以替换 List.of(…)Arrays.asList(…)或更好 Collections.unmodifiableList(Arrays.asList(…)) .

    您也可以删除 .reset()调用 setValuesFromString方法。删除它时,输入字符串中的元素必须与 toString() 的顺序相同。方法产生。这使得它不太灵活,但如果您扩展代码以包含更多元素,则效率会更高。

    关于java - 将 toString 与对象创建相关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65080551/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com