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?

8
  • You should know the type of object to iterate. Commented Dec 21, 2015 at 7:01
  • 1
    The value is array of Object objects. Commented Dec 21, 2015 at 7: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. Commented Dec 21, 2015 at 7: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). Commented Dec 21, 2015 at 7: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. Commented Dec 21, 2015 at 7:05

4 Answers 4

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.

Sign up to request clarification or add additional context in comments.

5 Comments

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.
@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.
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?
@mk08 Sure, you can pass the result of Jsoup to the constructor of the class where you actually create the new class.
Oh yes, that explains it. Thanks a ton!
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;
    }
}

1 Comment

Thanks for the detailed example. Will try to adopt it as per my requirement.
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());
}

1 Comment

Thanks a lot for detailed explanation and clearing the concept.!
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());

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.