Java Forum / General / March 2008
Generics
Todd - 06 Mar 2008 14:47 GMT Hello,
I have been reading about generics to determine if there is a way to accomplish what I _assumed_ could be done. From what I can tell, what I would like to do is not possible, but, honestly, generics are confusing to me.
What I would like to do is have one method, say getValue(), that returns each member of a mixed collection in its correct type. I have determined the the object type when storing it into the map, so it is available to me for use in the getValue() method. I thought that something along the lines of
public <T> T getValue() { return ObjectType.cast( value ); }
would work. However, I am having no luck coming up with anything that compiles, let alone runs, to return typed objects at runtime using a single method.
I have searched through the group, but have not found anything that clarifies for me whether this concept can be implemented.
Is there a way to return typed objects from a mixed collection at runtime using a single method? If so, could you provide me some tips as to how to create the method or class with method to do so?
Thanks in advance, Todd
Daniel Pitts - 06 Mar 2008 15:27 GMT > Hello, > [quoted text clipped - 27 lines] > Thanks in advance, > Todd Generics are determined either by the caller, or by the instantiater, not by the returner. Now, if did this:
public <T> T getValueAs(Class<T> type) { return type.cast(value); }
you might have better luck.
Or, better off:
class MyRef<T> { T value; public MyClass() { }
public void setValue(T value) { this.value = value; }
public T getValue() { return value; } }
MyRef<String> string = new MyRef<String>(); string.setValue("Hello!");
assert string.getValue().equals("Hello!");
What is it exactly that you are trying to do? I mean, what feature are you adding that needs this?
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Todd - 06 Mar 2008 15:41 GMT On Mar 6, 8:27 am, Daniel Pitts <newsgroup.spamfil...@virtualinfinity.net> wrote:
> > Hello, > [quoted text clipped - 66 lines] > -- > Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/> I am reading a data file that contains a mix of doubles, double arrays, integers, integer arrays, booleans and strings. Each entry has a name (its key) and value associated with it. I know that when I request "NumEntries" that the return will be an integer, so I thought I would code something like
Integer numEntries = getValue( "NumEntries" );
and have an integer return. Further example, knowing "Description" contains a string I would code something like
String description = getValue( "Description" );
Christian - 06 Mar 2008 16:30 GMT Todd schrieb:
> On Mar 6, 8:27 am, Daniel Pitts > <newsgroup.spamfil...@virtualinfinity.net> wrote: [quoted text clipped - 17 lines] > > String description = getValue( "Description" ); Sometimes you are better off without using generics. it might be better to use something like:
String getValue(String key) {} int getIntValue(String key) {}
and not use generics for this.
Christian
Todd - 06 Mar 2008 19:34 GMT I figured out how to do it!!
Thanks for the ideas, Todd
Lew - 07 Mar 2008 01:15 GMT > I figured out how to do it!! Exactly how?
 Signature Lew
