在 java 中返回多个原始对象.不推荐? [英] Returning multiple primitive objects in java . Unrecommended?

查看:41
本文介绍了在 java 中返回多个原始对象.不推荐?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始学习 Java 中的 OOP 编程.我已经用 C++ 编写了一些程序,我在 Java 中最怀念的一件事是返回多个值的可能性.C++ 函数确实只严格返回一个变量,但我们可以使用按引用参数返回更多变量.相反,在Java中我们不能做这样的事情,至少对于原始类型我们不能.

我想到的解决方案是创建一个类,将我想要返回的变量分组并返回该类的一个实例.例如,我需要在一个数组中查找一个对象,我想返回一个布尔值(找到与否)和一个索引.我知道如果没有找到任何东西,我可以只将索引设置为 -1,但我认为另一种方式更清楚.

问题是有人告诉我,他对 Java 的了解比我了解的多得多,我不应该为了返回多个值(即使它们是相关的)而创建类.他告诉类不应该被用作 C++ 结构,只是为了对元素进行分组.他还说方法不应该返回非原始对象,它们应该从外部接收对象并且只修改它.以下哪些是真的?

解决方案

我不应该为了返回多个值而创建类

类不应用作 C++ 结构,仅用于对元素进行分组.

方法不应该返回非原始对象,它们应该从外部接收对象并且只修改它

对于上述任何陈述,情况绝对不是这样.数据对象很有用,事实上,将纯数据与包含大量逻辑的类分开是一种很好的做法.

在 Java 中,我们最接近结构的是 POJO(普通的 Java 对象),在其他语言中通常称为数据类.这些类只是一组数据.POJO 的一个经验法则是它应该只包含原语、简单类型(字符串、装箱原语等)、简单容器(映射、数组、列表等)或其他 POJO 类.基本上可以轻松序列化的类.

想要将两个、三个或 n 个对象配对在一起是很常见的.有时数据足够重要,足以保证一个全新的类别,而在其他情况下则不然.在这些情况下,程序员经常使用 PairTuple 类.这是一个二元素通用元组的快速示例.

public class Tuple2{私人决赛T优先;私人最后U秒;公共元组2(T第一,U第二){this.first = 第一;this.second = 第二个;}public T getFirst() { 先返回;}公共 U getSecond() { 返回第二个;}}

使用元组作为方法签名一部分的类可能如下所示:

公共接口容器{...public Tuple2搜索(T 键);}

创建这样的数据类的一个缺点是,为了生活质量,我们必须实现诸如toStringhashCodeequals之类的东西> getter、setter、构造函数等.对于每个不同大小的元组,您必须创建一个新类(Tuple2Tuple3Tuple4 等).创建所有这些方法会给我们的应用程序带来微妙的错误.由于这些原因,开发人员通常会避免创建数据类.

像 Lombok 这样的图书馆对于克服这些挑战非常有帮助.我们对 Tuple2 的定义,以及上面列出的所有方法,可以写成:

@Data公共类 Tuple2{私人决赛T优先;私人最后U秒;}

这也使得创建自定义响应类变得非常容易.使用自定义类可以避免使用泛型自动装箱,并大大提高可读性.例如:

@Data公共类搜索结果{找到私有最终布尔值;私有最终整数索引;}...公共接口 Container<T>{...公共搜索结果搜索(T 键);}


<块引用>

方法应该从外部接收对象并且只修改它

这是一个糟糕的建议.围绕不变性设计数据要好得多.来自 Effective Java 2nd Edition, p75

<块引用>

不可变对象很简单.一个不可变对象只能处于一种状态,即它被创建时的状态.如果您确保所有构造函数都建立了类不变量,则可以保证这些不变量将始终保持正确,您或使用该类的程序员无需进一步努力.另一方面,可变对象可以具有任意复杂的状态空间.如果文档没有提供由 mutator 方法执行的状态转换的准确描述,则可能很难或不可能可靠地使用可变类.

