2

I have a method that puts value in HashMap of type HashMap<String, Object[]> & returns the same HashMap.

Code for putting value in HashMap:

doc = Jsoup.connect(url).get();
for( org.jsoup.nodes.Element element : doc.getAllElements() )
{
    for( Attribute attribute : element.attributes() )
    {
        String option_ID=element.tagName()+"_"+attribute.getKey()+"_"+attribute.getValue();
        String HTMLText=element.text();
        int HTMLTextSize=HTMLText.length();
        if(!HTMLText.isEmpty())
            data.put("Test"+i,new Object[{"Test"+i,option_ID,HTMLText,HTMLTextSize});//adding value in HashMap.
            i++;
    }

 }

I tried iterating as below, which I think is not the correct way :

HashMap<String, Object[]>set=HTMLDocument.createHTMLSet("URL of website");
Iterator it = set.entrySet().iterator();
while (it.hasNext()) {
    Map.Entry pair = (Map.Entry)it.next();
    System.out.println(pair.getKey() + " = " + pair.getValue());
}

As I am getting output as :

Test79 = [Ljava.lang.Object;@14e1a0f

Test378 = [Ljava.lang.Object;@1a5f880

How should I iterate over this HashMap to get Object[] values such as option_ID, HTMLText?

Maroun
  • 94,125
  • 30
  • 188
  • 241
MKay
  • 818
  • 9
  • 32
  • You should know the type of object to iterate. – Shriram Dec 21 '15 at 07:01
  • 1
    The value is *array* of `Object` objects. – Maroun Dec 21 '15 at 07:02
  • @Shriram: I am creating this object as `new Object[]{"Test"+i,option_ID,HTMLText,HTMLTextSize}` where, ID & Text are string & TextSize is of type int. – MKay Dec 21 '15 at 07:03
  • You shouldn't be doing it like this anyway. Create a proper class to store the information properly. Using an array of Object like this is like working in an untyped language. You lose all the benefits of Java (including, in this case, a good `toString` implementation). – RealSkeptic Dec 21 '15 at 07:04
  • 1
    When you see a toString output that begins with `"[L"`, that means it's an array as @MarounMaroun suggests. You'd have to check for array and then use Arrays.toString to print out it's contents. – Stan Kurdziel Dec 21 '15 at 07:05
  • Don't use raw types. Iterator should be Iterator>. Map.Entry should be Map.Entry. No cast needed anymore, and type safety ensured. – JB Nizet Dec 21 '15 at 07:06
  • Not sure if this should be closed as duplicate of http://stackoverflow.com/questions/409784/whats-the-simplest-way-to-print-a-java-array, or of http://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it – JB Nizet Dec 21 '15 at 07:07
  • Better override toString() method in your object to display the values. – Shriram Dec 21 '15 at 07:08

4 Answers4

4

Since each object has toString() method, the default displays the class name representation, then adding @ sign and then the hashcode, that's why you're getting the output

[Ljava.lang.Object;@14e1a0f

that means the array contains a class or interface.

One solution would be looping on the array and print each part (or using Arrays.toString method), but I highly recommend you wrapping this to your own class and override the toString method.

Maroun
  • 94,125
  • 30
  • 188
  • 241
  • Yes, this exactly worked. I tried to adopt your answer like this : ` System.out.println(pair.getKey() + " = " + Arrays.toString((Object[]) pair.getValue()));` It did give me contents in readable format. – MKay Dec 21 '15 at 07:18
  • 2
    @mk08 Thought I really encourage you to have a custom class containing all of the fields you want. It's more encapsulated and a better practice. – Maroun Dec 21 '15 at 07:19
  • This object is actually getting created on runtime when `Jsoup` parser connects to URL and scans the entire `DOM`. This may be basic question as I have not used Java at this extent, but for this scenario also would you suggest to have separate class? – MKay Dec 21 '15 at 07:23
  • @mk08 Sure, you can pass the result of `Jsoup` to the constructor of the class where you actually create the new class. – Maroun Dec 21 '15 at 07:24
  • Oh yes, that explains it. Thanks a ton! – MKay Dec 21 '15 at 07:25
1

The following code might help. Its always better to create a bean class consisting of the necessary information to be stored in an array of objects.

package stack.overflow;

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

public class RetrieveMap {
    public static void main(String[] args) {
        Person p = new Person();
        p.setName("John");
        p.setEmpNo("1223");
        p.setAge("34");

        Person p1 = new Person();
        p1.setName("Paul");
        p1.setEmpNo("1224");
        p1.setAge("35");

        Person[] arr = new Person[2];
        arr[0] = p ;
        arr[1] = p1;

        HashMap<String,Person[]> map = new HashMap<String,Person[]>(); 
        map.put("a1", arr);

        for(Map.Entry<String, Person[]> entry : map.entrySet()) {
            System.out.println("Key:" +entry.getKey());
            System.out.println("Value:" +entry.getValue());
            for(int i=0;i<entry.getValue().length;i++) {
                System.out.println("------------------");
                System.out.println("Array:"+i);
                Person r1 = (Person)entry.getValue()[i];
                System.out.println("Name:" +r1.getName());
                System.out.println("Age:" + r1.getAge());
                System.out.println("Emp no:" + r1.getEmpNo());
                System.out.println("------------------");
            }
        }
    }
}

package stack.overflow;

public class Person {
    String name;
    String age;
    String empNo;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public String getEmpNo() {
        return empNo;
    }
    public void setEmpNo(String empNo) {
        this.empNo = empNo;
    }
}
Priya
  • 81
  • 3
1

The short answer is your code is behaving exactly correctly; when you call .toString() on an Object[] (which happens implicitly with System.out.println()) you get that odd [<TYPE>@<IDENTIFIER> string. To print the contents of an array, use Arrays.toString().

There are a number of things we can clean up with this code, though.

  • Avoid mixing generics and arrays (Effective Java Item 25); arrays lack the type safety generics provide, and there's rarely a good reason to use them in modern generic code. A better type signature would be HashMap<String, List<Object>>. This is effectively identical, but in practice much easier to work with.
  • Don't use arrays to store different types. You appear to be storing a "Test" string, a identifier string, the element's text, and the text's length as fields in an array. This is what objects are for. Define an object with those four fields, and pass them into the constructor. Even better, since everything but i is computable from the element, just pass the element into the constructor and compute the information you need (HTML string, length, etc.) in the constructor or even in the class' getters.
  • Don't use raw types (Effective Java Item 23) for Iterators and Map.Entrys. Your IDE can warn you when you use raw types so you avoid this common programming error. In your code you should use Iterator<Entry<String, Object[]>> and Entry<String, Object[]>
  • Don't use Iterator to loop over a Map's elements, use a for-each loop:

    for (Entry<String, ...> e : map.entrySet()) {
      ...
    }
    
  • Don't call a Map variable a set; they're different things. Similarly a Map.Entry is not a pair - it specifically represents a key-value relationship.

Here's a cleaned-up version of your code, assuming a Container object exists that takes an Element and extracts the data you need.

doc = Jsoup.connect(url).get();
for (org.jsoup.nodes.Element element : doc.getAllElements()) {
  for (Attribute attribute : element.attributes()) {
    Container c = new Container(i++, attribute);
    data.put(c.getKey(), c);
  }
}

And:

HashMap<String, Container> map = HTMLDocument.createHTMLMap("URL of website");
for (Entry<String, Container> e : map.entrySet()) {
  System.out.println(e.getKey() + " = " + e.getValue());
}
dimo414
  • 47,227
  • 18
  • 148
  • 244
0

The value is array of Object. Try following instead

while (it.hasNext()) {
     Map.Entry pair = (Map.Entry)it.next();
      System.out.println(pair.getKey() + " = " + pair.getValue()[0].toString());

}
Amol Patil
  • 985
  • 2
  • 11
  • 43