0

My question: Why is linkedhashmap returning an object when I am expecting a string (perhaps my expectations are incorrect?), and how can I compare if a string value "line" contains the value of the linkedHashMap "sections"? I am defining the linked hash map as follows...

 LinkedHashMap<String, String> sections;
 sections = new LinkedHashMap();

Then, I have collected lines of text from a pdf. If certain conditions are met, II split the text on a white space putting the numerical value "#######" as the key and the rest of the line as the value...

 if (tocStartFound == true && tocEndFound == false) {
     if (line.matches("\\d{6}.+")){
     String lineSplit[] = line.split("\\s",2);
     sections.put(lineSplit[0], lineSplit[1]);
 }

Now, when i ask if line.contains(nextSection) I am told an "object cannot be converted to a charSequence."

if (sectionStarted == true){
    Set set = sections.entrySet();
    Iterator iter = set.iterator();
    boolean foundName = false;
    Object nextSection;
    while(iter.hasNext()){
        Map.Entry me = (Map.Entry)iter.next();
        if (foundName == true){
            nextSection = me.getValue();
            nextSection = nextSection.toString();
            break;
        }
        if (sectionName == me.getValue()) {
            foundName = true;
        }
}

Pattern pa = Pattern.compile(".+((?i)end of section).+");
Matcher ma = pa.matcher(line);
if (ma.find() || line.contains(nextSection)){
    System.out.println("End of Section");
    sectionStarted = false;
}

I guess I thought by defining the map with <string,string>, i was enduring that the data would be typed as strings. Best regards and thanks for the help...

Skinner
  • 1,461
  • 4
  • 17
  • 27
  • 1
    How is `nextSection` declared? What type? Does the method `String#contains` expect that type? – Sotirios Delimanolis Jan 22 '15 at 02:33
  • It is declared directly above the while(iter.hasnext()) loop, in this example - as an object. BUT, previously declared as a String im am told "object cannot be converted to a string" on the "nextSection = me.getValue();" statement. I assume because nextSection is identified as a string, but me.value() is an object? – Skinner Jan 22 '15 at 02:39
  • I clearly see `Object nextSection;`. So what is the declared type of `nextSection`? – Sotirios Delimanolis Jan 22 '15 at 02:40
  • So yes, changing the declaration to a String solves one problem, but creates another - but both are related to type incompatibility. – Skinner Jan 22 '15 at 02:41

2 Answers2

2

You should avoid raw types. Also for more flexibility of code prefer more general type for reference over precise one. So instead of

LinkedHashMap<String, String> sections;
sections = new LinkedHashMap();

use

Map<String, String> sections;
sections = new LinkedHashMap<>();// <> in short: represents 
                                 // generic type of reference

BTW you can rewrite above code in one line

Map<String, String> sections = new LinkedHashMap<>();

Now as said earlier you should avoid raw types, so instead of

Set set = sections.entrySet();

you need to specify what elements this Set should contain. In this case use

Set<Entry<String, String>> set = sections.entrySet();

Now I am not sure why you are using Iterator manually, but main purpose of existence Iterable interface which lets some classes return Iterator is to be used in enhanced-for-loop, so instead of

Iterator<Element> iter = someCollection.iterator();
while(iter.hasNext()){
    Element element = iter.next();
    //...
}

you can simply use

for (Element element : someCollection){
    //...
}

which in your case would be

for (Map.Entry<String, String> me : set){
    ...
}

Now since compiler knows that Entry is of type where key and value are Strings, it can assume that me.getEntry() will return String, so you no longer need to declare nextSection as Object and invoke toString() on it to get its String value, but you can simply use

String nextSection;
...
nextSection = me.getValue();

Because earlier nextSection was Object line.contains(nextSection) couldn't accept it as argument (Object reference can hold any kind of objects like Set, List, Car, Cow, or whatever you think of) because it expects CharSequence like String. Since now nextSection will be declared as String your problem will disappear.

Also you shouldn't compare content of Strings with == because it compares references. You should use equals method like someString.equals(someOtherString)(more info here: How do I compare strings in Java?).

Last thing is matter of coding style. You should avoid

if (condition == true){...}

because it can easily be mistakenly written as

if (condition = true){...}//notice one `=` not `==`

and because = is assignment it will first assign true to condition which means that this if will always execute its code.
To avoid such problems simply write

if (condition){...}

and in case of negation instead of if (foundName == false) you can use

if (!condition){...}
Community
  • 1
  • 1
Pshemo
  • 122,468
  • 25
  • 185
  • 269
1

Here's the official tutorial on Generics in Java. Read it.


You've used a parameterized type with sections, but stopped using it after

Set set = sections.entrySet();
Iterator iter = set.iterator();
Map.Entry me = (Map.Entry)iter.next();

These are raw types and should rarely be used. Parameterize them correctly (and change the type of nextSection to String) and you'll be fine with type checking.

Set<Entry<String, String>> set = sections.entrySet();       
Iterator<Entry<String, String>> iter = set.iterator();
boolean foundName = false;
String nextSection;
while(iter.hasNext()){
    Map.Entry<String,String> me = iter.next();
    if (foundName == true){
        nextSection = me.getValue();
        nextSection = nextSection.toString();
        break;
    }

Then remember that you have to use String#equals(Object) to compare String values.

Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724