I am trying to sort an arraylist by string length, i know of implementing Comparator, but i was wondering if this could be done within my function, without adding any extra classes or methods? Ideally I want to output them shortest to longest, but that I can do!
Here is a snippet of the method i would like to implement the comparator with.
public static void sCompare(BufferedReader r, PrintWriter w) throws IOException {
ArrayList<String> s= new ArrayList<String>();
String line;
int n = 0;
while ((line = r.readLine()) != null) {
s.add(line);
n++;
}
//Collections.sort(s);
Iterator<String> i = s.iterator();
while (i.hasNext()) {
w.println(i.next());
}
}
Thanks in advance for any input!
I don't see anything wrong with implementing the Comparator interface.
If your only concern is doing everything in the function, you could use an anonymous implementation. Something along the lines of :
Collections.sort(s, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return o1.length() - o2.length();
}
});
(that would replace you current line //Collections.sort(s);)
PS : you never use the value of n.
PPS: You may have to invert o1 and o2 depending of the order you want in the return statement.
Another example of implementing an interface with an anonymous class
I'm going to assume by "class" you mean "top level class", thus allowing the use of an anonymous class:
Collections.sort(s, new Comparator<String>() {
public int compare(String a, String b) {
// java 1.7:
return Integer.compare(a.length(), b.length());
// java 1.6
return a.length() - b.length();
}
});
Related
Java 6 uses merge sort to compare two objects in Collections.sort() whereas Java 1.7 uses Timsort
I have this class for object to sort
Class ObjectSort
{
String Name = "";
int priority = 0;
public ObjectSort (String name, int priority)
{
this.Name = Name;
this.priority = priority;
}
public getPriority()
{
return priority;
}
}
and my test class is
TestClass
{
...main()
{
List<ObjectSort> sorted = new ArrayList<ObjectSort> ();
sorted.add ("Table", 99);
sorted.add ("Chair", 1);
Collections.sort(sorted, new Comparator ());
}
// inner class to define comparator logic
private static final class Comparator implements java.util.Comparator<ObjectSort>
{
#Override
public int compare (ObjectSort f1, ObjectSort f2)
{
try
{
// Get the allocation priorities
int priority1 = f1.getPriority ();
int priority2 = f2.getPriority ();
if (priority1 == priority2)
return 0;
else
return (priority1 > priority2 ? 1 : 0);
}
catch (Exception e)
{
// Shouldn't happen, because we have the objects OK and there's no database activity
// happening here.
assert true;
}
return 0;
}
}
}
Now when we run the code in java 1.6, it sorts it correctly, Chair comes BEFORE table that is it is sorting it is ASCENDING order, which I want.
But where the code is run in Java 1.7, it does not sort it at all, Table comes before Chair. I checked and 1.6 uses merge sort whereas 1.7 is using Timsort. Please help me tell what is wrong in my code ?
UPDATE
In 1.7 in variable f1, Chair comes during code execution whereas in 1.6 Table comes!
Thanks!
Aiden
The problem is that your comparator is broken. When you have a Comparator
comparator.compare(a, b) == -comparator.compare(b, a)
The reason Java 7 doesn't accept this is; Java 7 has more checks that this condition is true.
they have updated the java to 1.7 :( and this code is not working there now :(
It never worked, it probably didn't sort properly before, but you didn't get a runtime error before.
A shorter version which will work is; (Don't reuse the name of common built in classes)
static class ObjectSortComparator implements Comparator<ObjectSort> {
#Override
public int compare (ObjectSort f1, ObjectSort f2) {
// Get the allocation priorities
int priority1 = f1.getPriority ();
int priority2 = f2.getPriority ();
return priority1 == priority2 ? 0 : (priority1 > priority2 ? 1 : -1);
}
}
Note: in Java 8 you don't need to write this yourself, you can do
sorted.sort(Comparator.comparingInt(ObjectSort::getPriority));
I am trying to make a markov chain in Java/Processing, that will read a book then be able to cut it up in probabilistic ways. Programming is a hobby…
I had the idea that the way to do it was to use a HashMap, and store a Word Object within it. I could easily do this with a String, but within each unique Word it needs to have another HashMap that will store more yet more Word Objects for the Words that follow it, and so on until we have made a model with a sufficient level of complexity.
The problems are that I can’t seem to be able to check whether or not a Word Object is already within the Map by its String name.
Through looking around on SO I can see that it is likely that I will need a Comparator — but all the examples that I have seen use compare or compareTo, when I think that I need something that is more like equals? I don’t need anything at all to do with Sorting, the order will be worked out in the second part of the program.
The code below is pretty horrible — I have been hacking away at this problem for ages but I can’t find an explanation that is sufficiently dumbed down enough for me to understand it.
In Pseudo:
read book
If the Word is not in the Map, put it in there
If the Word is in the Map, iterate the key
Check the Words that follow this Word, and check in the same way if they are within the first Word’s Map, adding as necessary… repeat…
When this is complete
Using the Integer values as probabilities, pick a word
from that Word’s Map, find a Word that is probable to follow it
repeat until desired length is achieved
Code so far:
///markovs
import java.util.HashSet;
import java.util.Comparator;
HashMap<Word, Integer> book;
void setup()
{
book = new HashMap<Word, Integer>();
String[] rows = loadStrings("crash.txt");
for (int i = 0; i < rows.length; i++)
{
if (trim(rows[i]).length() == 0)
{
continue;
}
String[] pieces = split(rows[i], " ");
for (int j = 0; j<pieces.length; j++)
{
Word temp = new Word(pieces[j]);
//c++;
if (book.compare(temp)) {
println("this worked for once");
//iterate here
} else {
book.put(temp, 1);
println("didn’t work");
//book.add(temp);
book.put(temp, 1);
}
}
}
println(book.size());
//println(c);
//println(book);
}
class WordComparator implements Comparator<Word> {
#Override
public int compare(Word w1, Word w2) {
String w1name = w1.name;
String w2name = w2.name;
if (w1name.equals(w2name)) {
return 1;
} else {
return 0;
}
}
}
class Word
{
String name;
int value=1;
int depth;
HashMap<String, Integer> list;
Word(String name_)
{
this.name = name_;
}
int compareTo(Word w) {
if (w.name.equals(this.name)) {
return 0;
} else {
return -1;
}
}
Word(Word w)
{
this.depth = w.depth+1;
}
void nextWord(String word)
{
}
void count() {
value++;
}
void makeHash()
{
list = new HashMap<String, Integer>();
}
}
To use an Object as a key in a HashMap, you need to override two methods: equals() and hashCode(). I'm not exactly sure what you're going for, but a simple example that just uses the name variable would look like this:
public boolean equals(Object other){
if(other instanceof Word){
return this.name.equals(((Word)other).name);
}
return false;
}
public int hashCode(){
return name.hashCode();
}
However, if you're just using the name variable anyway, you might be looking for a multimap, which is just a Map that contains a Map that contains...
HashMap<String, HashMap<String, Integer>> bookMap;
Furthermore, while HashMap does not use the compareTo function, the way you've implemented it seems off. First of all, you need to implement Comparable on your class:
class Word implements Comparable<Word>{
And secondly, the compareTo function should return one of 3 values: negative, zero, or positive. Right now you're only returning zero or negative, which doesn't make any sense.
I think you might be better off taking a step back and describing what you're actually trying to do, as your code contains a lot of confusing logic right now.
As for comparing, you can override Object's inherited equals method, something like:
# Override
boolean equals(Object o) {
return o instanceof Word
? o.name.equals(name) : false;
}
Be aware of using your own types as keys for the HashMap, in this case Word. That only works out well if you provide a sensible implementation of .hashCode() and .equals() on Word.
Here it looks like you could just use String instead. String already has the required method implementations. If you really do want to use Word, you could use those methods from String. e.g.
class Word {
String letters;
public int hashCode() {
return letters.hashCode();
}
public boolean equals(Object o) {
if (o == null || o.getClass() != getClass()) return false;
return letters.equals(((Word) o).letters);
}
}
You don't need a compare or compareTo, just these two.
With the use of below code, I am finding out which datacenter I am in and it is working fine..
public enum DatacenterEnum {
DEV, DC1, DC2, DC3;
private static DatacenterEnum compareLocation() {
String ourhost = getHostName();
for (DatacenterEnum dc : values()) {
String namepart = "." + dc.name().toLowerCase() + ".";
if (ourhost.indexOf(namepart) >= 0) {
return dc;
}
}
return null;// I don't want to do this now.
}
}
But it might be possible that it is not able to find any datacenter, so currently I am returning null.
Is there any direct way or a single line command by which I can return randomly either DC1 or DC2 or DC3 in the ENUM instead of returning null?
I know one way is to make a list of string and then randomnly select any integer between 0 to 2 inclusive and then find the string. But it is too much code, actually it's not but just trying to see is there any other way we can do this?
Any simple and direct way which I can use in the ENUM directly?
Here's the one line:
return DataCenterEnum.values()[new Random().nextInt(3) + 1)];
For those who require tighter control on their code, here's a safer version, which does not depend on the order of the enum instances:
return new DataCenterEnum[]{DC1, DC2, DC3}[new Random().nextInt(3)];
Here is a generic solution that will work for any enumeration.
Convenience method for single exclusion:
public static <E extends Enum<E>> E getRandom(Class<E> aEnum, E exclude) {
return getRandom(aEnum, Collections.singletonList(exclude));
}
Generic method that works with one or more exclusions:
public static <E extends Enum<E>> E getRandom(Class<E> aEnum, List<E> exclude){
//Convert set of enums into a list
List<E> enums = new ArrayList<E>(EnumSet.allOf(aEnum));
//Remove items from the list that you want to exclude
enums.removeAll(exclude);
int size = enums.size();
if(size != 0){
//Get random enum
int randomIndex = new Random().nextInt(size);
return enums.get(randomIndex);
} else {
throw new IllegalArgumentException("Empty Enumeration after excludes");
}
}
For your example you could call
EnumUtil.getRandom(DatacenterEnum.class, DatacenterEnum.DEV);
You could use the values() method, which returns an array. Then just use Math.random() to return a random instance.
Here is an example:
public static void main (String[] args) {
String[] arr = {"DEV","DC1","DC2","DC3"}; //returned by Enum.values(), you get the idea
String randElement = arr[(int) ((Math.random() * 3) +1)];
System.out.println(randElement);
}
Basically it boils down to generating a random number between 1 and n :)
This question already has answers here:
What is the easiest/best/most correct way to iterate through the characters of a string in Java?
(16 answers)
Closed 4 years ago.
I need a Iterator<Character> from a String object. Is there any available function in Java that provides me this or do I have to code my own?
One option is to use Guava:
ImmutableList<Character> chars = Lists.charactersOf(someString);
UnmodifiableListIterator<Character> iter = chars.listIterator();
This produces an immutable list of characters that is backed by the given string (no copying involved).
If you end up doing this yourself, though, I would recommend not exposing the implementation class for the Iterator as a number of other examples do. I'd recommend instead making your own utility class and exposing a static factory method:
public static Iterator<Character> stringIterator(final String string) {
// Ensure the error is found as soon as possible.
if (string == null)
throw new NullPointerException();
return new Iterator<Character>() {
private int index = 0;
public boolean hasNext() {
return index < string.length();
}
public Character next() {
/*
* Throw NoSuchElementException as defined by the Iterator contract,
* not IndexOutOfBoundsException.
*/
if (!hasNext())
throw new NoSuchElementException();
return string.charAt(index++);
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
It doesn't exist, but it's trivial to implement:
class CharacterIterator implements Iterator<Character> {
private final String str;
private int pos = 0;
public CharacterIterator(String str) {
this.str = str;
}
public boolean hasNext() {
return pos < str.length();
}
public Character next() {
return str.charAt(pos++);
}
public void remove() {
throw new UnsupportedOperationException();
}
}
The implementation is probably as efficient as it gets.
for (char c : myString.toCharArray()) {
}
Stealing from somebody else in another answer, this is probably the best direct implementation (if you're not going to use guava).
/**
* #param string
* #return list of characters in the string
*/
public static List<Character> characters(final String string) {
return new AbstractList<Character>() {
#Override
public Character get(int index) {
return string.charAt(index);
}
#Override
public int size() {
return string.length();
}
};
}
CharacterIterator it = new StringCharacterIterator("abcd");
// Iterate over the characters in the forward direction
for (char ch=it.first(); ch != CharacterIterator.DONE; ch=it.next())
// Iterate over the characters in the backward direction
for (char ch=it.last(); ch != CharacterIterator.DONE; ch=it.previous())
Short answer:
No, you have to code it.
Long answer:
List and Set both have a method for obtaining an Iterator (there are a few other collection classes, but probably not what your looking for). The List and Set interfaces are a part of the Collections Framework which only allow for adding/removing/iterating Objects like Character or Integer (not primitives like char or int). There is a feature in Java 1.5 called auto-boxing that will hide this primitive to Object conversion but I don't recommend it and it won't provide what you want in this case.
An alternative would be to wrap the String in a class of your own that
implements Iterator<Character>
but that might be more work than it is worth.
Here is a code snippet for doing what you want:
String s = "";
List<Character> list = new ArrayList<Character>(s.length());
for (int i = 0; i < s.length(); i++) {
// note that Character.valueOf() is preferred to new Character()
// you can omit the Character.valueOf() method
// and Java 1.5+ will auto-box the primitive into an Object
list.add(Character.valueOf(s.charAt(i)));
}
Iterator<Character> iterator = list.iterator();
No direct way. Not difficult to code, though:
public static Iterator<Character> gimmeIterator(final String x) {
Iterator<Character> it = new Iterator<Character>() {
String str = x == null ? "" : x;
int pos = -1; // last read
public boolean hasNext() { return(pos+1 < str.length()); }
public Character next() { pos++; return str.charAt(pos); }
public void remove() {
throw new UnsupportedOperationException("remove unsupported for this iterator");
}
};
return it;
}
This can be done with a little help from Apache Commons Lang (if you don't want to use Guava, and want a true java.util.Iterator.
private static Iterator<Character> iterator(String string) {
return Arrays.asList(ArrayUtils.toObject(string.toCharArray())).iterator();
}
With java 8 or newer you can use the stream facility. With the chars() method you can access an IntStream. The IntStream supports the method iterator() that returns an OfInt iterator. OfInt implements Iterator<Integer>.
String str = "foobar";
OfInt ofit = str.chars().iterator();
Iterator<Integer> it = ofit;
It is not a perfect answer, since you asked for Iterator<Character>.
Btw: With str.codePoints() you can also access a code point IntStream.
Not sure if there is a more direct way but you could do something like;
Arrays.asList(string.toCharArray()).iterator();
Scratch that; Arrays.asList doesn't do what I seem to remember it doing.
Edit 2: Seems like it last worked this way in 1.4
The Iterator iterate over a collection or whatever implements it. String class does nost implement this interface. So there is no direct way.
To iterate over a string you will have to first create a char array from it and then from this char array a Collection.
This feels dirty, but you could use Scanner with empty string delimiter:
Scanner scanner = new java.util.Scanner(myInput).useDelimiter("");
Scanner implements Iterator, so scanner is now an Iterator of length-1 strings, which is close.
To continue with the (very?) dirty, in Java 8 you can then do this to succinctly iterate by chars:
for (String s: (Iterable<String>)() -> scanner) {
char c = s.charAt(0);
System.out.println(c);
}
For details on why () -> scanner works (and why it may be dangerous, though not in this use case), see Explain how this lambda can be assigned to an Iterable.
I've got a few Comparators -- one for Dates, one for decimals, one for percentages, etc.
At first my decimal comparator looked like this:
class NumericComparator implements Comparator<String> {
#Override
public int compare(String s1, String s2) {
final Double i1 = Double.parseDouble(s1);
final Double i2 = Double.parseDouble(s2);
return i1.compareTo(i2);
}
}
Life was simple. Of course, this doesn't handle the case where the strings aren't parseable. So I improved compare():
class NumericComparator implements Comparator<String> {
#Override
public int compare(String s1, String s2) {
final Double i1;
final Double i2;
try {
i1 = Double.parseDouble(s1);
} catch (NumberFormatException e) {
try {
i2 = Double.parseDouble(s2);
} catch (NumberFormatException e2) {
return 0;
}
return -1;
}
try {
i2 = Double.parseDouble(s2);
} catch (NumberFormatException e) {
return 1;
}
return i1.compareTo(i2);
}
}
Life was better. Tests felt more solid. However, my code reviewer pointed out, "What about nulls?"
Great, so now I have to repeat the above with NullPointerException or prepend the method body with:
if (s1 == null) {
if (s2 == null) {
return 0;
} else {
return -1;
}
} else if (s2 == null) {
return 1;
}
This method is huge. The worst part is, I need to repeat this pattern with three other classes which compare different types of strings and could raise three other exceptions while parsing.
I'm not a Java expert. Is there a cleaner, neater solution than -- gasp -- copying and pasting? Should I trade correctness for lack of complexity so as long as it is documented?
Update: Some have suggested that it's not the Comparator's job to handle null values. Since the sort results are displayed to users I indeed want nulls to be sorted consistently.
You are implementing a Comparator<String>. String's methods, including compareTo throw a NullPointerException if a null is handed in to them, so you should too. Similarly, Comparator throws a ClassCastException if the arguments' types prevent them from being compared. I would recommend you implement these inherited behaviors.
class NumericComparator implements Comparator<String> {
public int compare(String s1, String s2) {
final Double i1;
final Double i2;
if(s1 == null)
{
throw new NullPointerException("s1 is null"); // String behavior
}
try {
i1 = Double.parseDouble(s1)
} catch (NumberFormatException e) {
throw new ClassCastException("s1 incorrect format"); // Comparator behavior
}
if(s2 == null)
{
throw new NullPointerException("s2 is null"); // String behavior
}
try {
i2 = Double.parseDouble(s1)
} catch (NumberFormatException e) {
throw new ClassCastException("s2 incorrect format"); // Comparator behavior
}
return i1.compareTo(i2);
}
}
You can almost regain the original elegance by extracting a method to do the type checking and conversion.
class NumericComparator implements Comparator<String> {
public int compare(String s1, String s2) {
final Double i1;
final Double i2;
i1 = parseStringAsDouble(s1, "s1");
i2 = parseStringAsDouble(s2, "s2");
return i1.compareTo(i2);
}
private double parseStringAsDouble(String s, String name) {
Double i;
if(s == null) {
throw new NullPointerException(name + " is null"); // String behavior
}
try {
i = Double.parseDouble(s1)
} catch (NumberFormatException e) {
throw new ClassCastException(name + " incorrect format"); // Comparator behavior
}
return i;
}
}
If you are not particular about the Exception messages, you can lose the "name" parameter. I'm sure you can lose an extra line here or word there by applying little tricks.
You say you need to repeat this pattern with three other classes which compare different types of strings and could raise three other exceptions. It's difficult to offer specifics there without seeing the situation, but you may be able to use "Pull Up Method" on a version of my parseStringAsDouble into a common ancestor of NumericComparator that itself implements java's Comparator.
There are a lot of subjective answers to this question. Here's my own $.02.
First, the trouble you're describing is the canonical symptom of a language that lacks first-class functions, which would enable you to succinctly describe these patterns.
Second, in my opinion, it should be an error to compare two Strings as Doubles if one of them cannot be considered a representation of a double. (The same is true for nulls, etc.) Therefore, you should permit the exceptions to propagate! This will be a contentious opinion, I expect.
Here's how I'd improve the comparator:
First, exctract a method for converting the value. It's being repeated, multiple try...catches are always ugly -> better to have as few of them as possible.
private Double getDouble(String number) {
try {
return Double.parseDouble(number);
} catch(NumberFormatException e) {
return null;
}
}
Next, write down simple rules to show how you want the flow of the comparator to be.
if i1==null && i2!=null return -1
if i1==null && i2==null return 0
if i1!=null && i2==null return 1
if i1!=null && i2!=null return comparison
Finally do horrible obfuscation to the actual comparator to raise a few WTF:s in code review (or like others like to say it, "Implement the Comparator"):
class NumericComparator implements Comparator<String> {
public int compare(String s1, String s2) {
final Double i1 = getDouble(s1);
final Double i2 = getDouble(s2);
return (i1 == null) ? (i2 == null) ? 0 : -1 : (i2 == null) ? 1 : i1.compareTo(i2);
}
private Double getDouble(String number) {
try {
return Double.parseDouble(number);
} catch(NumberFormatException e) {
return null;
}
}
}
...yes, that's a branching nested ternary. If anyone complains about it, say what others here have been saying: Handling nulls isn't Comparator's job.
You could create a utility method that handles parsing and returns a certain value in the case of nulls or parse exceptions.
Take a step back. Where does those Strings come from? For what is this Comparator to be used? Do you have a Collection of Strings which you would like to sort or so?
Try this:
import com.google.common.base.Function;
import com.google.common.collect.Ordering;
Ordering.nullsFirst().onResultOf(
new Function<String, Double>() {
public Double apply(String s) {
try {
return Double.parseDouble(s);
} catch (NumberFormatException e) {
return null;
}
})
The only problem, if it you consider it that, is that null Strings and other non-parseable Strings will all be intermingled. That's probably not a big deal, considering the benefits -- this gives you a comparator that is guaranteed to be correct, whereas with a hand-coded comparator, even relatively simple ones, it's amazing how easy it is to commit a subtle error that breaks transitivity or, umm, antisymmetricity.
http://google-collections.googlecode.com
It seems that there are two concerns being mixed here and maybe should be broken up into separate components. Consider the following:
public class ParsingComparator implements Comparator<String> {
private Parser parser;
public int compare(String s1, String s2) {
Object c1 = parser.parse(s1);
Object c2 = parser.parse(s2);
new CompareToBuilder().append(c1, c2).toComparison();
}
}
The Parser interface would have implementations for numbers, dates, etc. You could potentially use the java.text.Format class for your Parser interface. If you don't want to use commons-lang, you could replace the use of CompareToBuilder with some logic to handle nulls and use Comparable instead of Object for c1 and c2.
tl;dr: Take guidance from the JDK. The Double comparator is not defined for either non-numbers or nulls. Make people give you useful data (Doubles, Dates, Dinosaurs, whatever) and write your comparators for that.
As near as I can tell, this is a case of user input validation. For example, if you are taking input from a dialog box, the correct place to ensure that you have a parseable String that is a Double, Date or whatever is in the input handler. Make sure it's good before the user can tab away, hit "Okay" or equivalent.
Here's why I think this:
First question: if the Strings aren't parseable as numbers, I think you're trying to solve the problem in the wrong place. Say, for instance, I try to compare "1.0" to "Two". The second is clearly not parseable as a Double but is it less than the first? Or is it greater. I would argue that the users should have to turn their Strings into Doubles before they ask your which is greater (which you can easily answer with Double.compareTo, for instance).
Second question: if the Strings are "1.0" and null, which is greater? The JDK source doesn't handle NullPointerExceptions in the Comparator: if you give it a null, autoboxing will fail.
The worst part is, I need to repeat
this pattern with three other classes
which compare different types of
strings and could raise three other
exceptions while parsing.
Exactly why I would argue that the parsing should happen outside your Comparator with exception-handling dealt with before it arrives at your code.
If you are able to change the signature I would suggest you write the method so that it can accept any supported Object.
public int compare(Object o1, Object o2) throws ClassNotFoundException {
String[] supportedClasses = {"String", "Double", "Integer"};
String j = "java.lang.";
for(String s : supportedClasses){
if(Class.forName(j+s).isInstance(o1) && Class.forName(j+s).isInstance(o1)){
// compare apples to apples
return ((Comparable)o1).compareTo((Comparable)o2);
}
}
throw new ClassNotFoundException("Not a supported Class");
}
You might even define it recursively where you cast your Strings to Doubles and then return the result of calling itself with those objects.
IMHO you should first create a method that returns a Double from a String, embedding the null and parsing failure cases (but you must define what to do in such cases : throw an exception ? return a default value ??).
Then your comparator just have to compare obtained Double instances.
In other words, refactoring...
But I still wonder why you need to compare strings though expecting they represent doubles. I mean, what prevents you from manipulating doubles in the code that would actually use this comparator ?
according to your needs and Ewan's post, I think there's a way to extract the structure that you can reuse:
class NumericComparator implements Comparator<String> {
private SafeAdaptor<Double> doubleAdaptor = new SafeAdaptor<Double>(){
public Double parse(String s) {
return Double.parseDouble(s);
}
};
public int compare(String s1, String s2) {
final Double i1 =doubleAdaptor.getValue(s1, "s1");
final Double i2 = doubleAdaptor.getValue(s2, "s2");
return i1.compareTo(i2);
}
}
abstract class SafeAdaptor<T>{
public abstract T parse(String s);
public T getValue(String str, String name) {
T i;
if (str == null) {
throw new NullPointerException(name + " is null"); // String
}
try {
i = parse(str);
} catch (NumberFormatException e) {
throw new ClassCastException(name + " incorrect format"); // Comparator
}
return i;
}
}
I extract the method as an abstract class which can be reuse in other cases(although the class name is suck).
cheers.
So I improved compare()...
sure you did.
first, the Comparator interface doesn't specify what happens with nulls. if your null checking if statement works for your use case, that's great, but the general solution is throwing an npe.
as to cleaner... why final? why all the catch/throws? why use compareTo for a primitive wrapper?
class NumericComparator implements Comparator<String> {
public int compare(String s1, String s2) throws NullPointerException, NumberFormatException {
double test = Double.parseDouble(s1) - Double.parseDouble(s2);
int retVal = 0;
if (test < 0) retVal = -1;
else if (test > 0) retVal = 1;
return retVal;
}
}
seems you might find it clearer renaming test to t1 and retVal to q.
as to repeating the pattern... eh. you might be able to use generics with reflection to invoke appropriate parseX methods. seems like that'd not be worth it though.