Can someone explain what the following does?
private HashSet nodes[];
nodes = new HashSet[21];
I'm a little confused... in the difference between
private HashSet nodes = new HashSet;
and the above, particularly in terms of the square brackets syntax. Is this an array of HashSets? Because normally I'm used to seeing
int[] myarray = new int[21];
Or something like that.
They're just alternatives - both are valid, unfortunately.
Heck, even this would be valid:
int[] bad [] = null;
That's equivalent to
int[][] bad = null;
Don't do this, obviously :)
From section 10.2 of the JLS:
The [] may appear as part of the type at the beginning of the declaration, or as part of the declarator for a particular variable, or both.
And
We do not recommend "mixed notation" in an array variable declaration, where brackets appear on both the type and in declarators.
Basically, use the form that keeps all the type information in one place - the form you're used to. That's the overwhelmingly idiomatic form.
private HashSet nodes = new HashSet;
is not valid Java. Unlike JavaScript, the new operator in Java always requires a parenthesized argument list.
private HashSet nodes = new HashSet(21);
differs from
private HashSet[] nodes = new HashSet[21];
in that the former constructs one HashSet set that initially has space enough for 21 set items while the latter is an array of 21 null values that can be filled with references to sets.
private HashSet nodes[];
declares a member variable that can refer to any array whose elements are of type HashSet.
nodes = new HashSet[21];
creates an array with space for 21 HashSet references and assigns it to that member variable.
Remember that in Java, unlike in C, HashSet[21] is not a type so you can't just allocate space for an array in Java by doing
int[21] myints;
At some point you have to create an array via
new <type>[size],
the abbreviated syntax new <type> { element0, element1, element2, ... },
or reflectively via java.lang.reflect.Array.newInstance.
Yes, it is an array of HashSets.
HashSet nodes[];
is the same as
HashSet[] nodes;
The difference in where you place the brackets only becomes important when you use commas to declare a bunch of variables at a time:
HashSet[] alpha, bravo, charlie; // Three arrays of hashsets
HashSet delta[], echo, foxtrot; // One array (delta) and two hashsets (echo and foxtrot)
In Java, the declaration
private HashSet nodes[];
is equivalent to the declaration
private HashSet[] nodes;
It can be pronounced "an array of HashSets" or "a HashSet array."
Related
In Java we may create IntFunction<String[]> from 1D array constructor reference:
// both do the same thing
IntFunction<String[]> createArrayL = size -> new String[size];
IntFunction<String[]> createArrayMR = String[]::new;
Now I wonder why we cannot do this with a 2D array:
BiFunction<Integer, Integer, String[][]> createArray2DL =
(rows, cols) -> new String[rows][cols];
// error:
BiFunction<Integer, Integer, String[][]> createArray2DMR =
String[][]::new;
Of course we may write:
IntFunction<String[][]> createArray2DInvalidL = String[][]::new;
System.out.println(createArray2DInvalidL.apply(3)[0]); // prints null
but this will behave differently than:
new String[3][3]
because row arrays will not be initialized.
So my question is: why String[][]::new doesn't work for 2D arrays (for me it looks like an inconsistency in language design)?
Quite an interesting case indeed.
The problem is that String[][]::new is a function with an arity of 1(it's a constructor of an array of arrays) and can't be treated as a BiFunction(arity of 2) and your example new String[3][3] has two parameters instead of one.
In this case,
createArray2DInvalidL.apply(3)
is equal to calling new String[3][];
What you might be looking for is:
IntFunction<String[][]> createArray2D = n -> new String[n][n];
Dimensions don't need to have equal lengths and it sounds like a pretty reasonable assumption.
http://4comprehension.com/multidimensional-arrays-vs-method-references/
There is no inconsistency here. If you write a statement like
IntFunction<ElementType[]> f = ElementType[]::new;
you create a function whose evaluation will return a new array with each entry being capable of holding a reference of ElementType, initialized to null. This doesn’t change, when you use String[] for ElementType.
But it also has been addressed explicitly in The Java Language Specification, §15.13.3. Run-Time Evaluation of Method References:
If the form is Type[]k :: new (k ≥ 1), then the body of the invocation method has the same effect as an array creation expression of the form new Type [ size ] []k-1, where size is the invocation method’s single parameter. (The notation []k indicates a sequence of k bracket pairs.)
There is no support for a rectangular multi-dimensional array creation method reference, most likely, because there is no actual use case that acted as a driving force. The one-dimensional array creation expression can be used together with Stream.toArray(…), allowing a more concise syntax than the equivalent lambda expression, despite there is no special support in the underlying architecture, i.e. int[]::new produces exactly the same compiled code as intArg -> new int[intArg]. There is no similar use case for a two (or even more) dimensional array creation, so there isn’t even a similar functional interface for a function consuming two or more int value and producing a reference type result.
While designing a small API, i was about to write a static value that references to an array of String:
public static final String[] KEYS={"a","b","c"}
I have found this to be marked as a 'security hole' in Joshua Bloch's 'Effective Java' item 14, where he proposes as an alternative, declaring te array 'private' and provide a public getter that returns an unmodifiable list:
return Collections.unmodifiableList(Arrays.asList(KEYS))
I just cant see why would this be necessary, the array in the initial statement is declared final even though its public, and its elements are immutable, how could that be modified from an external piece of code?
The array is not immutable.
You can still write:
KEYS[0] = "d";
without any issues.
final just means you cannot write:
KEYS = new String[]{"d"};
I.e. you cannot assign a new value to the variable KEYS.
final means
You can't change the Basket. Still you can change the fruits inside.
Basket is your Array instance. Fruits are your keys inside.
In first case, from somewhere else in the code, I can do
ClassName.KEYS[2] ="MyOwnValue";
But you can't modify when it is unmodifiable list.
Give a shot to read : Why final instance class variable in Java?
While the array reference itself is immutable (you cannot replace it with a reference to another array) and the Strings themselves are immutable too it is still possible to write
KEYS[0] = "new Key";
A composite object ( array , Set , List etc ) being final doesn't mean that its constituent objects will not be changed - you can still change constituent objects . final for a composite object simply means that its reference can't be changed.
For your case, value of KEYS can't be changed but KEYS[0] etc can be changed.
I have several objects I want to store in an arrayList that represents a single assembly language instruction (eg Add, Jump, etc). The objects in each ArrayList are constant for a given instruction, so I just need to load each of the objects for a given instruction into the proper arrayList once at load time.
The tedious part is that I need to name each of the objects before they're added to the arrayList:
static {
...
ArrayList<CodeFrag[]> intIntGtrEqlProtoCode = new ArrayList<CodeFrag[]>();
...
intIntGtrEqlProtoCode.add(intIntGtrEqlInst1);
CodeFrag[] intIntGtrEqlInst2 = {Subtract};
intIntGtrEqlProtoCode.add(intIntGtrEqlInst2);
CodeFrag[] intIntGtrEqlInst3 = {Duplicate};
...
}
I have a feeling like there is a way to avoid doing all this extremely tedious naming. Can someone point it out to me?
You could do something like this:
CodeFrag[] arr = {Subtract, Duplicate, Foo, Bar};
for (CodeFrag c : arr)
intIntGtrEqlProtoCode.add(new CodeFrag[]{c});
Also, if all of the arrays have length 1, couldn't you replace it with a List<CodeFrag>? Then you could just do
intIntGtrEqlProtoCode = new ArrayList<CodeFrag>(Arrays.asList(Subtract, Duplicate, Foo, Bar));
I know that when I initialize a char array:
I have to
char[] b= new char[5];
or
char[] b= new char[5]({1,2,3,4,5});
why not like
ArrayList<Charset> list = new ArrayList<Charset>();
initialize array :
char[] b = new char[5](); ?
Why they are different? Is it one of java philosophical nature or some reasons behind it ?
If you've ever used C, then the answer is fairly simple. In C, the way you create arrays is by allocating a static length of memory on the stack that is large enough to contain the number of elements, and point to the first element with a pointer - or dynamic length of memory on the heap, and point to the first element with a pointer.
int a[5]; //stack, static allocation
int* a = (int*)malloc(sizeof(int)*5)); //heap, dynamic allocation
And in C++, the second version was changed to this, obviously because it's more obvious what is happening:
int* a = new int[5];
And they took this type of array creation over to Java.
int[] a = new int[5];
Arrays don't really work like typical objects, hence why even creating them and manipulating them with reflection uses a different Array class in order to manipulate the object. (see http://docs.oracle.com/javase/tutorial/reflect/special/arrayInstance.html )
ArrayLists are different, because they're just everyday classes like most things in java, so you initialize them with an actual constructor call:
List<T> = new ArrayList<T>();
Basically, arrays and classes just work in different ways.
That's is simply design of Java. ArrayList and Arrays are two different things. No need to be same declaration.
I guess the guys who created Java wanted to keep a syntax close to the C syntax. In Java, arrays are minimalist low-level objects, so their case is a bit particular.
ArrayList is a container, it's similar as Vector in C++, it can add and remove elements, but array can't change its size
Arrays and ArrayList are used for different purposes. If you need a fixed size collection of objects then go for array but if you need dynamically growing collection of objects then go for arraylist. In some way compiler need to know about what is your need, hence the syntax is different.
I can declare an array of maps using generics to specify the map type:
private Map<String, Integer>[] myMaps;
However, I can't figure out how to instantiate it properly:
myMaps = new HashMap<String, Integer>[count]; // gives "generic array creation" error
myMaps = new HashMap[count]; // gives an "unchecked or unsafe operation" warning
myMaps = (Map<String, Integer>[])new HashMap[count]; // also gives warning
How can I instantiate this array of maps without getting a compiler error or warning?
Update:
Thank you all for your replies. I ended up going with the List suggestion.
Not strictly an answer to your question, but have you considered using a List instead?
List<Map<String,Integer>> maps = new ArrayList<Map<String,Integer>>();
...
maps.add(new HashMap<String,Integer>());
seems to work just fine.
See Java theory and practice: Generics gotchas for a detailed explanation of why mixing arrays with generics is discouraged.
Update:
As mentioned by Drew in the comments, it might be even better to use the Collection interface instead of List. This might come in handy if you ever need to change to a Set, or one of the other subinterfaces of Collection. Example code:
Collection<Map<String,Integer>> maps = new HashSet<Map<String,Integer>>();
...
maps.add(new HashMap<String,Integer>());
From this starting point, you'd only need to change HashSet to ArrayList, PriorityQueue, or any other class that implements Collection.
You can't safely create a generic array. Effective Java 2nd Edition goes into the details in the chapter on Generics. Start at the last paragraph of page 119:
Why is it illegal to create a generic
array? Because it isn’t typesafe. If
it were legal, casts generated by the
compiler in an otherwise correct
program could fail at runtime with a
ClassCastException. This would violate
the fundamental guarantee provided by
the generic type system.
To make this more concrete, consider
the following code fragment:
// Why generic array creation is illegal - won't compile!
List<String>[] stringLists = new List<String>[1]; // (1)
List<Integer> intList = Arrays.asList(42); // (2)
Object[] objects = stringLists; // (3)
objects[0] = intList; // (4)
String s = stringLists[0].get(0); // (5)
Let’s pretend that line 1, which
creates a generic array, is legal.
Line 2 creates and initializes a
List<Integer> containing a single
element. Line 3 stores the
List<String> array into an Object
array variable, which is legal because
arrays are covariant. Line 4 stores
the List<Integer> into the sole
element of the Object array, which
succeeds because generics are
implemented by erasure: the runtime
type of a List<Integer> instance is
simply List, and the runtime type of a
List<String>[] instance is List[], so
this assignment doesn’t generate an
ArrayStoreException. Now we’re in
trouble. We’ve stored a List<Integer>
instance into an array that is
declared to hold only List<String>
instances. In line 5, we retrieve the
sole element from the sole list in
this array. The compiler automatically
casts the retrieved element to String,
but it’s an Integer, so we get a
ClassCastException at runtime. In
order to prevent this from happening,
line 1 (which creates a generic array)
generates a compile-time error.
Because arrays and generics don't combine well (as well as other reasons), it's generally better to use Collection objects (in particular List objects) rather than arrays.
In general it is not a good idea to mix generics and arrays in Java, better use an ArrayList.
If you must use an array, the best way to handle this is to put the array creation (your example 2 or 3) in a separate method and annotate it with #SuppressWarnings("unchecked").
You can create generic array of map
Create list of map.
List<Map<String, ?>> myData = new ArrayList<Map<String, ?>>();
Initialize array.
Map<String,?>[]myDataArray=new HashMap[myData .size()];
Populate data in array from list.
myDataArray=myData.toArray(myDataArry);
Short answer appears to be that you really just can't.
See the following for a blog about it.
http://www.bloggingaboutjava.org/2006/01/java-generics-quirks/
One of the comments to the blog states that:
Actually, the engineers made the creation of such an Array illegal. So the creation of an array from generic Class fails. The Collection.toArray method followed by a Cast to the Array works at compile time.
This solves not the problem, that the ArrayStoreCheck can’t be done during Runtime, but you can create an Array of generics in this way.
As suggested by Bill the Lizard, you probably are better off using a
List<Map<String,Integer>>
I know its a bit late to reply but I found this workaround helpful for my case...Hope it helps!
Use an array of HashMap to store HashMaps..
public static void main(String[] args) {
HashMap[] arr = new HashMap[1];//creating an array of size one..just for sake of example
HashMap<String, String> arrMap = new HashMap<String, String>();
//use loops to store desired key-value pairs into the HashMap which will be stored inside the array
arrMap.put("ABC", "Name");
//use loop to store your desired hashMap into the array at a particular index
arr[0] = arrMap;
//desired manipulation of the stored array.
System.out.println(arr[0]);
}
myMaps = new HashMap<String, Integer>[10]();
So that's Wrong
Why not make a List of Maps instead of trying to make an array?
List<Map<String, Integer>> mymaps = new ArrayList<Map<String, Integer>>(count);