Todd - 10 Mar 2008 17:15 GMT > > I figured out how to do it!! > > Exactly how? > > -- > Lew All,
Here is the source that I came up with to do this. Please critique it. I would like to have concrete comments as to how it could be improved For example, I read a TechTip that said it would be better to use a scanner or at least String.split() in lieu of the StringTokenizer.
Todd
//=========================================
import java.util.StringTokenizer; import java.util.Vector;
/** * * @author heidenthal */ public class DataRecord { public DataRecord( String value, String description ) { // Fill the data record with the passed information this.value = new String( value ); this.description = new String( description );
// The record value needs to have its data type defined // for the typed return of the value dataType = determineType( value ); }
public String getDescription() { return description; }
public <T> T getValue() { @SuppressWarnings( "unchecked" ) // TODO check cast and don't suppress Class <T> type = dataType.getClassType();
return type.cast( dataType.castValue( value ) ); }
public Class getClassType() { return dataType.getClassType(); }
private DataType determineType( String value ) { dataType = DataType.STRING;
// boolean type if( isBoolean( value ) ) { dataType = DataType.BOOLEAN; } else if( isInteger( value ) ) // int type { dataType = DataType.INTEGER; } else if( isDouble( value ) ) // double type { dataType = DataType.DOUBLE; } else if( isDoubleArray( value ) ) // double[] type { dataType = DataType.DOUBLE_ARRAY; }
return dataType; }
private boolean isBoolean( String value ) { if( value.equalsIgnoreCase( "true" ) || value.equalsIgnoreCase( "false" ) ) { return true; }
return false; }
private boolean isInteger( String value ) { try { Integer.parseInt( value ); return true; } catch( Exception exception ) { return false; } }
private boolean isDouble( String value ) { try { Double.parseDouble( value ); return true; } catch( Exception exception ) { return false; } }
private boolean isDoubleArray( String value ) { if( value.contains( "{" ) && value.contains( "}" ) ) { return true; }
return false; }
private String value; private String description; private DataType dataType;
@SuppressWarnings( "unchecked" ) // TODO check cast and don't suppress private enum DataType { STRING( String.class ) { String castValue( String value ) { return value; } },
BOOLEAN( Boolean.class ) { Boolean castValue( String value ) { return Boolean.parseBoolean( value ); } },
INTEGER( Integer.class ) { Integer castValue( String value ) { return Integer.parseInt( value ); } },
DOUBLE( Double.class ) { Double castValue( String value ) { return Double.parseDouble( value ); } },
DOUBLE_ARRAY( Double[].class ) { Double[] castValue( String value ) { Vector<Double> values = new Vector<Double>();
StringTokenizer tokenizer = new StringTokenizer( value.substring( 1 ), " }" ); while( tokenizer.hasMoreTokens() ) { values.add( Double.parseDouble( tokenizer.nextToken() ) ); }
Double[] valuesArray = new Double[values.size()]; valuesArray = values.toArray( valuesArray );
return valuesArray; } };
DataType( Class clazz ) { this.clazz = clazz; }
abstract <T> T castValue( String value );
Class getClassType() { return clazz; }
private Class clazz; } }
//========================================
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Locale; import java.util.StringTokenizer;
/** * * @author heidenthal */ public class DataCollection extends HashMap<String, DataRecord> { public DataCollection( String filename ) { buildDefaultMap( filename ); }
public void buildDefaultMap( String filename ) { String line = null; InputStream reader = Class.class.getResourceAsStream( filename ); try { BufferedReader bufferedReader = new BufferedReader( new InputStreamReader( reader ) ); while( (line = bufferedReader.readLine()) != null ) { // Break the line into the key and data record StringTokenizer str = new StringTokenizer( line,"=" );
// Get the key for the data String key = str.nextToken().trim().toUpperCase(Locale.ENGLISH);
// Get the record value String value = str.nextToken( "=," ).trim();
// Get the description (if it exists) String description = str.nextToken( "\n" ).trim();
// Create a new data record and add it to the collection DataRecord dataRecord = new DataRecord( value, description );
this.put( key, dataRecord ); } } catch( IOException ioException ) { System.err.println( "Unable to open " + filename ); System.err.println( ioException ); } }
public <T> T get( String key ) throws NullPointerException { DataRecord dataRecord = super.get( key.trim().toUpperCase(Locale.ENGLISH) );
@SuppressWarnings( "unchecked" ) // TODO check cast and don't suppress Class<T> type = dataRecord.getClassType();
return type.cast( dataRecord.getValue() ); } }
Lew - 11 Mar 2008 01:13 GMT > import java.util.StringTokenizer; > import java.util.Vector; Don't use java.util.Vector. Use one of the List implementations that replaced it in 1998, such as ArrayList.
> public <T> T getValue() > { > @SuppressWarnings( "unchecked" ) // TODO check cast and don't > suppress > Class <T> type = dataType.getClassType(); The need for an "unchecked" suppression is an indicator that you don't have the generics quite right. Don't feel bad; with type erasure it isn't easy to get generics exactly right, warning-free.
 Signature Lew
Todd - 11 Mar 2008 13:59 GMT > > import java.util.StringTokenizer; > > import java.util.Vector; [quoted text clipped - 14 lines] > -- > Lew Lew,
Question about ArrayList vs. Vector. I remember reading that one should only use Vector since it is the only collection _guaranteed_ to be thread-safe. Is this no longer considered true?
Todd
Owen Jacobson - 11 Mar 2008 14:31 GMT > > > import java.util.StringTokenizer; > > > import java.util.Vector; [quoted text clipped - 14 lines] > > -- > > Lew Please don't quote signatures.
> Lew, > > Question about ArrayList vs. Vector. I remember reading that one > should only use Vector since it is the only collection _guaranteed_ to > be thread-safe. Is this no longer considered true? It depends on what you mean by "thread-safe". All of Vector's methods are declared synchronized, which means that only one method may be in progress on a single Vector at a time. However, this provides no guarantees about coherency across multiple method calls, nor particularly across iteration.
If you need the same promise from a List, you can use Collections.synchronizedList (backingList) to construct a wrapper around a List that performs the same synchronization that Vector does. However, I've rarely found synchronizing on individual lists to be all that useful, for the reasons I outlined above.
-o
Mark Space - 11 Mar 2008 21:04 GMT > Question about ArrayList vs. Vector. I remember reading that one > should only use Vector since it is the only collection _guaranteed_ to > be thread-safe. Is this no longer considered true? As Owen said, this is totally untrue. Vectors are required to be thread safe, thus requiring synchronization overhead whether you need it or not. All other (new) collections have a separate thread-safe version that you can instantiate optionally if you want thread safety.
Where the heck did you read this drivel? Seriously, I'm interested in knowing who is promulgating nonsense about Java.
Thanks in advance.
Andreas Leitgeb - 12 Mar 2008 09:16 GMT >> Question about ArrayList vs. Vector. I remember reading that one >> should only use Vector since it is the only collection _guaranteed_ to [quoted text clipped - 4 lines] > not. All other (new) collections have a separate thread-safe version > that you can instantiate optionally if you want thread safety. It was partially untrue, in that Vector is not the only one. But anyway it is the only one where you have thread-safety concisely, without the extra boilerplate of Collections.synchronizedWhatever(...).
PS1: If Thread-safety is not an requirement, then Vector is of course unnecessarily slower than other Collections.
PS2: If I need to deal with the capacity of a synchronized array-like Collection, how would I do this with ArrayList and Collections.synchronized*What* ?
RedGrittyBrick - 12 Mar 2008 10:39 GMT > PS1: If Thread-safety is not an requirement, then Vector is of ... > PS2: If I need to deal with the capacity of a synchronized ... PS1: Sony PlayStation. PS2: Sony PlayStation 2.
For postscripts I prefer the traditional abbreviations:
PS PPS
and so on.
Mark Space - 14 Mar 2008 20:31 GMT > PS > PPS P. S. = post scriptum, after the writing.
P. P. S. = post post scriptum, after the after writing.
P. P. P. S = post post post scriptum, after the after-after writing.
etc.
Lew - 13 Mar 2008 00:58 GMT > PS2: If I need to deal with the capacity of a synchronized array-like > Collection, how would I do this with ArrayList and > Collections.synchronized*What* ? What do you mean, "to deal with the capacity of a ... Collection"?
For operations on a synchronized List, you use the returned List from the Collections.synchronizedList() call.
List <T> synched = Collections.synchronizedList( unsynched ); ... synchronized( synched ) { if ( synched.size() == 0 ) { synched.add( foo ); } } etc.
 Signature Lew
Andreas Leitgeb - 13 Mar 2008 08:54 GMT >> PS2: If I need to deal with the capacity of a synchronized array-like >> Collection, how would I do this with ArrayList and >> Collections.synchronized*What* ? > What do you mean, "to deal with the capacity of a ... Collection"? I meant, I had a look at the Javadoc for ArrayList and skimmed over those of its methods that aren't specified by interfaces. Only those that deal with capacity (querying and setting) are specific to ArrayList. Plus there is also removeRange(), which it inherits from AbstractList, and thus also isn't available through List-API. Vector also offers these features.
While I'm not judging the practical value of these, it seems like Vector was the only threadsafe collection that had removeRange and a means to get/set the capacity in case a known large number of items needs to be added, to avoid multiple incremental re-allocations.
Lew - 13 Mar 2008 14:27 GMT >>> PS2: If I need to deal with the capacity of a synchronized array-like >>> Collection, how would I do this with ArrayList and [quoted text clipped - 4 lines] > those of its methods that aren't specified by interfaces. Only > those that deal with capacity (querying and setting) are specific Well, setting, anyway.
> to ArrayList. Plus there is also removeRange(), which it inherits > from AbstractList, and thus also isn't available through List-API. [quoted text clipped - 5 lines] > of items needs to be added, to avoid multiple incremental > re-allocations. Why do people insist on calling Vector "thread safe"? Having synchronized methods doesn't make it thread safe.
If you set the capacity then add items, you need to explicitly synchronize on the Vector anyway. Individual methods' synchronization doesn't extend through multiple method calls. There's no advantage to Vector here.
It also happens that removeRange() is a protected method, so relying on it forces you to extend AbstractList or a subclass. This is extra work that, from what you've indicated, doesn't solve your synchronization problem. Plus now you have to maintain an extra class instead of simply relying on the Java API. Work you'd avoid by using ArrayList and synchronizing explicitly, since you have to anyway.
I'd just use an ArrayList variable (for the extra methods List doesn't support), and explicitly synchronize.
 Signature Lew
