类型安全:Map []类型的表达式需要未经检查的转换才能符合Map <string,object> []

时间:2018-12-29 20:30:27

标签: java arrays generics hashmap

我有以下两行:

Map<String,Object>[] IEXDivMap = null;       

IEXDivMap =  new Map[IEXJsonArray.length()];

并得到警告:

The expression of type Map[] needs unchecked conversion to conform to Map<String,Object>[]

有没有办法解决这个问题?

更新:

我在评论中被问到为什么我们需要一个Map数组。我们将获得一系列哈希图,并将每个哈希图放置在map数组中。这是代码:

@SuppressWarnings("unchecked")
public static Map<String,Object>[] getDiv(String ticker) {
    Map<String,Object>[] IEXDivMap = null;
    try{
        String url = "https://api.IEXtrading.com/1.0/stock/" + ticker + "/dividends/1y"; 
        URL obj = new URL(url);   

        HttpURLConnection con = (HttpURLConnection) obj.openConnection();       
        con.setRequestMethod("GET");
        int responseCode = con.getResponseCode();
        if(responseCode == 404){
            System.out.println("Ticker " + ticker + " NOT FOUND in getDiv()!");
            return IEXDivMap;                
        }else if (responseCode != 200){
            System.out.println("IEX Printing All Response Header for URL: " + obj.toString() + "\n");
            Map<String, List<String>> map = con.getHeaderFields();            
            for(Map.Entry<String, List<String>> entry : map.entrySet()) {
                System.out.println("IEX " + entry.getKey() + " : " + entry.getValue());
            }
        }

        BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
        String inputLine;
        StringBuilder response = new StringBuilder();

        while ((inputLine = in.readLine()) != null) {
            response.append(inputLine);             
        }
        in.close();

        JSONArray IEXJsonArray = new JSONArray(response.toString());        
        IEXDivMap = new Map[IEXJsonArray.length()];

        for (int i = 0; i < IEXJsonArray.length(); i++) {
            IEXDivMap[i] = new HashMap<String,Object>();
            JSONObject IEXJsonObject = IEXJsonArray.getJSONObject(i);

            IEXDivMap[i].put("exDate",IEXJsonObject.getString("exDate"));
            IEXDivMap[i].put("amount",IEXJsonObject.getString("amount"));

            //System.out.println(IEXDivMap[i]);
            System.out.println(IEXDivMap[i].get("exDate") + " 0  " + IEXDivMap[i].get("amount"));
        }
    }catch(Exception e){
        System.out.println("FATAL ERROR: Something went wrong in getDiv " + e.getMessage());
        System.exit(0);
    }
    return IEXDivMap; 
}

5 个答案:

答案 0 :(得分:4)

不幸的是,不可能以干净的方式解决此问题。

干净的解决方案是创建通用数组,但由于类型擦除而无法实现。

为什么禁止创建通用数组?

考虑以下数组示例:

Object[] arr = new String[1];
arr[0] = 10;

结果为ArrayStoreException

现在想象一下允许创建通用数组:

Map<String, String>[] map = new Map<>[1]; // This is illegal
Object[] objects = map;
objects[0] = new HashMap<Integer, Integer>(); // No ArrayStoreException

编译器警告说,可以将任何Map放入数组,并且编译器和运行时都不能检查它。因此警告

解决方法?

引用Java generics faq可以使用:

  
      
  • 原始类型的数组
  •   
  • 无界通配符参数化类型的数组
  •   
  • 集合而不是数组
  •   

我个人强烈建议您考虑使用List

List<Map<String, Object>> list = new ArrayList<>();

答案 1 :(得分:2)

您无法避免该警告。数组创建仅允许将原始类型用作元素类型。我确定Java专家决定不在那里允许泛型是有原因的,但我不知道该原因。

因此,如果您真的想要一个Map<String,Object>元素数组(由于某种原因不能使用List),则可以声明具有该泛型类型的变量,但是您将始终在存储刚创建的数组时会收到该警告,因为该数组只能具有原始类型。

但这只是一个警告,您的代码将运行得很好。这是一个警告,而不是一个错误,这意味着有些事情需要开发人员注意,因为编译器无法确定是否可以。

那么导致警告的问题是什么?

在运行时,Map<String,Object>[]仅仅是Map[],因为在编译过程中会擦除泛型类型。因此,创建数组会产生正确的数组运行时类型,并且您不会从该分配中获得ClassCastException。仅在编译时检查泛型规则:编译器有责任确保分配给Map[]变量的运行时Map<String,Object>[]仅包含其中字符串用作键的Maps和对象作为值(当然null值也可以作为数组元素)。

现在,如果您将编译时的Map[]值分配给Map<String,Object>[]变量,

Map[] rawArray = ...;
Map<String,Object>[] generic Array = rawArray;

编译器不知道rawArray中包含的映射使用什么类型的键和值,因此他正确地警告您这种类型不兼容的风险。但是,对于新创建的new Map[n]

Map<String,Object>[] genericArray = new Map[5];

编译器根本不够聪明,无法看到此数组仅包含其初始null值,因此完全符合Map<String,Object>[]的要求。该语句实际上并不包含任何与类型相关的风险,只是编译器不够智能而无法理解。

因此,我的建议是忽略警告或在此处放置适当的@SuppressWarnings注释,并说明为什么有理由抑制警告。遗憾的是我们无法将@SuppressWarnings注释应用于单个语句,因此您可能希望将数组创建重构为自己的方法,因此@SuppressWarnings注释仅适用于该操作而不是整个方法。

答案 2 :(得分:0)

对于您的用例,我没有看到在像List这样的集合上使用数组的内在优势。只需将您的代码更改为使用List即可,这将确保类型安全,并且无需进行任何类型的索引等操作。

将要改变的大事情:

  • 如何声明退货类型

    public static List<Map<String,Object>> getDiv(String ticker) 
    
  • 如何实例化持有人

    List<Map<String,Object>> IEXDivMap = new ArrayList<>();
    
  • 如何填充地图(有点,您只需更改其引用方式即可)

    Map<String, Object> divMap = new HashMap<>();
    

答案 3 :(得分:0)

无法避免警告。

通过将其显式转换为适当的参数化数组类型,可以避免未检查的转换警告:

IEXDivMap = (Map<String, Object>[]) new Map[IEXJsonArray.length()];

IEXDivMap = (Map<String, Object>[]) new Map<?,?>[IEXJsonArray.length()];

但是它将导致产生未经检查的强制转换警告,因此您将一个警告换成另一个。

答案 4 :(得分:-2)

也许是这样吗?

import java.util.Map;
import java.util.HashMap;

public class test {
  public static void main(String[] args) {
    class MyMap extends HashMap<String,Object> { }
    MyMap[] IEXDivMap = null;       

    IEXDivMap = new MyMap[2];
  }
}