Java对象解构

39

在JavaScript中,有对象解构,因此我们可以将对象拆分并只使用最终键,如果中间对象被多次重用。 例如:

const person = {
  firstName: "Bob",
  lastName: "Marley",
  city: "Space"
}

所以,我们可以像这样解构它来获取每个值,而不是调用 person.<>

console.log(person.firstName) 
console.log(person.lastName) 
console.log(person.city) 

解构:

const { firstName, lastName, city } = person;

像这样调用:

console.log(firstName)
console.log(lastName)
console.log(city)

在 Java 中是否有类似的东西?我有一个 Java 对象,需要从中获取值,并且必须像这样调用长的中间对象名称:

myOuterObject.getIntermediateObject().getThisSuperImportantGetter()
myOuterObject.getIntermediateObject().getThisSecondImportantGetter()
...

我希望以某种方式对它进行解构,并仅调用最后一个方法getThisSuperImportantGetter()getThisSecondImportantGetter(),以便使代码更加简洁。


这就是在Java中“解构”对象的方法。你可以通过各种方式将字符串转换为属性,但这样做没有什么意义,或者你可以引入一个JVM脚本语言。无论哪种方式,你都会付出性能代价。或者你可以获取中间对象,并以此为基础编写主线代码。当你需要访问嵌套对象时,“干净”的概念通常不与Java代码相关(并且根据您需要多么容易地修改/扩展代码,例如Demeter,这样做可能有点冒险)。 - Dave Newton
Java并不以简洁和表达能力著称。如果这些特点对您很重要,您可能需要考虑其他JVM语言。 - Carcigenicate
不,它不会,但是您可以使用第一个getter的结果调用一个方法,然后在该方法内部处理内部对象。 - Juan Carrey
1
你可以先将内部对象分配给一个1个字母的变量,然后调用a.getThisSuperImportantGetter()a.getThisSecondImportantGetter() - isaace
3个回答

28

Java语言架构师Brian Goetz最近谈到了在即将发布的Java版本中添加解构(destructuring)功能。请查看他的文章中的Sidebar: pattern matching章节:

Towards Better Serialization

我强烈不喜欢当前的语法提案,但根据Brian所说,您的用例将如下所示(请注意,这仅仅是一个提案,并且不能在任何当前的Java版本中使用):

public class Person {
    private final String firstName, lastName, city;

    // Constructor
    public Person(String firstName, String lastName, String city) { 
        this.firstName = firstName;
        this.lastName = lastName;
        this.city = city;
    }

    // Deconstruction pattern
    public pattern Person(String firstName, String lastName, String city) { 
        firstName = this.firstName;
        lastName = this.lastName;
        city = this.city;
    }
}

然后,您就可以在instanceof检查中使用该解构模式,例如:

if (o instanceof Person(var firstName, lastName, city)) {
   System.out.println(firstName);
   System.out.println(lastName);
   System.out.println(city);
}

抱歉,Brian的例子中没有提到任何直接解构赋值的内容,我不确定这些是否会被支持,并且如何支持。

在旁边说一句:我确实看到了它与构造函数的相似之处,但我个人并不太喜欢目前的提案,因为“解构器”的参数感觉像是输出参数(Brian在他的论文中也这样说)。对我来说,在每个人都谈论不变性和让方法参数成为final的世界里,这相当不直观。

我更希望看到Java跨越障碍并支持多值返回类型。大致上是这样的:

    public (String firstName, String lastName, String city) deconstruct() { 
        return (this.firstName, this.lastName, this.city);
    }

2
一旦元组类型和解构内置到语言中,多个返回类型就会自动出现。 - Aiono
1
值得注意的是,当使用public record Person(String firstName, String lastName, String city){}时,您将免费获得deconstruct。我同意输出参数有点奇怪。 - Holger
只是好奇:您能否举个例子,说明如何使用“记录”来协助解构? - Stefan Haberl
2
虽然解构声明的最终语法尚未确定,但已经确定记录将获得默认实现,类似于它们今天获得默认构造函数的方式。因此,使用记录声明,将组件匹配解构为变量将立即生效。 - Holger
记录模式 现在是 Java 21 的一部分。 就像 @StefanHaberl 一样,我起初对语法感到困惑。然而,它确保以类型安全的方式实现了深度解构,尤其是考虑到类型擦除的情况下。 - richardb
1
有趣的是,在2023年我们仍然在谈论类型擦除 ;) - Stefan Haberl

24
据我所知,Java不支持这个功能。
另一种JVM语言叫做Kotlin,它支持这个功能。 Kotlin | 解构声明

2
Clojure也支持它,甚至包括数组和映射等嵌套结构。 - ᐅdevrimbaris

1
正如所指出的,Java不支持像Javascript那样的解构赋值。但是,Groovy,一种JVM语言,也支持这样的赋值方式。
def (a,b,c) = [10, 20, 'foo']

或者使用数据类型如下所示:
def (int i, String j) = [10, 'foo']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接