0

I have a string named "var" where the text string is set as doc1, doc2 or doc3

String var = "doc2" // doc1 or doc2 or doc3

I get content from the website using Jsoup this way

Document doc_comp = Jsoup.connect("http://www.computer.org").get();            
        Elements doc1_comp  = doc_comp.select("ul > doc1" );                                
        Elements doc2_comp  = doc_comp.select("ul > doc2" );
        Elements doc3_comp  = doc_comp.select("ul > doc3" );

I use switch case for the corresponding values to be printed

       switch(var)
        {
        case "doc1": System.out.println(doc1_comp.text());
        break;
        case "doc2":System.out.println(doc2_comp.text());
        break;
        case "doc3":System.out.println(doc3_comp.text());
        break;
        default: System.out.println("no info");
        }

Everything works perfectly fine with the switch case but I want to use a single line of code to replace switch case like this

System.out.println(var.concat("_comp.text()"));

but it straight away prints as a string "var_comp.text()" but does not execute it and print the content inside it.

Is there a way around to make it run

Vinay Potluri
  • 525
  • 1
  • 7
  • 23

4 Answers4

0

You can use a Ternary operator which will replace the switch statement into one line of code, but using ternary operator doesn't make it faster or efficient than switch statement.

sample:

System.out.println(var.equals("doc1") ? doc1_comp.text() : (var.equals("doc2") ? doc2_comp.text() : ( var.equals("doc3") ? doc3_comp.text() : "no info" ) ));
Rod_Algonquin
  • 25,268
  • 6
  • 47
  • 61
0

I think the switch statement is good(in fact best option). But if you really want to execute string contents, you can achieve it by using a lightweight scripting framework like java script or bean shell.

I will discourage it over something which can be achieved with in java, but there certainly are some cases where using scripting frameworks as glue is really required.

see below example using javascript:

package com.demo.test;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class ScriptTest {

    public static void main(String[] args) throws ScriptException {
        ScriptEngine jse = new ScriptEngineManager()
                .getEngineByName("javascript");
        Bindings bindings = jse.getBindings(ScriptContext.ENGINE_SCOPE);
        ScriptTest test = new ScriptTest();
        bindings.put("test", test);
        String preFix = "demo";
        jse.eval("test." + preFix + "_test()");
        preFix = "actual";
        jse.eval("test." + preFix + "_test()");
    }

    public void demo_test() {
        System.out.println("demo test");
    }

    public void actual_test() {
        System.out.println("actual test");
    }
}

This certainly is not a single line solution as it needs the script environment to be set. Also you need to take care of object passing in two contexts

Note: this will affect the performance severely. (execution namespace switching is costly)
personally I prefer beanshell over javascript, its performance is a bit better but then you need to include its dependent jars (although small footprint) which is not the case with javascript which runs out of the box.

Shail016
  • 5,907
  • 1
  • 17
  • 25
0

You can use the var directly in your doc_comp.select() method and in your System.out.println() method. For example:

String var = "doc2" // doc1 or doc2 or doc3
Document doc_comp = Jsoup.connect("http://www.computer.org").get();            
Elements doc_comp_var  = doc_comp.select("ul > " + var);
System.out.println(doc_comp_var.text());
fajarkoe
  • 1,483
  • 9
  • 10
0

You could use reflection, but that isn't very performant, usually adds complexity and makes code less safe.

I might be misunderstanding exactly what you're trying to achieve, but I think it'd be simplest to put all those document Elements into a HashMap<String, Elements>. It wouldn't make a one-liner, but it'd perform better than Reflection, and makes the code more concise. Like so:

Document doc_comp = Jsoup.connect("http://www.computer.org").get(); 

Map<String, Elements> map = new HashMap<>();

for(int i=1; i < 4; ++i) {
    map.put("doc" +i+ "_comp", doc_comp.select("ul > doc"+i) );                                
}

and then:

Elements elem = map.get(var + "_comp");
if( elem != null ) {
    System.out.println( elem.text() );
}
else {
    System.out.println("no info");
}

In general, if you want to "dispatch" certain methods based on Strings and want to avoid reflection, then a reasonable approach is to design an interface, put class instances that implement that interface into a Map, and perform map look-ups to perform the dispatching.

ie.

public interface MyInterface {
    public void doSomething();
}

public class A implements MyInterface {
    @Override
    public void doSomething() {
        System.out.println("do something class A");
    }        
}

public class B implements MyInterface {
    @Override
    public void doSomething() {
        System.out.println("do something class B");
    }
}

You then create a "dispatch map" (possibly during application start up):

Map<String, MyInterface> dispatchMap = new HashMap<>();
dispatchMap.put("thingA", new A());
dispatchMap.put("thingB", new B());
dispatchMap.put("thingX", new A()); // etc...

And have a method that uses the dispatch map to look-up the code to execute:

public void doSomethingBasedOnString(String thingName) {

    MyInterface code = dispatchMap.get(thingName);

    if( code != null ) {
        code.doSomething();
    }
    else {
        // dynamic code lookup failed
    }
}

Later client code can dynamically execute methods using your dispatch mechanism:

doSomethingBasedOnString("thingB");    // outputs: "do something class B"
Matt Coubrough
  • 3,343
  • 2
  • 23
  • 37