The title is probably not the best, I apologize for that.
I have several final static Lists I am using to define defaults for database values. The default list of values should never change, as such when populating them, I use Collections.nCopies(int,T) to obtain an immutable List. These Lists are then used to populate lists in another class with defaults. The values in these Lists are expected to change.
Pseudocode for the class of defaults:
public final class FooDefaults {
public final static List<Integer> LIST_ONE;
public final static List<String> LIST_TWO;
//This map allows easier access to "column" values.
public final static List<Map<String,String>> LIST_THREE;
static {
LIST_ONE = Collections.nCopies(7, 5);
LIST_TWO = Collections.nCopies(10, "boo");
Map<String, String> temp = new java.util.LinkedHashMap<>();
for(int i=0;i<15;i++) {
temp.put(("Param"+i),"foo");
}
LIST_THREE = Collections.nCopies(10, temp);
}
}
Pseudocode for the class of editable values:
public class Foo {
//Keep the reference from changing.
//Prevents an accidental new.
private final List<Integer> listOne;
private final List<String> listTwo;
private final List<Map<String,String>> listThree;
public Foo() {
listOne = new java.util.ArrayList<>(FooDefaults.listOne);
listTwo = new java.util.ArrayList<>(FooDefaults.listTwo);
listThree = new java.util.ArrayList<>(FooDefaults.listThree);
}
}
My concern is that as I have performed a shallow copy on these lists, changes in the lists in Foo, will be visible in the Lists in FooDefaults.
This post: https://stackoverflow.com/a/1685158/1391956 suggests that due to Strings and Integers being immutable, I need not worry about accidentally overwriting the values in FooDefaults.LIST_ONE and FooDefaults.LIST_TWO.
Thus, my primary concern are the values contained within the maps in FooDefaults.LIST_THREE. If I change the values in the maps in Foo's listThree, will the change be visible in FooDefaults?
If so, what would be the most efficient way to handle this? Class Foo is likely to be instantiated over a thousand times and added to a List in another class, thus speed will potentially be an issue.
I originally created the final static lists in FooDefaults in the interest of speed, as it is my (probably incorrect) assumption that creating those Lists in FooDefaults and simply copying the data would be faster than creating them every time Foo is instantiated.
EDIT: If I must perform a Deep Copy I plan on using something similar to:
public static final List<Map<String, String>> getListThreeCopy() {
Map<String,String> temp = new java.util.LinkedHashMap<>();
for(Map.Entry<String, String> entry: LIST_THREE.get(0).entrySet()) {
temp.put(entry.getKey(),entry.getValue());
}
List<Map<String,String>> rtnList = new java.util.ArrayList<>();
for(int i=0;i<LIST_THREE.size();i++) {
rtnList.add(temp);
}
return rtnList;
}
Would there be a faster way?
In the end, I used the code mentioned at the end of my post in a loop to perform a Deep Copy 1,500 times and timed it. I did the same with the instantiation code.
As I somewhat expected, recreating the List from scratch is much faster than a deep copy.
16 milliseconds with the Deep Copy versus 0 milliseconds with instantiation. I timed it using System.currentTimeMillis().
So long as I only create it in a static function, I have little reason to worry about errors.
Related
This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 1 year ago.
I don't understand why after getting value from hashmap and updating hashmap, the local value changing at updated value. I always thought that java works on pass by value not by reference.
#Component
#RequiredArgsConstructor
public class ParametersCompare {
#NonNull
private final ParameterRepository parameterRepository;
public boolean isAnyChange(String object, List<Parameter> currentParameter) {
Map<String, String> parameterHistory = parameterRepository.getHistoricalParameter(object);
parameterRepository.updateParameters(currentParameter, object);
return isAnyChange(parameterHistory, currentParameter);
}
#Service
public class ParameterRepository {
private final Map<String, Map<String, String>> oldParameters = new TreeMap<>();
public void updateParameters(List<Parameter> currentParameters, String object) {
Map<String, String> oldParameters = this.oldParameters.computeIfAbsent(object, s -> new HashMap<>());
updateParameters(currentParameters, oldParameters, object);
}
public Map<String, String> getHistoricalParameter(String object) {
Map<String, String> currentParameters = this.oldParameters.get(object);
if (object == null) {
return Collections.emptyMap();
} else {
return currentParameters;
}
}
private void updateParameters(List<Parameter> currentParameters, Map<String, String> oldParameters, String object) {
currentParameters.forEach(parameter -> oldParameters.put(parameter.getName(), parameter.getValue()));
this.oldParameters.put(object, oldParameters);
}
}
After line
parameterRepository.updateParameters(currentParameter, object);
oldParameters is changing to variable received from currentParameter.
Thanks in advance for pointing why is changing.
best regards
Java is pass-by-value on all fronts, yes, but remember that all non-primitive values are references. For non-primitives, the values you pass around are always treasure maps and never the treasure. = wipes out the old 'X marks the spot' and draws a new X in, and . (as well as [] and a few others, like synchronized(ref)) are java-ese for `follow the X, find a shovel, dig down, and operate on the treasure you find'.
List<String> hello = new ArrayList<String>();
conjures up a new treasure chest out of thin air. Bury it someplace on the vast beach. Like all objects, it has no name.
conjure a treasure map out of new air. It is named hello.
Draw an X on the hello map, marking the position where you buried the chest you made in X.
foo(hello);
Make a copy of your hello map, and hand the copy of the map to foo. If foo reassigns their map (they do param = somethingElse;), your map does not change, as they are operating on their copy. If, however, they follow their map and dig down, well, they find the same treasure you would find on your map:
List<String> list = new ArrayList<String>();
op1(list);
System.out.println(list);
public void op1(List<String> list) {
list.add("HELLO");
}
public void op2(List<String> list) {
list = List.of("HELLO");
}
In this code, it prints HELLO, because op1 follow its map and modified the treasure. If you replace it with a call to op2, nothing is printed; op2 makes new treasure and updates its own map which you will not observe, as java is indeed pass-by-value.
so, how can I use variable from map as value not as reference?
Given that variables are references, you are doing it. Presumably you want: "How do I ensure that the method I hand this map to gets its own clone?" and the answer is pretty much in that restated question: By cloning. There is nothing baked into java, because objects need to represent data concepts that are cloneable in the first place. For example, you can't feasibly clone any InputStream representing an underlying (OS-level) file handle. Also, cloning a huge array or any other object with a large internal data store would then be extremely expensive. Furthermore, any object that has a field of such a non-cloneable type would itself then also be non-cloneable, so non-cloneables are all over the place, and that perhaps explains why java has no baked in support for it.
Most data types where you'd want to make clones DO however have APIs that let you do that:
List<String> original = new ArrayList<String>();
original.add(...);
List<String> clone = new ArrayList<String>(original);
Now clone is a truly full clone. It's a shallow copy, which in this case is irrelevant, as String is an immutable datatype. That means the treasure chest is made from solid titanium - nobody can mess with it or move it, so you can hand out copies of a map that leads to it with wild abandon - it will never effect you. That's why immutable data types are often quite convenient. No worries about cloning and handing out references (=treasure maps).
I am new to java and practicing by creating a simplistic NaiveBayes classifier. I am still new to object instantiation, and wonder what to do to initialize a HashMap of HashMaps. When inserting new observations into the classifier, I can create a new HashMap for an unseen feature name in a given class, but do I need to initialize?
import java.util.HashMap;
public class NaiveBayes {
private HashMap<String, Integer> class_counts;
private HashMap<String, HashMap<String, Integer>> class_feature_counts;
public NaiveBayes() {
class_counts = new HashMap<String, Integer>();
// do I need to initialize class_feature_counts?
}
public void insert() {
// todo
// I think I can create new hashmaps on the fly here for class_feature_counts
}
public String classify() {
// stub
return "";
}
// Naive Scoring:
// p( c | f_1, ... f_n) =~ p(c) * p(f_1|c) ... * p(f_n|c)
private double get_score(String category, HashMap features) {
// stub
return 0.0;
}
public static void main(String[] args) {
NaiveBayes bayes = new NaiveBayes();
// todo
}
}
Note this question is not specific to Naive Bayes classifiers, just thought I would provide some context.
Yes, you need to initialize it.
class_feature_counts = new HashMap<String, HashMap<String, Integer>>();
When you want to add a value to class_feature_counts, you need to instantiate it too:
HashMap<String, Integer> val = new HashMap<String, Integer>();
// Do what you want to do with val
class_feature_counts.put("myKey", val);
Recursive generic data structures, like maps of maps, while not an outright bad idea, are often indicative of something you could refactor - the inner map often could be a first order object (with named fields or an internal map), rather than simply a map. You'll still have to initialize these inner objects, but it often is a much cleaner, clearer way to develop.
For instance, if you have a Map<A,Map<B,C>> you're often really storing a map of A to Thing, but the way Thing is being stored is coincidentally a map. You'll often find it cleaner and easier to hide the fact that Thing is a map, and instead store a mapping of Map<A,Thing> where thing is defined as:
public class Thing {
// Map is guaranteed to be initialized if a Thing exists
private Map<B,C> data = new Map<B,C>();
// operations on data, like get and put
// now can have sanity checks you couldn't enforce when the map was public
}
Also, look into Guava's Mulitmap/Multiset utilities, they're very useful for cases like this, in particular they do the inner-object initializations automatically. Of note for your case, just about any time you implement Map<E, Integer> you really want a Guava Multiset. Cleaner and clearer.
You must create an object before using it via a reference variable. It doesn't matter how complex that object is. You aren't required to initialize it in the constructor, although that is the most common case. Depending on your needs, you might want to use "lazy initialization" instead.
Do not declare your variables with HashMap. It's too limiting.
Yes, you need to initialize class_feature_counts. You'll be adding entries to it, so it has to be a valid map. In fact, initialize both at declaration and not in the constructor since there is only one way for each to start. I hope you're using Java 7 by now; it's simpler this way.
private Map< String, Integer> classCounts = new HashMap<>();
private Map< String, Map< String, Integer>> classFeatureCounts = new HashMap<>();
The compiler will deduce the types from the <>. Also, I changed the variable names to standard Java camel-case style. Are classCounts and classFeatureCounts connected?
I obtain a HashSet from a HashMap and I don't want that my modifications on the HashSet reflect on the HashMap values.
What's the best way of doing something like this :
HashSet<Object> hashset = new HashSet((Collection<Object>) hashmap.values());
//Something like ...
hashset.detach();
//Then i can modify the HashSet without modifying the HashMap values
Edit :
I have to modify an element in the HashSet but I don't want to modify this same element in the HashMap.
Thanks!!!
If you're creating a new HashSet as per the first line of your code snippet, that's already a separate collection. Adding or removing items from the set won't change your hashMap. Modifying the existing items will, of course - but that's a different matter, and will almost always be a Very Bad Thing (assuming your modifications affect object equality).
When you create the HashSet from hashMap.values() like this, then it's already "detached" in the sense that modifying the HashSet will not influence the map it was constructed from.
However, if you modify an object inside the set (for example calling a setter on it), then those changes will be reflected inside the HashMap as well (since the Set and the Map will refer to the same object).
One way around this is to make defensive copies of each element (using clone() or by using a copy constructor).
Another way is to use immutable objects.
You are close:
Set<Object> set = hashmap.values(); // is backed by the map
// create a new hashset seeded from the other set
Set<Object> hashset = new HashSet<Object>(set);
If you are trying to copy the values, and change the state of the values you need to create a deep copy, which relies on knowing how to create copies of the objects held in the Map as values. Hopefuly this test illustrates what I mean.
#Test
public void testHashMap() throws Exception {
final Map<Integer, TestContainer<Double>> hashmap = new HashMap<Integer, TestContainer<Double>>();
final TestContainer<Double> t1 = new TestContainer<Double>(1d);
final TestContainer<Double> t2 = new TestContainer<Double>(2d);
hashmap.put(1, t1);
hashmap.put(2, t2);
// create a separate collection which can be modified
final Set<TestContainer<Double>> hashset = new HashSet<TestContainer<Double>>(hashmap.values());
assertEquals(2, hashmap.size());
assertEquals(2, hashset.size());
hashset.remove(t2);
assertEquals(2, hashmap.size());
assertEquals(1, hashset.size());
// prove that we cannot modify the contents of the collection
hashset.iterator().next().o += 1;
assertEquals(2d, t1.o, 0d);
}
private static final class TestContainer<T> {
private T o;
private TestContainer(final T o) {
this.o = o;
}
}
Try this:
public MyType cloneObject(MyType o) {
MyType clone = new MyType();
// TODO copy the attributes of 'o' to 'clone' return the clone
return clone;
}
public void populateHashSet(HashMap<Object,MyType> hashMap) {
HashSet<MyType> hashSet = new HashSet<MyType>();
for (MyType o : hashMap.values()) {
hashSet.add(cloneObject(o));
}
}
That said, I would be very careful about making copies of objects unless all the attributes of the object are primitive/immutable types. If you just copy an attribute object reference to an object reference in the clone then your 'clone' can still produce side-effects in the original object by changing the objects it references.
I'm new to Java and I need to make a list of lists of lists. I could do it in python because an element of a list can be a list so in an embedded list list[0] would refer to a list and list[0][0] would refer to the zeroeth element of the embedded list. Is there any easy way to implement this behavior in java?
All the other answers are technically correct, but IMHO if you implement a rough List of Lists of Lists you are not treating your data at the right level of abstraction. For example I am pretty sure that a List of Lists already means "something" in your business domain. Encapsulate this "something" in another object so you can just have a List<Something> instead of a difficult to use and maintain List<List<List<Object>>>.
As Mario says, you probably need to abstract out your data a little further. But, the following will do what you need.
In Java you would so something like:
List<List<List<Object>>> listOfListsOfLists =new ArrayList<List<List<Object>>>();
Then to access the items, you would use:
listOfListsOfLists.get(a).get(b).get(c);
Or, to iterate over everything:
for (List<List<Object>> list2: listOfListsOfLists) {
for (List<Object> list1: list2) {
for (Object o: list1) {
// use `o`
}
}
}
Since all of these answers make me barf, can I just add the suggestion that you either
Create a data type to express your data while encapsulating the details of the structure, or at least
Create a key type that wraps an int[] (but overrides equals and hashCode properly) and use a HashMap instead? It's typically rare that your whole 3-dimensional structure will be filled up much anyway.
Even better you could encapsulate that map and use varargs for clean access.
public class NDimensionalArray<V> {
private final int dimensions;
private final Map<Key, V> values = new HashMap<Key, V>();
private NDimensionalArray(int dimensions) {
this.dimensions = dimensions;
}
public V get(int... indices) {
checkIndices(indices);
return values.get(new Key(indices));
}
public void set(V value, int... indices) {
checkIndices(indices);
values.put(new Key(indices), value);
}
private void checkIndices(int[] indices) {
if ( indices.length != dimensions ) {
throw new IllegalArgumentException();
}
}
private static final class Key {
private final int[] indices;
private Key(int[] indices) {
this.indices = indices;
}
#Override
public int hashCode() {
return Arrays.hashCode(indices);
}
#Override
public boolean equals(Object obj) {
return Arrays.equals(indices, ((Key)obj).indices);
}
}
}
If people have examples of established collections libraries that already do this sort of thing, let me know and I'll add links.
While it is certainly true that you can construct a List<List<List<whatever>>> in Java, I can't help but wonder, Why do you want to do this? Not that it's inconceivable that this is the best solution to your problem, but wow, like why?
I guess I could imagine something like
public class Employee ...
List<Employee> store; // all the employees in a store
List<List<Employee>> city; // all the store lists for a city
List<List<List<Employee>>> nation; // all the store lists for the nation
But would you really want to process it that way? I don't know, it depends on what you need to do with it.
A comprehensive example showing List-of-List with collections and generics (Java 1.5+)
// declare the list of lists
List<List<String>> listOfListOfStrings = new ArrayList<List<String>>();
// populate
List<String> listOfStrings = new ArrayList<String>(); // one inner list
listOfStrings.add("one-one");
listOfStrings.add("one-two");
listOfListOfStrings.add(listOfStrings);
listOfStrings = new ArrayList<String>(); // and another one
listOfStrings.add("two-one");
listOfStrings.add("two-two");
listOfListOfStrings.add(listOfStrings);
// access
String oneOne = listOfListOfStrings.get(0).get(0); // first element of first inner list
String twoTwo = listOfListOfStrings.get(1).get(1); // second element of second inner list
In the instructions I have been asked to "declare a interface type to hold a map with sets of characters as its keys, and with sorted sets of strings as values". All this time I have been using TreeSets. Now I am not sure, I am now
thinking of using TreeMap. Code below is demo TreeMap I have used. Firstly is it acceptable to use TreeSet instead of TreeMap as per instruction above. Secondly I am getting an error "non-static variable names cannot be referenced from a static context", when using TreeMap for methodB()? Thanks.
public class MyMates
{
private TreeMap names = new TreeMap();
private static String[] name1 = null;
private static String[] name2 = null;
private static String[] name3 = null;
public MyMates()
{
super();
names = new TreeMap();
}
public static void methodASet()
{
String[] name1 = new String[] {"Amy", "Jose", "Jeremy", "Alice", "Patrick"};
String[] name2 = new String[] { "Alan", "Amy", "Jeremy", "Helen", "Alexi"};
String[] name3 = new String[] { "Adel", "Aaron", "Amy", "James", "Alice" };
}
public static String methodB(String aTemp)
{
for (int i = 0; i < name1.length; i++)
{
names.add(name1[i]);
}
System.out.println(names);
for (int i = 0; i < name2.length; i++)
{
names.add(name2[i]);
}
System.out.println(names);
for (int i = 0; i < name3.length; i++)
{
names.add(name3[i]);
}
System.out.println(names);
return aTemp
}
public static void populateTable()
{
girlFriends myList = new girlFriends();
names.addAll(myList.getNames()); // same error here
}
As R. Bemrose said in a comment, you're not being asked for an implementation, just an interface. So don't worry about the implementation. A map lets you put a value (in your case, a sorted set of Strings) in for a particular key (in your case, a set of characters), and use the same key to retrieve the same value. What would that interface look like? That's the question.
The "non-static variable names cannot be referenced from a static context" is easy to resolve.
You can remove the "static" modifier of your methodB().
Another solution is to declare your class member "names" as static.
Your method methodASet() has a bug !!! You redeclare name1, name2, and name3 as local variables. So the static class members are never set.
A TreeSet and a TreeMap haven't the same function :
A TreeMap is a Map (inteface java.util.Map), that is to say an association key/value (where keys are ordered)
A TreeSet is a Set (interface java.util.Set) : an ordered collection of objects where all objects are unique in the set, without the "key" notion of the Map.
So, you have to choose the representation (Map or Set) in relation with your needs (access to the objects by a key or not).
It looks like private TreeMap names isn't static so it can't be accessed from a static method. Perhaps you need to brush up on your static variables/methods? http://leepoint.net/notes-java/flow/methods/50static-methods.html
You have to remember that methodASet and methodB are different methods and variables in methodASet cannot be seen by methodB. When you declare String[] name1 you're making a new variable of type String[], not using the class variable name1 (the one you set to null). Remove the "String[]" from the variables in methodASet to reuse the class variables.
Thinking about it, does TreeMap even have add() methods? I think you might want to switch to the aforementioned TreeSet or change your add() methods to put().
For populateTable(), are you sure that girlFriends is a type? Where is it coming from? Are you sure you don't mean for myList to be of a standard java collections type?
Hope my (mostly convoluted) post helps!
Edit: Blast! I think you're right. It looks like he's only got to write the interface, not the implementation.
Edit: Static examples
Static method:
Class.doSomething()
Static variable:
Class.count_something
Class method:
ObjectType obj = new ObjectType()
obj.doSomething()
Class variable:
ObjectType obj = new ObjectType()
obj.count_something
This is kind of an aside since it looks like your instructions actually want you to create an interface, not an implementation. However, given the task of implementing this interface, if consistently using Java terminology (map, set, character and string), the instructions seem to want you to maintain this data structure:
Map<Set<Character>, SortedSet<String>> map;
If that's the case, a TreeMap is not a good choice of implementation since it is very difficult to enforce an ordering on non-sorted Sets. Set doesn't implement Comparable for starters and creating a Comparator for your TreeMap would require some complex logic.
If the above is what your instructor is expecting, I would suggest using a HashMap which has no problem using a Set as a key type:
map = new HashMap<Set<Character>, SortedSet<String>>();