the output should be as below:
foo (A, T1, T2) -> void
bar (A, T1, T2, T3) -> int
doo () -> double
public static class A {
void foo(int T1, double T2) { }
int bar(int T1, double T2, char T3) { return 1; }
static double doo() { return 1; }
}
static void displayMethodInfo(Object obj)
{
Class<?> a = obj.getClass();
Method[] methods = a.getDeclaredMethods();
for (Method y : methods) //print methods
{
System.out.print(y.getName() + "(" ); // + y.getDeclaringClass().getSimpleName());
Type[] types = y.getGenericParameterTypes(); //get parameter types
if (!(Modifier.isStatic((y.getModifiers()))))
{
//non-static method, output this class namr as the 1st argument
System.out.print(y.getName()); //display
if (types.length > 0)
{
//put a comma and space
System.out.print(", ");
}
}
for (Type z : types)
System.out.print(", " + z.toString());
System.out.println( ") " + " -> " + y.getGenericReturnType().toString()); //*/
/*
//print parameter of the method
int i = 0;
for (; i < types.length-1; i++)
{
System.out.print(removeClassFromName (types[i].toString()) + ", ");
}
if (types.length > 0) //print last parameter
{
System.out.print(removeClassFromName(types[i].toString()));
//print return type
System.out.println( " ) " + " -> " + removeClassFromName(y.getGenericReturnType().toString()));
} */
}
}
with my code after I run the code, it outputs the code as below, it does not print out the type correctly. how should I fixed and have that output correctly?
bar(int, double, char) -> int
doo() -> double
foo(int, double) -> void
And every time when I recompiled and run it, the output is having the different order.
#Zoe as #Sami Sarraj said, your code is doing what is supposed to. About the order, it is not possible to get the order it was wrote by the getDeclaredMethods() call, as you can see here.
About getting the parameters names you can find a hint here.
Related
**I wrote a simple code that have to compare to numbers, but when I run it compiler say me that has a error with boolean values. I dont understand why it doesnt work **
{
public static void main(String[] args) {
compare(8,22);
}
static void compare(int a, int b){
switch (a) {
case (a > b) -> System.out.println(a + " > " + b);
case (b < a) -> System.out.println(a + " < " + b);
case (a == b) -> System.out.println(a + " = " + b);
default -> System.out.println("Something is wrong !");
}
}
}```
Change it to:
{
public static void main( String... args )
{
compare( 8, 22 );
}
static void compare( final int a, final int b )
{
switch( Integer.signum( Integer.compare( a, b ) ) )
{
case 1 -> System.out.println( a + " > " + b );
case -1 -> System.out.println( a + " < " + b );
case 0 -> System.out.println( a + " = " + b );
default -> System.out.println( "Something is wrong !" );
}
}
}
And it should work!
case requires distinct constant expressions, and the terms that you use ((a > b), (b < a) and (a == b)) are no constants (not to mention that (a > b) and (b < a) are equivalent). They also return a boolean. switch does not handle a boolean switch selector directly.
In JShell, (only) this works for switch with "boolean":
boolean flag = …
switch( Boolean.toString( flag ) )
{
case "true" -> …
case "false" -> …
default -> throw new Error( "Hä?" );
}
I have a list of java objects, and I want to use stream to filter them at runtime. However, the variable I want to filter on is only known at runtime.
For eg, the user says I want a list of all cats whose fur length is longer than 3cm, I should be able to do
cats.stream().filter(cat -> cat.getFurLength() > 3).collect(Collectors.toList());
The getFurLength() getter however should be dynamically invoked - if the user instead wants to filter by eye colour then I should be able to call
cats.stream().filter(cat -> cat.getEyeColour() == Colour.BLUE).collect(Collectors.toList());
How do I achieve this without writing all possible filters beforehand?
Ideally the user should send something like:
{
eyeColour:{
operator: "equal_to",
value: "BLUE"
},
furLength: {
operator: "greater_than",
value: 3
}
}
and the code should be able to generate the filters dynamically based on these criteria.
Assuming your Cat class follows JavaBean convention you could use java.beans.PropertyDescriptor to access getter Method based on property name.
This allows us to learn what type of value we are dealing with. If it is numeric we can handle greater_than and other operators, but if it is non-numeric we should handle only equals_to operator.
"Simplified" and very limited solution could look like:
NOTE:
- Solution doesn't support primitive numeric types like int. Use Integer, Double etc. instead.
- I am converting all numbers to BigDecimal and use compareTo to simplify numerical type comparison, if you get any bugs for big numbers or very precise ones feel free to replace it with proper type comparison).
- for equality check it compares string representation of objects (result of toString()), so for Color you can't use BLUE but your JSON would need to hold java.awt.Color[r=0,g=0,b=255])
class PredicatesUtil {
static <T> Predicate<T> filters(Class<T> clazz, String filtersJson) {
JSONObject jsonObject = new JSONObject(filtersJson);
List<Predicate<T>> predicateList = new ArrayList<>();
for (String property : jsonObject.keySet()) {
JSONObject filterSettings = jsonObject.getJSONObject(property);
try {
String operator = filterSettings.getString("operator");
String value = filterSettings.getString("value");
predicateList.add(propertyPredicate(clazz, property, operator, value));
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
}
return combinePredicatesUsingAND(predicateList);
}
static <T> Predicate<T> combinePredicatesUsingAND(List<Predicate<T>> predicateList) {
return t -> {
for (Predicate<T> pr : predicateList) {
if (!pr.test(t))
return false;
}
return true;
};
}
static <T> Predicate<T> propertyPredicate(Class<T> clazz, String property,
String operator, String value)
throws IntrospectionException {
final Method m = new PropertyDescriptor(property, clazz).getReadMethod();
final Class<?> returnType = m.getReturnType();
return obj -> {
try {
Object getterValue = m.invoke(obj);
if (Number.class.isAssignableFrom(returnType)) {
BigDecimal getValue = new BigDecimal(getterValue.toString());
BigDecimal numValue = new BigDecimal(value);
int compared = getValue.compareTo(numValue);
if (operator.equalsIgnoreCase("equal_to")) {
return compared == 0;
} else if (operator.equalsIgnoreCase("lesser_than")) {
return compared < 0;
} else if (operator.equalsIgnoreCase("greater_than")) {
return compared > 0;
} else {
throw new RuntimeException("not recognized operator for numeric type: " + operator);
}
} else {
//System.out.println("testing non-numeric, only euals_to");
if (operator.equalsIgnoreCase("equal_to")) {
return value.equalsIgnoreCase(getterValue.toString());
}
throw new RuntimeException("not recognized operator: " + operator);
}
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
};
}
}
which can be used like:
class Cat {
private Color eyeColour;
private Integer furLength;
Cat(Color eyeColor, Integer furLength) {
this.eyeColour = eyeColor;
this.furLength = furLength;
}
public Color getEyeColour() {
return eyeColour;
}
public Integer getFurLength() {
return furLength;
}
public void setEyeColour(Color eyeColour) {
this.eyeColour = eyeColour;
}
public void setFurLength(Integer furLength) {
this.furLength = furLength;
}
#Override
public String toString() {
return "Cat{" +
"eyeColor=" + eyeColour +
", furLength=" + furLength +
'}';
}
}
class CatsDemo {
public static void main(String[] args) {
String json =
"{\n" +
" eyeColour:{\n" +
" operator: \"equal_to\",\n" +
" value: \"java.awt.Color[r=0,g=0,b=255]\"\n" +
" },\n" +
" furLength: {\n" +
" operator: \"greater_than\",\n" +
" value: \"3\"\n" +
" }\n" +
"}";
List<Cat> cats = List.of(
new Cat(Color.blue, 1),
new Cat(Color.blue, 2),
new Cat(Color.blue, 3),
new Cat(Color.blue, 4),
new Cat(Color.blue, 5),
new Cat(Color.yellow, 1),
new Cat(Color.yellow, 2),
new Cat(Color.yellow, 3),
new Cat(Color.yellow, 4),
new Cat(Color.yellow, 5)
);
cats.stream()
.filter(PredicatesUtil.filters(Cat.class, json))
.forEach(System.out::println);
}
}
Output:
Cat{eyeColor=java.awt.Color[r=0,g=0,b=255], furLength=4}
Cat{eyeColor=java.awt.Color[r=0,g=0,b=255], furLength=5}
Make it reusable with a function.
List<Cat> filterCats(cats, Predicate<Cat> filter) {
return cats.stream().filter(filter).collect(Collectors.toList());
}
And then use it with:
filterCats(cats, cat -> cat.getEyeColour() == Colour.BLUE)
Or,
filterCats(cats, cat -> cat.getFurLength() > 3)
For what it's worth: Apache Commons BeanUtils library is specialized in accessing bean properties in a dynamic way.
See BeanPropertyValueEqualsPredicate for an understanding. This is only a solution for equality matches.
This is a probable answer of my question in stack overflow.Integer to word conversion
At first I have started with dictionary. Then I came to know it is obsolete. So now I use Map instead of dictionary. My code is work well for number till Millions. But the approach I take here is a naive approach. The main problem of this code is
First: Huge numbers of variable use
2nd: Redundant code block as per program requirement
3rd: Multiple if else statement
I am thinking about this problems
Solution for 2nd problem: using user define function or macros to eliminate redundant code block
Solution for 3rd problem: Using switch case
My code:
public class IntegerEnglish {
public static void main(String args[]){
Scanner in=new Scanner(System.in);
System.out.println("Enter the integer");
int input_number=in.nextInt();
Map<Integer,String> numbers_converter = new HashMap<Integer,String>();
Map<Integer,String> number_place = new HashMap<Integer,String>();
Map<Integer,String> number_2nd = new HashMap<Integer,String>();
numbers_converter.put(0,"Zero");
numbers_converter.put(1,"One");
numbers_converter.put(2,"Two");
numbers_converter.put(3,"Three");
numbers_converter.put(4,"Four");
numbers_converter.put(5,"Five");
numbers_converter.put(6,"Six");
numbers_converter.put(7,"Seven");
numbers_converter.put(8,"Eight");
numbers_converter.put(9,"Nine");
numbers_converter.put(10,"Ten");
numbers_converter.put(11,"Eleven");
numbers_converter.put(12,"Twelve");
numbers_converter.put(13,"Thirteen");
numbers_converter.put(14,"Fourteen ");
numbers_converter.put(15,"Fifteen");
numbers_converter.put(16,"Sixteen");
numbers_converter.put(17,"Seventeen");
numbers_converter.put(18,"Eighteen");
numbers_converter.put(19,"Nineteen");
number_place.put(3,"Hundred");
number_place.put(4,"Thousand");
number_place.put(7,"Million");
number_place.put(11,"Billion");
number_2nd.put(2,"Twenty");
number_2nd.put(3,"Thirty");
number_2nd.put(4,"Forty");
number_2nd.put(5,"Fifty");
number_2nd.put(6,"Sixty");
number_2nd.put(7,"Seventy");
number_2nd.put(8,"Eighty");
number_2nd.put(9,"Ninty");
if(input_number== 0){
System.out.println("zero");
}
else if(input_number>0 && input_number<19){
System.out.println(numbers_converter.get(input_number));
}
else if(input_number>19 && input_number<100){
int rem=input_number%10;
input_number=input_number/10;
System.out.print(number_2nd.get(input_number));
System.out.print(numbers_converter.get(rem));
}
else if(input_number==100){
System.out.println(number_place.get(3));
}
else if(input_number>100 && input_number<1000){
int reminder=input_number%100;
int r1=reminder%10;
int q1=reminder/10;
int quot=input_number/100;
System.out.print(numbers_converter.get(quot) + "hundred");
if(reminder>0 && reminder<20){
System.out.print(numbers_converter.get(reminder));
}
else{
System.out.println(number_2nd.get(q1) + numbers_converter.get(r1));
}
}
else if(input_number==1000){
System.out.println(number_place.get(4));
}
else if(input_number>1000 && input_number<10000){
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
System.out.print(numbers_converter.get(thousand) + "thousand" + numbers_converter.get(hundred)+ " hundred");
if(rem >0 && rem<20){
System.out.print(numbers_converter.get(rem));
}
else if(rem >19 && rem <100){
System.out.print(number_2nd.get(quotient) + numbers_converter.get(rem_two));
}
}
else if(input_number>10000 && input_number<1000000000){
//Say number 418,229,356
int third_part=input_number%1000;//hold 356
input_number=input_number/1000;//hold 418,229
int sec_part=input_number%1000;//hold 229
input_number=input_number/1000;// hold 418
int rem_m=third_part%100;//hold 56
int rem_m1=rem_m%10;//hold 6
int rem_q=rem_m/10;// hold 5
int q_m=third_part/100;// hold 3
int sec_part_rem=sec_part%100;// hold 29
int sec_part_rem1=sec_part_rem%10;//9
int sec_part_q=sec_part_rem/10;//hold 2
int sec_q=sec_part/100;// hold 2
int input_q=input_number/100;// hold 4
int input_rem=input_number%100;//hold 18
int input_q_q=input_rem/10;//hold 1
int input_rem1=input_rem%10;// hold 8
System.out.print(numbers_converter.get(input_q) + " hundred ");
if(input_rem>0 && input_rem<20){
System.out.print(numbers_converter.get(input_rem)+ " Million ");
}
else{
System.out.print(number_2nd.get(input_q_q) + " " + numbers_converter.get(input_rem1) + " Million ");
}
System.out.print(numbers_converter.get(sec_q) + " hundred ");
if(sec_part_rem >0 && sec_part_rem<20){
System.out.println(numbers_converter.get(sec_part_rem) + " thousand ");
}
else{
System.out.print(number_2nd.get(sec_part_q) + " " + numbers_converter.get(sec_part_rem1) + " thousand ");
}
System.out.print(numbers_converter.get(q_m) + " hundred ");
if(rem_m>0 && rem_m<20){
System.out.print(numbers_converter.get(rem_m));
}
else{
System.out.print(number_2nd.get(rem_q) + " " + numbers_converter.get(rem_m1));
}
}
}
}
Redundant Code Blocks
int rem=input_number%100;
int rem_two=rem%10;
int quotient =rem/10;
input_number=input_number/100;
int thousand=input_number/10;
int hundred = input_number%10;
This type of code block used almost every where. Taking a number divide it with 100 or 1000 to find out the hundred position then then divide it with 10 to find out the tenth position of the number. Finally using %(modular division) to find out the ones position.
How could I include user define function and switch case to minimize the code block.
Instead of storing the results in variables, use a method call:
int remainder100(int aNumber) {
return aNumber % 100;
}
int remainder10(int aNumber) {
return aNumber % 10;
}
...etc.
System.out.println(numbers_converter.get(remainder100(input_number)));
About 3rd problem: I wouldn't use switch ... case, too many cases.
Instead, take advantage that numbering repeats itself every 3 digits. That means the pattern for thousands and millions is the same (and billions, trillions, etc).
To do that, use a loop like this:
ArrayList<String> partialResult = new ArrayList<String>();
int powersOf1000 = 0;
for (int kiloCounter = input_number; kiloCounter > 0; kiloCounter /= 1000) {
partialResult.add(getThousandsMilionsBillionsEtc(powersOf1000++);
partialResult.add(convertThreeDigits(kiloCounter % 1000));
}
Then you can print out the contents of partialResult in reverse order to get the final number.
I'd suggest you break your single main method down into a couple of classes. And if you haven't already create a few unit tests to allow you to easily test / refactor things. You'll find it quicker than starting the app and reading from stdin.
You'll find it easier to deal with the number as a string. Rather than dividing by 10 all the time you just take the last character of the string. You could have a class that does that bit for you, and a separate one that does the convert.
Here's what I came up with, but I'm sure it can be improved. It has a PoppableNumber class which allows the last character of the initial number to be easily retrieved. And the NumberToString class which has a static convert method to perform the conversion.
An example of a test would be
#Test
public void Convert102356Test() {
assertEquals("one hundred and two thousand three hundred and fifty six", NumberToString.convert(102356));
}
And here's the NumberToString class :
import java.util.HashMap;
import java.util.Map;
public class NumberToString {
// billion is enough for an int, obviously need more for long
private static String[] power3 = new String[] {"", "thousand", "million", "billion"};
private static Map<String,String> numbers_below_twenty = new HashMap<String,String>();
private static Map<String,String> number_tens = new HashMap<String,String>();
static {
numbers_below_twenty.put("0","");
numbers_below_twenty.put("1","one");
numbers_below_twenty.put("2","two");
numbers_below_twenty.put("3","three");
numbers_below_twenty.put("4","four");
numbers_below_twenty.put("5","five");
numbers_below_twenty.put("6","six");
numbers_below_twenty.put("7","seven");
numbers_below_twenty.put("8","eight");
numbers_below_twenty.put("9","nine");
numbers_below_twenty.put("10","ten");
numbers_below_twenty.put("11","eleven");
numbers_below_twenty.put("12","twelve");
numbers_below_twenty.put("13","thirteen");
numbers_below_twenty.put("14","fourteen ");
numbers_below_twenty.put("15","fifteen");
numbers_below_twenty.put("16","sixteen");
numbers_below_twenty.put("17","seventeen");
numbers_below_twenty.put("18","eighteen");
numbers_below_twenty.put("19","nineteen");
number_tens.put(null,"");
number_tens.put("","");
number_tens.put("0","");
number_tens.put("2","twenty");
number_tens.put("3","thirty");
number_tens.put("4","forty");
number_tens.put("5","fifty");
number_tens.put("6","sixty");
number_tens.put("7","seventy");
number_tens.put("8","eighty");
number_tens.put("9","ninty");
}
public static String convert(int value) {
if (value == 0) {
return "zero";
}
PoppableNumber number = new PoppableNumber(value);
String result = "";
int power3Count = 0;
while (number.hasMore()) {
String nextPart = convertUnitTenHundred(number.pop(), number.pop(), number.pop());
nextPart = join(nextPart, " ", power3[power3Count++], true);
result = join(nextPart, " ", result);
}
if (number.isNegative()) {
result = join("minus", " ", result);
}
return result;
}
public static String convertUnitTenHundred(String units, String tens, String hundreds) {
String tens_and_units_part = "";
if (numbers_below_twenty.containsKey(tens+units)) {
tens_and_units_part = numbers_below_twenty.get(tens+units);
}
else {
tens_and_units_part = join(number_tens.get(tens), " ", numbers_below_twenty.get(units));
}
String hundred_part = join(numbers_below_twenty.get(hundreds), " ", "hundred", true);
return join(hundred_part, " and ", tens_and_units_part);
}
public static String join(String part1, String sep, String part2) {
return join(part1, sep, part2, false);
}
public static String join(String part1, String sep, String part2, boolean part1Required) {
if (part1 == null || part1.length() == 0) {
return (part1Required) ? "" : part2;
}
if (part2.length() == 0) {
return part1;
}
return part1 + sep + part2;
}
/**
*
* Convert an int to a string, and allow the last character to be taken off the string using pop() method.
*
* e.g.
* 1432
* Will give 2, then 3, then 4, and finally 1 on subsequent calls to pop().
*
* If there is nothing left, pop() will just return an empty string.
*
*/
static class PoppableNumber {
private int original;
private String number;
private int start;
private int next;
PoppableNumber(int value) {
this.original = value;
this.number = String.valueOf(value);
this.next = number.length();
this.start = (value < 0) ? 1 : 0; // allow for minus sign.
}
boolean isNegative() {
return (original < 0);
}
boolean hasMore() {
return (next > start);
}
String pop() {
return hasMore() ? number.substring(--next, next+1) : "";
}
}
}
I have written a program to solve Diophantine equations in the form
A5 + B5 + C5 + D5 + E5 = 0;
It should run in N3long(N) time, but it usually takes about 10 minutes for an input size of 100. Can anyone tell me whats wrong?
public class EquationSolver {
//Solves Equations of type: A^5 + B^5 + C^5 + D^5 + E^5 = F^5
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Enter a max value: ");
int N = input.nextInt();
long START_TIME = System.nanoTime();
SLinkedList test = new SLinkedList();
SLinkedList test2 = new SLinkedList();
test = setupLeftList(N);
test2 = setupRightList(N);
System.out.println("Note: This program takes about 7 minutes to complete for input of 100");
test = mergeSort(test);
test2 = mergeSort(test2);
long END_TIME2 = System.nanoTime() - START_TIME;
System.out.println("Total Time:" + END_TIME2/1000000000.0);
checkEquality(test, test2);
long END_TIME3 = System.nanoTime() - START_TIME;
System.out.println("Total Time:" + END_TIME3/1000000000.0);
}
public static SLinkedList setupLeftList(long boundary)
{
//Creates and returns an linkedList of all possible A,B,C values and their sums
SLinkedList leftSums = new SLinkedList();
for(long c = 0; c < boundary; c++)
{
for(long b = 0; b < c; b++)
{
for(long a = 0; a < b; a++)
{
long sum = (long)(Math.pow(a+1,5)) + (long)(Math.pow(b+1, 5)) + (int)(Math.pow(c+1, 5));
Node current = new Node (sum, a+1, b+1, c+1, null);
//System.out.println(sum);
leftSums.addLast(current);
}
}
}
return leftSums;
}
public static SLinkedList setupRightList(long boundary)
{
//Creates and returns an linkedList of all possible D,E,F values and their sums
SLinkedList rightSums = new SLinkedList();
for(int f = 0; f < boundary; f++)
{
for(int e = 0; e < f; e++)
{
for(int d = 0; d < e; d++)
{
long sum = (long)(Math.pow(f+1, 5)) - ((long)(Math.pow(d+1, 5)) + (long)(Math.pow(e+1,5)));
Node current = new Node (sum, d+1, e+1, f+1, null);
//System.out.println(current.getSum());
rightSums.addLast(current);
}
}
}
return rightSums;
}
public static SLinkedList mergeSort(SLinkedList sums)
// Sorts each list by the value of the sum
{
if (sums.length() > 1 )
{
SLinkedList[] splitList = split(sums);
SLinkedList s1 = mergeSort(splitList[0]);
SLinkedList s2 = mergeSort(splitList[1]);
sums = merge(s1, s2);
}
return sums;
}
public static SLinkedList[] split(SLinkedList sums)
{
// Splits a linked list into two (somewhat) equal halves
long midpoint = sums.length()/2;
Node midPoint = sums.elementAt(midpoint);
SLinkedList s1 = new SLinkedList(sums.head, midPoint, midpoint);
SLinkedList s2 = new SLinkedList(midPoint, sums.tail, midpoint);
SLinkedList[] both = new SLinkedList[]{s1, s2};
return both;
}
public static SLinkedList merge(SLinkedList s1, SLinkedList s2)
{
// Merges two sorted lists of elements
SLinkedList sMerged = new SLinkedList();
while(!s1.isEmpty() && !s2.isEmpty())
{
if (s1.getFirst().getSum() < s2.getFirst().getSum())
{
sMerged.addLast(s1.removeFirst());
}
else
{
sMerged.addLast(s2.removeFirst());
}
}
while(!s1.isEmpty())
{
sMerged.addLast(s1.removeFirst());
}
while(!s2.isEmpty())
{
sMerged.addLast(s2.removeFirst());
}
return sMerged;
}
public static void checkEquality(SLinkedList left, SLinkedList right)
{
// Checks two linked lists for nodes that contain the same Sum value
boolean ans = false;
while (left.isEmpty() == false && right.isEmpty() == false)
{
long currentLeft = left.getFirst().getSum();
long currentRight = right.getFirst().getSum();
if (currentLeft > currentRight)
{
right.removeFirst();
}
else if(currentLeft < currentRight)
{
left.removeFirst();
}
else
{
if (left.getFirst().getC() <= right.getFirst().getA())
{
System.out.println("Answer Found: " + "A: " + left.getFirst().getA() + " B: " + left.getFirst().getB() + " C: "
+ left.getFirst().getC() + " D: " + right.getFirst().getA() + " E: " + right.getFirst().getB() + " F: " + right.getFirst().getC());
ans = true;
}
Node temp = left.getFirst().getNext();
while (temp.getSum() == currentRight)
{
if (temp.getC() <= right.getFirst().getA())
{
System.out.println("Answer Found: " + "A: " + left.getFirst().getA() + " B: " + left.getFirst().getB() + " C: "
+ left.getFirst().getC() + " D: " + right.getFirst().getA() + " E: " + right.getFirst().getB() + " F: " + right.getFirst().getC());
ans = true;
}
temp = temp.getNext();
}
right.removeFirst();
left.removeFirst();
}
}
if (ans == false)
{
System.out.println("No answer found.");
}
}
}
The definitive answer is: use a profiler and see what causes a bottleneck...
But I see you have Math.pow() calls, all with longs, and their 5th power.
You could do it quicker, while even detecting the overflow:
public static long pow5(long base) {
if(base <=6208 && base >=-6208) {
return base*base*base*base*base;
} else {
throw new IllegalArgumentException("Overflow!");
}
}
(Magic number disclaimer: 62085 is ~263, is a number is bigger than that, the 5th power won't fit into 64 bits...)
Math.pow uses doubles, which means a lot of conversion in itself...
Also, #Floris pointed out that it is not even worth computing this over and over again - it could be put into a nice array, and just index that
public static long[] pow5 = getPow5(100);
public static long[] getPow5(long numElements) {
long[] toReturn = new long[numElements];
for(long i=0;long<numElements;long++) {
toReturn[i] = i*i*i*i*i;
}
return toReturn;
}
And where needed, instead of Math.pow(x, 5) just use pow5[x]
I have this following test code:
public static final String[] list = {
"apple","ball","cat","dog","egg","fan","girl","hat","igloo","jerk"
};
...
HashMap<DoubleKey<Integer, Integer>, String> hm = new HashMap<DoubleKey<Integer, Integer>, String>();
Set<DoubleKey<Integer, Integer>> s = new TreeSet<DoubleKey<Integer, Integer>>();
Random g = new Random();
for(int i=0; i<10; i++){
int first = g.nextInt(9999) + 1000;
int second = g.nextInt(9999) + 1000;
DoubleKey<Integer, Integer> k1 = new DoubleKey<Integer, Integer>(first, second);
DoubleKey<Integer, Integer> k2 = new DoubleKey<Integer, Integer>(first, second);
s.add(k1);
hm.put(k2, list[i]);
}
Set<DoubleKey<Integer, Integer>> ts = hm.keySet();
Iterator<DoubleKey<Integer, Integer>> itr = ts.iterator();
while(itr.hasNext()){
DoubleKey<Integer, Integer> k = itr.next();
System.out.println(k.getFirstKey().toString() + " + " + k.getSecondKey().toString() + " -> " + hm.get(k).toString());
}
System.out.println("----");
Iterator<DoubleKey<Integer, Integer>> sItr = s.iterator();
while(sItr.hasNext()){
DoubleKey<Integer, Integer> k = sItr.next();
String currStr = hm.get(k);
System.out.println(k.getFirstKey().toString() + " + " + k.getSecondKey().toString() + " -> " + currStr);
}
What I did is to create a Custom Generic Class DoubleKey<K, J> to contain a key having two parts. As you can see, the Set s and the keys of HashMap hm are have the same components, but was instantiated differently (k1 = k2). When I try to get a value using the keys on s to hm, it returns null, though at the first printing it shows the correct mapping.
Sample Output:
3922 + 2544 -> girl
9267 + 3750 -> hat
3107 + 10929 -> apple
5162 + 8834 -> fan
8786 + 1125 -> cat
10650 + 4078 -> egg
3808 + 7363 -> jerk
1364 + 7657 -> dog
1364 + 4412 -> ball
1583 + 1460 -> igloo
----
10650 + 4078 -> null
1364 + 4412 -> null
1364 + 7657 -> null
1583 + 1460 -> null
3107 + 10929 -> null
3808 + 7363 -> null
3922 + 2544 -> null
5162 + 8834 -> null
8786 + 1125 -> null
9267 + 3750 -> null
This is my DoubleKey implemention:
public class DoubleKey<K extends Comparable<K>,J extends Comparable<J>> implements Comparable<DoubleKey<K,J>>{
private K key1;
private J key2;
public DoubleKey(K key1, J key2){
this.key1 = key1;
this.key2 = key2;
}
public K getFirstKey(){
return this.key1;
}
public J getSecondKey(){
return this.key2;
}
// need for Comparable interface
public int compareTo(DoubleKey<K,J> aThat){
// NOTE: check for nulls
return (this.key1.toString() + this.key2.toString()).compareTo(aThat.key1.toString() + aThat.key2.toString());
}
public boolean equals(DoubleKey<K,J> aThat){
return (this.key1.toString() + this.key2.toString()).equals(aThat.key1.toString() + aThat.key2.toString());
}
}
How did it happened? Can two objecst (in this case from a custom generic) be different eve3n if they have instantiated with 2 same values? How can I correct this? I hope someone can help me here. Thanks!
Additionally to .hashCode(), you should have an implementation of equals(Object), not (only) equals(DoubleKey<...>), since otherwise you'll have two independent methods here (and only the first one is actually called by the HashMap). Here is a proposal:
public boolean equals(Object other) {
if(this == other)
return true;
if(!(other instanceof DoubleKey))
return false;
DoubleKey that = (DoubleKey)other;
return (this.key1 == null ? that.key1 == null : this.key1.equals(that.key1)) &&
(this.key2 == null ? that.key2 == null : this.key2.equals(that.key2));
}
The hashCode method should be made to fit this, too, for example like this:
public int hashCode() {
return key1.hashCode() * 3 + key2.hashCode() * 5;
}
Your key1.toString()+key2.toString() comparison is a bit dangerous, as it lets (1, 21).equals((12,1)) be true, which is usually not intended. The same is true for your compareTo method - compare the components using their compareTo method, not the concatenated String.
Learn this lesson now: If you override the equals method (as you have done), then you MUST override the hashcode method too. That method is used for various things, including looking up items in HashMaps.
Where is DoubleKey class's hashCode method override? I don't think that it will work as a proper key unless you implement this because otherwise your two objects will be considered different.