不可变对象本质上是线程安全的;它们不需要同步.它们不会被多个线程同时访问它们而损坏.这无疑是实现线程安全的最简单方法.事实上,没有一个线程可以观察到另一个线程对一个不可变对象的任何影响.因此,不可变对象可以自由共享.

I'm just beginning to learn OOP programming in java. I have already programmed a little in C++, and one of the things I miss the most in Java is the possibility to return multiple values. It's true that C++ functions only strictly return one variable, but we can use the by-reference parameters to return many more. Conversely, in Java we can't do such a thing, at least we can't for primitive types.

The solution I thought off was to create a class grouping the variables I wanted to return and return an instance of that class. For example, I needed to look for an object in a an array and I wanted to return a boolean(found or not) and an index. I know I could make this just setting the index to -1 if nothing was found, but I think it's more clear the other way.

The thing is that I was told by someone who knows much more about Java than I know that I shouldn't create classes for the purpose of returning multiple values ( even if they are related). He told classes should never be used as C++ structs, just to group elements. He also said methods shouldn't return non-primitive objects , they should receive the object from the outside and only modify it. Which of these things are true?

解决方案

I shouldn't create classes for the purpose of returning multiple values

classes should never be used as C++ structs, just to group elements.

methods shouldn't return non-primitive objects, they should receive the object from the outside and only modify it

For any of the above statements this is definitely not the case. Data objects are useful, and in fact, it is good practice to separate pure data from classes containing heavy logic.

In Java the closest thing we have to a struct is a POJO (plain old java object), commonly known as data classes in other languages. These classes are simply a grouping of data. A rule of thumb for a POJO is that it should only contain primitives, simple types (string, boxed primitives, etc) simple containers (map, array, list, etc), or other POJO classes. Basically classes which can easily be serialized.

Its common to want to pair two, three, or n objects together. Sometimes the data is significant enough to warrant an entirely new class, and in others not. In these cases programmers often use Pair or Tuple classes. Here is a quick example of a two element generic tuple.

public class Tuple2<T,U>{
    private final T first;
    private final U second;

    public Tuple2(T first, U second) {
        this.first = first;
        this.second = second;
    }

    public T getFirst() { return first; }
    public U getSecond() { return second; }
}

A class which uses a tuple as part of a method signature may look like:

public interface Container<T> {
     ...
     public Tuple2<Boolean, Integer> search(T key);
}

A downside to creating data classes like this is that, for quality of life, we have to implement things like toString, hashCode, equals getters, setters, constructors, etc. For each different sized tuple you have to make a new class (Tuple2, Tuple3, Tuple4, etc). Creating all of these methods introduce subtle bugs into our applications. For these reasons developers will often avoid creating data classes.

Libraries like Lombok can be very helpful for overcoming these challenges. Our definition of Tuple2, with all of the methods listed above, can be written as:

@Data
public class Tuple2<T,U>{
    private final T first;
    private final U second;
}

This also makes it extremely easy to create custom response classes. Using the custom classes can avoid autoboxing with generics, and increase readability greatly. eg:

@Data
public class SearchResult {
    private final boolean found;
    private final int index;
}
...
public interface Container<T> {
     ...
     public SearchResult search(T key);
}


methods should receive the object from the outside and only modify it

This is bad advice. It's much nicer to design data around immutability. From Effective Java 2nd Edition, p75

Immutable objects are simple. An immutable object can be in exactly one state, the state in which it was created. If you make sure that all constructors establish class invariants, then it is guaranteed that these invariants will remain true for all time, with no further effort on your part or on the part of the programmer who uses the class. Mutable objects, on the other hand, can have arbitrarily complex state spaces. If the documentation does not provide a precise description of the state transitions performed by mutator methods, it can be difficult or impossible to use a mutable class reliably.

Immutable objects are inherently thread-safe; they require no synchronization. They cannot be corrupted by multiple threads accessing them concurrently. This is far and away the easiest approach to achieving thread safety. In fact, no thread can ever observe any effect of another thread on an immutable object. Therefore, immutable objects can be shared freely.

这篇关于在 java 中返回多个原始对象.不推荐?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