1

I am trying to convert the python code provided by our instructor into the equivalent Java code. This portion of code is supposed to read from a txt file, parse the data with regex, and store them as an array of words. A restriction for this exercise is that the "data_storage_obj" is used to imitate JavaScript Object, and we have to keep them in that key-value format.

The instruction indicates that a data structure in Java that is closest to a JavaScript Object is "HashMap". However, because key each maps to a different data structure for storing the corresponding information, the best type I can think of so far is "Object". However, one of the keys maps to a lambda function, so I get this error message saying "error: incompatible types: Object is not a functional interface". I'm wondering what type I should be using to cover all the types I am going to store as the map values.

A snippet of code provided by the instructor:

def extract_words(obj, path_to_file):
    with open(path_to_file) as f:
        obj['data'] = f.read()
    pattern = re.compile('[\W_]+')
    data_str = ''.join(pattern.sub(' ', obj['data']).lower())
    obj['data'] = data_str.split()

data_storage_obj = {
    'data' : [],
    'init' : lambda path_to_file : extract_words(data_storage_obj, path_to_file),
    'words' : lambda : data_storage_obj['data']
}

data_storage_obj['init'](sys.argv[1])

Java code I have been working on:

public class Twelve{
    static void extract_words(Object obj, String path_to_file){
        System.out.println("extract_words()");
        if(obj instanceof HashMap){
            HashMap<String, Object> hashMap = (HashMap<String, Object>) obj;
            String file_data = "";
            try {
                file_data = (new String(Files.readAllBytes(Paths.get(path_to_file)))).replaceAll("[\\W_]+", " ").toLowerCase();
            } catch (IOException e) {
                e.printStackTrace();
            }
            hashMap.put("data", Arrays.asList(file_data.split(" ")));
            obj = hashMap;
        }
    }

    static HashMap<String, Object> data_storage_obj = new HashMap<>();

    public static void main(String[] args){
        ArrayList<String> data = new ArrayList<String>();
        data_storage_obj.put("data", data);
        data_storage_obj.put("init", path_to_file -> extract_words(data_storage_obj, path_to_file));
        data_storage_obj.put("words", data_storage_obj.get("data"));
    }
}

  • Note that you are not properly translating your python code. The python code *mutates* the first parameter, it doesn't *assign* to it. You are trying to make an assignment to your parameter. As for your error, you simply have to cast the lambda to an appropriate type - the one you'll be using when you write your main function. – RealSkeptic Apr 28 '19 at 10:22
  • @realSkeptic does the dupe really answer the question? – Jonas Wilms Apr 28 '19 at 10:40
  • @Jonas It answers the main part, which is why the OP is getting the error they mentioned. Of course, there are other problems with the translation, as I already mentioned, but once proper casting is used for the lambdas, they can debug the rest of it. – RealSkeptic Apr 28 '19 at 10:47
  • @realSkeptic "proper casting" ... are you really recommending casting Runnable to Object and then Object back to Runnable when calling? Also I don't see how the duplicate addresses that. – Jonas Wilms Apr 28 '19 at 10:48
  • @JonasWilms Given the constraints of the exercise, that seems to be the only option. It's not something I would do in any real-life project, but homework questions are not real-life projects. – RealSkeptic Apr 28 '19 at 10:51
  • @realSkeptic I still disagree. Reopening ... Duplicate was: https://stackoverflow.com/questions/26828246/why-cant-i-assign-lambda-to-object – Jonas Wilms Apr 28 '19 at 10:56
  • thank you guys for the responses, but because **Runnable** does not take any parameters, I'm trying to figure it out by using **Consumer** – Tiffany Tseng Apr 28 '19 at 23:59
  • It's not supposed to be Runnable. You need `Consumer` for the first lambda, and you missed the second lambda, `words`, which should be a `Supplier`. The issue is not about *which* functional interface you should have, but about being aware that you need to tell the lambda which interface it is before you can assign it to Object. – RealSkeptic Apr 29 '19 at 08:02

1 Answers1

0

To represent an object with "static" properties, you can use a Singleton:

  class DataStorage {
    ArrayList<String> data = new ArrayList<String>();

    void init(String pathToFile) { // ¹
     // ²
     try {
      this.data = (new String(Files.readAllBytes(Paths.get(pathToFile)))).replaceAll("[\\W_]+", " ").toLowerCase();
     } catch (IOException e) {
      e.printStackTrace();
     }            
    }

    ArrayList<String> getWords() { // ³
     return this.data;
    }
 }

When transpiling from a scripting language (Python, JavaScript) into a statically typed language (Java), you cannot just keep the dynamic structure. Instead you have to add adequate types, and as Java only has classes, you need another class here.

When transpiling, you should adapt the common practices from the language you are transpiling into:

¹: Use camelCase for methods / variables.

²: As there are no standalone functions in Java, extract_words could be directly merged with the init method (or you add it as a static method to DataStorage).

³: As there are no real getters/setters in Java, you have to fall back to the "method as getter" pattern.

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • 1
    How does that answer the question? – RealSkeptic Apr 28 '19 at 10:19
  • @realSkeptic "I'm wondering what type I should be using to cover all the types I am going to store as the map values." – Jonas Wilms Apr 28 '19 at 10:20
  • The OP said explicitly that they are instructed to keep a name-value data structure (hence asking what type the **value** should be). Anyway, what you presented is certainly not a Singleton. – RealSkeptic Apr 28 '19 at 10:25
  • @realSkeptic because I havent made the constructor private? If they are instructed like this, the instruction is wrong. – Jonas Wilms Apr 28 '19 at 10:27