Lew - 13 Mar 2008 14:32 GMT Andreas Leitgeb wrote:
>> it seems like >> Vector was the only threadsafe collection that had removeRange and a >> means to get/set the capacity in case a known large number >> of items needs to be added, to avoid multiple incremental >> re-allocations. What's wrong with multiple re-allocations? AIUI, ArrayList grows its capacity by doubling the array size, so there's not going to be a whole lot of re-allocation overhead - possibly even less than by manually calling ensureCapacity(), if you're not at least doubling the internal capacity with each call.
 Signature Lew
Andreas Leitgeb - 13 Mar 2008 18:18 GMT > What's wrong with multiple re-allocations? AIUI, ArrayList grows its capacity > by doubling the array size, I didn't intend to cause so much fuss with those few methods that Vector and ArrayList have, but plain List hasn't. I dislike fuss, which is the reason, that when I need something synchronized then I'd rather use a Vector than any of those Collections that I need to cast spells on to make synchronized, and then even lose some of the functionality. If my needs were more complicated, and I'd need extra sync-fuss even above what the Vector offers, then I can just as well use any other Collection and do all the sync myself.
Andreas Leitgeb - 13 Mar 2008 17:58 GMT > Why do people insist on calling Vector "thread safe"? Having synchronized > methods doesn't make it thread safe. I fail to see in which way a Vector was any *less* "thread safe" than a Collections.synchronizedList(new ArrayList(...)).
Docu for synchronizedList says: " Returns a synchronized (thread-safe) ..." Note, it doesn't say "synchronized and also thread-safe", but rather seems to consider those two to be like synonyms.
Docu for Vector only says: " Vector is synchronized.
What operations can I do on a synchronizedList without extra synchronization-block, that I cannot do on a Vector likewise and with same level of real thread-safety?
Lew - 14 Mar 2008 01:36 GMT >> Why do people insist on calling Vector "thread safe"? Having synchronized >> methods doesn't make it thread safe. > > I fail to see in which way a Vector was any *less* "thread safe" than > a Collections.synchronizedList(new ArrayList(...)). It isn't.
> Docu for synchronizedList says: > " Returns a synchronized (thread-safe) ..." > Note, it doesn't say "synchronized and also thread-safe", > but rather seems to consider those two to be like synonyms. Yes, and that is one instance of Sun's documentation leading people astray.
Individual methods are synchronized; using two synchronized methods separately is not inherently thread-safe; consider check-and-set operations.
The OP's problem seemed to call for a check-and-set (check capacity, and increase if needed, then add()). Even with Vector or synchronizedList(), this opens the barn door for a race condition without explicit synchronization. As I said, in this case I wouldn't use Vector or synchronizedList(); I'd declare the variable a plain ArrayList for the extra methods the OP wanted (or just List, since I think they're not really needed), and dispense with implicit synchronization altogether.
> Docu for Vector only says: > " Vector is synchronized. > > What operations can I do on a synchronizedList without extra > synchronization-block, that I cannot do on a Vector likewise > and with same level of real thread-safety? None.
ArrayList and synchronizedList() give you Lists without the non-collections methods of Vector and without Enumeration. I like synchronizedList() better than Vector because it lacks unneeded machinery; it Occam's Razors itself into my heart.
It's not what List has that Vector doesn't; it's what Vector has that List doesn't that makes me excoriate Vector.
 Signature Lew
