简体   繁体   English

返回语句应该在Java中使用泛型吗?

[英]Should return statements use generics in Java?

I have a basic question about using the "Best Practices" in coding. 我有一个关于在编码中使用“最佳实践”的基本问题。 (I'm using Java, but the question is general to OOP.) When writing method's for a class that are intended to be used in the long run, is it best to leave the return object with or without generics? (我正在使用Java,但问题对于OOP来说是一般性的。)当为一个打算长期使用的类编写方法时,是否最好留下返回对象有或没有泛型?

To be specific in my case, I'm returning a Map<String, Integer> with the method. 在我的情况下具体来说,我正在使用该方法返回Map<String, Integer> Should I specify this in the return statement, or should I simply return a Map ? 我应该在return语句中指定它,还是应该只返回一个Map

It is best to use generics whenever possible. 最好尽可能使用泛型。 It will help avoid runtime exceptions, and it won't force the people using your code to do a bunch of ugly type casting. 它将有助于避免运行时异常,并且它不会强迫使用您的代码的人进行一堆丑陋的类型转换。 For example, if you use the following signature: 例如,如果您使用以下签名:

Map<String, Integer> getMap();

... then the consuming code might look like this: ...然后消费代码可能如下所示:

Map<String, Integer> map = getMap();
Integer val = map.get(key);

... but if you use a signature like this: ...但是如果你使用这样的签名:

Map getMap();

... the consuming code might look like this: ...消费代码可能如下所示:

Map<String, Integer> map = (Map<String, Integer)getMap();
Integer val = map.get(key);

By using generics, not only do you save that (Map<String, Integer>) cast, but in the event that you change getMap to actually return a Map<String, Object> , you will get a compile-time error (which is easy to catch and fix), rather than possibly getting an exception when you call map.get(key) and the JRE tries to do an automatic cast of some random Object into an Integer. 通过使用泛型,不仅可以保存(Map<String, Integer>) getMap转换,但是如果您将getMap更改为实际返回Map<String, Object> ,则会出现编译时错误(即容易捕获和修复),而不是在调用map.get(key)时可能会出现异常,并且JRE尝试将某个随机Object自动转换为Integer。

You should definitely return a Map<String, Integer> instead of a plain Map if it makes sense in your method, as this will make it easier for others to use said method - after getting the Map<String, Integer> they will be able to retrieve String keys and Integer values without having to cast them from a generic Object every time (this also makes it a little more typesafe as this way they will know what the keys and values are without even reading the javadoc for your method). 如果在你的方法中有意义的话,你肯定应该返回一个Map <String,Integer>而不是一个普通Map,因为这将使其他人更容易使用所述方法 - 在获得Map <String,Integer>后他们将能够检索字符串键和整数值,而不必每次都从通用对象中转换它们(这也使它更加类型安全,因为这样他们就会知道键和值是什么,甚至没有为你的方法读取javadoc)。

So in short, definitely, return generics. 所以简而言之,肯定是返回泛型。

If the method is clearly intended to work with a certain type (ie only String ), then it's ok to return a List<String> . 如果该方法明确用于某种类型(即只有String ),则可以返回List<String> If the method is generic taking a type parameter T , you can return List<T> . 如果该方法是通用的,则采用类型参数T ,您可以返回List<T>

I would not simply return a Map , because usually it causes confusion and more boiler-plate code to convert to the desired type. 我不会简单地返回一个Map ,因为它通常会导致混淆和更多的样板代码转换为所需的类型。

If you are returning a collection, you should include the generic type that is contained by the collection. 如果要返回集合,则应包括集合包含的泛型类型。 For example: 例如:

public Map<String, Blammo> getBlammoMap(...)

is (IMHO) preferred to 是(恕我直言)的首选

public Map getBlammoMap(...)

Because it 因为它

  1. Limits the options of a bad cast (ie kapowMap = (Map<String, Kapow> getBlammoMap() ). 限制坏转换的选项(即kapowMap = (Map<String, Kapow> getBlammoMap() )。
  2. Tells the consumer what the method is actually returning. 告诉消费者该方法实际返回的是什么。

In general, your type parameters, both input and output, should capture the level of specificity of the precise function. 通常,输入和输出的类型参数应该捕获精确函数的特异性级别。 In functional programming, they go so far as to say "the types are the documentation." 在函数式编程中,他们甚至说“类型是文档”。 If I were to see Map foo(Arg args) I would think that foo is in no way concerned with the types in the Map it returns, but somehow relies on Args for something." If I were to see Map<T,String> foo(T t, Arg arg) or Map<T, U> foo(T t, U u) I would think "OK, foo produces a Map based on the type of its t and with a String produced by Arg (or by the U from u )." 如果我看到Map foo(Arg args)我会认为foo并不关心它返回的Map中的类型,但不知何故依赖于Args的东西。“如果我看到Map<T,String> foo(T t, Arg arg)Map<T, U> foo(T t, U u)我会想“好吧,foo根据其t的类型和Arg生成的String生成一个Map(或者来自uU )。“

In terms of preference, clearly you want to be as clear as possible to the future programmer (yourself or others). 在偏好方面,显然你希望对未来的程序员(你自己或其他人)尽可能清楚。 Just as returning Map without type-params is obscure, so too would returning Map<String, Integer> might be overly restrictive (and thus misleading) if your foo would work equally well with, say, Map<String, Long> 就像没有类型参数的返回Map是模糊的一样,返回Map<String, Integer>也可能过于严格(因而误导),如果你的fooMap<String, Long>

I believe that more specific, the better. 我相信更具体,更好。 If your method is return a map that always has Strings as the key, and Integers as the value, then definitely use the Map has the return type. 如果你的方法返回一个总是以字符串作为键,并且整数作为值的映射,那么肯定使用Map具有返回类型。 That way, any calling code knows exactly what they're getting. 这样,任何调用代码都准确地知道他们得到了什么。 If the return type was just Map, then the calling code would have no idea what the class the keys and values are (Other than Object). 如果返回类型只是Map,那么调用代码将不知道键和值是什么类(除了Object之外)。

In general, you should probably always specify paramerize Maps, Lists, etc., so it's known exactly what it contains. 通常,您应该总是指定参数化地图,列表等,因此它确切地知道它包含的内容。 This is very helpful when iterating over them and you can use a java foreach. 迭代它们时,这非常有用,你可以使用java foreach。

for (String currKey : myMap.keySet())
{
  System.out.println("curr Key: " + currKey + " curr Value: " + myMap.get(currKey));
}

This eliminates any extra iterators or casting. 这消除了任何额外的迭代器或铸造。

Ho-ho-ho! 哈哈哈! A pretty New Year question. 一个漂亮的新年问题。

You generally must (MUST) return a proper generic Map<Whatever, YouNeed> . 你通常必须(必须)返回一个合适的通用Map<Whatever, YouNeed> It may sound crazy, but as soon as you use any generic type without type parameters, you're getting into trouble. 这可能听起来很疯狂,但只要您使用任何没有类型参数的通用类型,您就会遇到麻烦。

The trouble will be as follows: raw types, being used in the code, change the way methods (even seemingly non-related ones) are resolved. 麻烦将如下:在代码中使用的原始类型, 改变方法(甚至看似不相关的方法)的解决方式。 Find a presentation by Joshua Bloch and Bill Pugh called "Java Puzzlers: Scraping the Bottom of the Barrel" for details whle I'm preparing an example :) The video with details is at http://www.parleys.com/#id=2168&st=5 (you may want to scroll to slide 44, 5. "Glommer Pile") 查看Joshua Bloch和Bill Pugh的演讲,题为“Java Puzzlers:刮痧底部”,详细介绍我正在准备一个例子:)有关详情的视频,请访问http://www.parleys.com/#id = 2168&st = 5 (您可能想要滚动到幻灯片44,5。“Glommer Pile”)

So here's an example: 所以这是一个例子:

/**
 * (c) (as far as I know) Joshua Bloch and Bill Pugh, 2010
 */
public class Glommer<T> {
    String glom(Collection<?> objs) {
        String result = "";
        for (Object o : objs) result += o;
        return result;
    }

    int glom(List<Integer> ints) {
        int result = 0;
        for (int i : ints) result += i;
        return result;
    }

    public static void main(String args[]) {
        List<String> strings = Arrays.asList("1", "2", "3");
        System.out.println(new Glommer().glom(strings));
    }
}

Question is, whether it 问题是,是否

  • prints 6 打印6
  • prints 123 打印123
  • throws an exception, 抛出异常,
  • or does something else. 或做其他事情。

Try to guess. 猜猜看。 Then compile (yes it compiles) and see what happens. 然后编译(是的,编译),看看会发生什么。

Now that does not apply to your case. 现在,这并不适用于你的情况。 But having a habit of always specifying the type, even if it will be just Map<?,?> , is extremely helpful. 但是有一个总是指定类型的习惯,即使它只是Map<?,?> ,也是非常有帮助的。 You won't lose. 你不会输。

The obligatory Java Generics FAQ link 必修的Java Generics FAQ链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM