Copy ObservableList java

Mansueli picture Mansueli · Jun 27, 2014 · Viewed 10.4k times · Source

I have a masterData which is an ObservableList and filteredData which is also an ObservableList.

Then, I want to use it to show the filtered data when the filter is set, but also to be able to recover whenever necessary. Here is the MCVE:

package br;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class Main{
    private static ObservableList<Foo> masterData = FXCollections.observableArrayList();
    private static ObservableList<Foo> filteredData = FXCollections.observableArrayList();
    static Filter filter = new Filter();
    public static void addDummy(){
        masterData.add(new Foo("a",1));
        masterData.add(new Foo("aa",3));
        masterData.add(new Foo("b",2));
        masterData.add(new Foo("bb",4));
        masterData.add(new Foo("c",3));
    }
    public static void printData(ObservableList<Foo> list){
        for(Foo f: list) System.out.println(f.getName());
    }
    public static void main(String[] args) {
        addDummy();
        applyFilter(3);
        printData(filteredData);
        applyFilter(0);
        printData(filteredData);
    }
    public static void applyFilter(int num){
        filter.setData(masterData);
        filter.setFilter(num);
        filteredData = filter.getData();
    }
}

The class filter, which I use to filter the data:

package br;

import java.util.ArrayList;
import java.util.List;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;

public class Filter {
    private ObservableList<Foo> data = FXCollections.observableArrayList();
    public void setFilter(int filter){
        List<Foo> copy = new ArrayList<Foo>(data);
        for(Foo f: copy)
            if(f.getBar()<filter) data.remove(f);
    }
    public ObservableList<Foo> getData() {
        return data;
    }

    public void setData(ObservableList<Foo> data) {
        this.data = data;
    }

}

And the Foo class, which is just a [String] name and a [int] bar (plus getters /setters)

package br;

public class Foo {
    private String name;
    private int bar;
    public Foo(String name, int bar){
        this.setBar(bar);
        this.setName(name);
    }
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public int getBar() {return bar;}
    public void setBar(int bar) {this.bar = bar;}
}

When you run this code, you will get:

aa
bb
c

Both when the filter was set to 3 (which filtered the data as expected) and after the filter was "reset" to zero.

How can I make sure the filter is always processed with the data in the masterData and then stored on the filteredData ?

Note: this is for a JavaFX project, so I really need to use the ObservableList.

Answer

ItachiUchiha picture ItachiUchiha · Jun 27, 2014

Problem

public void setData(ObservableList<Foo> data) {
    this.data = data;
}

Explanation

In case you are wondering that Java obeys Pass By Value and the value of masterData should have been copied to the list data. You are correct ! But there is just a little twist to the story !

In case of primitives, the values are passed but in case of objects, Object references are passed by value.

So, you are referencing to the Object of the masterData, instead of copying the values to a new List !

Solution

this.data = FXCollections.observableArrayList(data);

This will create a new Object for data to refer and all the manipulations will be done on this new object's data.