Andreas Leitgeb - 14 Mar 2008 11:14 GMT >> I fail to see in which way a Vector was any *less* "thread safe" than >> a Collections.synchronizedList(new ArrayList(...)). > It isn't. Ok, so at least I didn't miss anything on factual side :-)
> Individual methods are synchronized; using two synchronized methods separately > is not inherently thread-safe; consider check-and-set operations. Now I'm a bit surprised about your definition of "thread-safety", because in a thread not very long ago, you insisted on static methods being principially thread-safe, without consideration of context...
PS: Occam's Razor says "don't buy more than you need" with a rather philosophical meaning of buying :-). Anyway, I don't need to buy Vector's extra features. I get them for free. Even quite the opposite: synchronizedList costs me more characters to type.
Lew - 14 Mar 2008 13:50 GMT > PS: Occam's Razor says "don't buy more than you need" with a > rather philosophical meaning of buying :-). Anyway, I don't > need to buy Vector's extra features. I get them for free. > Even quite the opposite: synchronizedList costs me more > characters to type. Typing effort is not part of my metric. The presence of unneeded machinery is the consideration. It isn't ever needed, so why include it when ArrayList is out there with exactly what's needed?
> Now I'm a bit surprised about your definition of "thread-safety", > because in a thread not very long ago, you insisted on static > methods being principially thread-safe, without consideration > of context... I insisted that they /could/ be thread-safe, not without consideration of context. Don't misrepresent my points.
 Signature Lew
