I am in the midst of learning about methods in Java and was curious to know if passing a method as an argument within another method is bad practice. Although I know there are many ways to achieve the same solution there are times in which code written in one way is more efficient than others.
For instance in the code exercise it was asked to create a method with two parameters(name and position)
and create a second method with one parameter(score). Then call both of these methods and display the results using the following score data (1500, 900, 400, 50).
My solution was written as follows:
public class Main {
public static void main(String[] args) {
displayHighScorePosition("Fred",calculateHighScorePosition(1500));
displayHighScorePosition("Ted", calculateHighScorePosition(900));
displayHighScorePosition("Jen", calculateHighScorePosition(400));
displayHighScorePosition("John",calculateHighScorePosition(50));
}
public static void displayHighScorePosition(String name, int highScorePosition) {
System.out.println(name + " managed to get into position " + highScorePosition + " on the high score table");
}
public static int calculateHighScorePosition(int score) {
int position = 4;
if(score >= 1000) {
position = 1;
} else if (score >= 500) {
position = 2;
} else if (score >= 100) {
position = 3;
}
return position;
}
}
This displayed the same output as what was expected by the exercise, but the code written in the exercise was
public class Main {
public static void main(String[] args) {
int highScorePosition = calculateHighScorePosition(1500);
displayHighScorePosition("Fred", highScorePosition);
int highScorePosition = calculateHighScorePosition(900);
displayHighScorePosition("Ted", highScorePosition);
int highScorePosition = calculateHighScorePosition(400);
displayHighScorePosition("Jen", highScorePosition);
int highScorePosition = calculateHighScorePosition(50);
displayHighScorePosition("John", highScorePosition);
}
public static void displayHighScorePosition(String name, int highScorePosition) {
System.out.println(name + " managed to get into position " + highScorePosition + " on the high score table");
}
public static int calculateHighScorePosition(int score) {
int position = 4;
if(score >= 1000) {
position = 1;
} else if (score >= 500) {
position = 2;
} else if (score >= 100) {
position = 3;
}
return position;
}
}
Does it make a difference? i.e. is one a better way to write or will I run into issues down the road when the code becomes much more complex?
You're not passing another method as a parameter, you're passing the return value of a method as a parameter, which is a totally different concept.
Anyway, the second example (apart from being syntactically wrong since you keep re-declaring a variable instead of just re-assigning a value to it) is just more verbose for no apparent gain, in this case.
It would make sense if you then used any of those declared variables someplace else down the method.
My code results with endless number "2", I don't understand why.
Also my tutor told me to add validation for negative values - I don't know how to do it.
public class FibonacciRecursive {
public static void main(String[] args) {
int fibonacciNumberOrder = 10;
do {
System.out.print(fibonacci(fibonacciNumberOrder) + " ");
} while (true);
}
public static long fibonacci(int fibonacciNumberInOrder) {
if (fibonacciNumberInOrder == 0) {
return 0;
}
if (fibonacciNumberInOrder <= 2) {
return 1;
}
long fibonacci = fibonacci(-1) + fibonacci(-2);
return fibonacci;
}
}
edit:
When I changed that line
long fibonacci = fibonacci(-1) + fibonacci(-2);
to:
long fibonacci = fibonacci(fibonacciNumberInOrder-1) + fibonacci(fibonacciNumberInOrder-2);
It prints endless "55"
How should I change my code to make it work?
It happens because you calculate the Fibonacci number with constants instead of relative numbers to passed ones through, which is the point of recursion.
public static long fibonacci(int fibonacciNumberInOrder) {
if (fibonacciNumberInOrder == 0) {
return 0;
}
if (fibonacciNumberInOrder <= 2) {
return 1;
}
long fibonacci = fibonacci(fibonacciNumberInOrder - 1) + fibonacci(fibonacciNumberInOrder - 2);
return fibonacci;
}
The key changed line is:
long fibonacci = fibonacci(fibonacciNumberInOrder-1) + fibonacci(fibonacciNumberInOrder-2);
You are recursing with constants! Change this
long fibonacci = fibonacci(-1) + fibonacci(-2);
to
long fibonacci = fibonacci(fibonacciNumberInOrder-1) + fibonacci(fibonacciNumberInOrder-2);
And, in your while loop in main - you need to modify fibonacciNumberInOrder
int fibonacciNumberOrder = 1;
do {
System.out.print(fibonacci(fibonacciNumberOrder) + " ");
fibonacciNumberOrder++;
} while (true);
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'm Making a game which uses a parent to run an attack class as shown below
public String attack(int damage, int extradamage, String type) {
int hitpossibility;
hitpossibility = (int) ((Math.random() * 100) + 1);
if (type.compareTo("Ranged") == 0) {
weaponnoise = "twang!";
}else{
weaponnoise = "swing!";
}
if (chancetohit >= hitpossibility) {
for (int x = 0; x < damage; x++) {
result = result + (int) ((Math.random() * 6) + 1);
}
result = result + extradamage;
return weaponnoise + " The " + name + " did " + +result + " damage";
}
return weaponnoise +"The " +name+" missed!";
}
I have multiple different weapons which i want to use and have succeded in this however i have a dagger which i would like to attack twice per turn instead of once like the others. This is the class which i use to set the daggers damage values:
public class Dagger extends Blade {
public Dagger() {
super();
damage = 1;
extradamage = -1;
chancetohit = 75;
}
public String attack(int damage, int extradamage, String type) {
return super.attack(damage, extradamage, type);
}
I then have a class that runs it and currently it does this:
for (int l = 0; l < 2; l++) {
System.out.println(pointy.attack(pointy.damage, pointy.extradamage, pointy.getType()));
monsterhealth = monsterhealth - pointy.result;
System.out.println(monsterhealth);
pointy.result = 0;
}
Instead of it printing the attack twice, i want it to attack twice on the same line. I was wondering what i can change in the dagger class which would allow me to do so.
Any help is of course appreciated thank you!
This answer is an explanation of #Arnav 's comments. Here Dagger is a sub-class of the main weapon class and you want to invoke super-class' attack twice when the attack method of Dagger is called.
For this you need to call super.attack twice from Dagger attack method:
public class Dagger extends Blade {
public Dagger() {
super();
damage = 1;
extradamage = -1;
chancetohit = 75;
}
public String attack(int damage, int extradamage, String type) {
String result1 = super.attack(damage, extradamage, type);
String result2 =super.attack(damage, extradamage, type);
return // You can return result1 or result2 based on your requirement
}
Note: I deleted my earlier answer, because this approach is better than the other one.
Is it possible to convert the function go into the non-recursive function? Some hints or a start-up sketch would be very helpful
public static TSPSolution solve(CostMatrix _cm, TSPPoint start, TSPPoint[] points, long seed) {
TSPSolution sol = TSPSolution.randomSolution(start, points, seed, _cm);
double t = initialTemperature(sol, 1000);
int frozen = 0;
System.out.println("-- Simulated annealing started with initial temperature " + t + " --");
return go(_cm, sol, t, frozen);
}
private static TSPSolution go(CostMatrix _cm, TSPSolution solution, double t, int frozen) {
if (frozen >= 3) {
return solution;
}
i++;
TSPSolution bestSol = solution;
System.out.println(i + ": " + solution.fitness() + " " + solution.time() + " "
+ solution.penalty() + " " + t);
ArrayList<TSPSolution> nHood = solution.nHood();
int attempts = 0;
int accepted = 0;
while (!(attempts == 2 * nHood.size() || accepted == nHood.size()) && attempts < 500) {
TSPSolution sol = nHood.get(rand.nextInt(nHood.size()));
attempts++;
double deltaF = sol.fitness() - bestSol.fitness();
if (deltaF < 0 || Math.exp(-deltaF / t) > Math.random()) {
accepted++;
bestSol = sol;
nHood = sol.nHood();
}
}
frozen = accepted == 0 ? frozen + 1 : 0;
double newT = coolingSchedule(t);
return go(_cm, bestSol, newT, frozen);
}
This is an easy one, because it is tail-recursive: there is no code between the recursive call & what the function returns. Thus, you can wrap the body of go in a loop while (frozen<3), and return solution once the loop ends. And replace the recursive call with assignments to the parameters: solution=bestSol; t=newT;.
You need to thinkg about two things:
What changes on each step?
When does the algorithm end?
Ans the answer should be
bestSol (solution), newT (t), frozen (frozen)
When frozen >= 3 is true
So, the easiest way is just to enclose the whole function in something like
while (frozen < 3) {
...
...
...
frozen = accepted == 0 ? frozen + 1 : 0;
//double newT = coolingSchedule(t);
t = coolingSchedule(t);
solution = bestSol;
}
As a rule of thumb, the simplest way to make a recursive function iterative is to load the first element onto a Stack, and instead of calling the recursion, add the result to the Stack.
For instance:
public Item recursive(Item myItem)
{
if(myItem.GetExitCondition().IsMet()
{
return myItem;
}
... do stuff ...
return recursive(myItem);
}
Would become:
public Item iterative(Item myItem)
{
Stack<Item> workStack = new Stack<>();
while (!workStack.isEmpty())
{
Item workItem = workStack.pop()
if(myItem.GetExitCondition().IsMet()
{
return workItem;
}
... do stuff ...
workStack.put(workItem)
}
// No solution was found (!).
return myItem;
}
This code is untested and may (read: does) contain errors. It may not even compile, but should give you a general idea.