Patricia Shanahan - 13 Mar 2008 15:53 GMT >>> PS2: If I need to deal with the capacity of a synchronized array-like >>> Collection, how would I do this with ArrayList and [quoted text clipped - 13 lines] > of items needs to be added, to avoid multiple incremental > re-allocations. removeRange is not really needed, because the same job can be done using only the List interface: myList.subList(from, to).clear();
This sort of operation requires explicit synchronization to prevent any changes in the list between calculation of the index values and the clear call.
Patricia
Lew - 12 Mar 2008 03:21 GMT > Question about ArrayList vs. Vector. I remember reading that one > should only use Vector since it is the only collection _guaranteed_ to > be thread-safe. Is this no longer considered true? It was never true, whether some considered it so or not. The rule prior to 1998 was only to use Vector because it was the only choice. After that, it was to use ArrayList unless you needed or wanted the collection to be inherently synchronized. Most of the time you don't need thread safety because the context is not multi-threaded. So most of the time, the built-in overhead of Vector's synchronization (much less in modern JVMs) was wasted overhead.
It remains true since 1998 that if you do want or need to use synchronization on your List, then Vector is the wrong choice. The right choice is at least Collections.synchronizedList( someList ). <http://java.sun.com/javase/6/docs/api/java/util/Collections.html#synchronizedLis t(java.util.List)>
More sophisticated concurrent algorithms can use the java.util.concurrent package and its kin. <http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-summary.html>
 Signature Lew
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|