I just started taking Computer Science (Java) about 5 weeks ago and I am still having trouble creating methods. I was assigned to create an NFL statistic class and then create a method to show a calculation. Everything went smooth until I went to call my method in a test class. What seems to be missing here?
NFLPlayer CLASS (Containin the method):
private int touchdowns;
private int interceptions;
private int passingAttempts;
private int completedPasses;
private int passingYards;
private int runningYards;
private int recievingYards;
private int tackles;
private int sacks;
// Method for Quarterback rating
public double QBRating(int touchdowns, int passingAttempts, int completedPasses,
int passingYards, int interceptions) {
double a = (completedPasses / passingAttempts - 0.3) * 5;
double b = (passingYards / passingAttempts - 3) * 0.25;
double c = (touchdowns / passingAttempts) * 25;
double d = 2.375 - (interceptions / passingAttempts * 25);
double ratingQB = ((a + b + c + d) / 6) * 100;
{
return ratingQB;
}
}
Now here is my test class where I am having trouble displaying my calculations
class MyTest {
public static void main(String[] args) {
NFLPlayer playerStats = new NFLPlayer();
//Player1 finding quarterback rating
int touchdowns = 2;
int passingAttempts = 44;
int passingYards = 285;
int interceptions = 1;
int completedPasses = 35;
// Call QB rating method
playerStats.QBRating(touchdowns, passingAttempts, completedPasses,
passingYards, interceptions);
System.out.println(QBRating);
}
}
Instead of passing so many int arguments (easy to mix them up) to your method you could give your NFLPlayer class private fields for each value:
public class NFLPlayer {
private final String name;
private int touchdowns;
private int passingAttempts;
private int completedPasses;
private int passingYards;
private int interceptions;
public NFLPlayer(String name) {
this.name = name;
}
// Method names start with a lower case character in Java
// The name should usually be an imperative 'do something' not a noun ('something')
// although there are exceptions to this rule (for instance in fluent APIs)
public double calculateQbRating() {
double a = (completedPasses / passingAttempts - 0.3) * 5.0;
double b = (passingYards / passingAttempts - 3.0) * 0.25;
// an AritmeticException will occur if passingAttempts is zero
double c = (touchdowns / passingAttempts) * 25.0;
double d = 2.375 - (interceptions / passingAttempts * 25.0);
return ((a + b + c + d) / 6.0) * 100.0;
}
public String getName() {
return name;
}
// setter for the touchdowns field
public void setTouchdowns(int value) {
touchdowns = value;
}
// TODO: add other setters for each private field
#Override
public String toString() {
return String.format("Player %s has QB rating %s", name, calculateQbRating());
}
}
Your application (this is not called a test):
class NFLApplication {
public static void main(String[] args) {
NFLPlayer playerStats = new NFLPlayer("johnson");
playerStats.setTouchdowns(2);
playerStats.setPassingAttempts(44);
playerStats.setPassingYards(285);
playerStats.setInterceptions(1);
playerStats.setCompletedPasses(35);
double qbRating = playerStats.calculateQbRating();
System.out.println(qbRating);
}
}
A test for your NFLPlayer class using the JUnit framework (JUnit is usually included by default within your IDE):
public class NFLPlayerTest {
// instance of the class-under-test
private NFLPlayer instance;
// set up method executed before each test case is run
#Before
public void setUp() {
instance = new NFLPlayer();
}
#Test
public void testCalculateQbRatingHappy() {
// SETUP
instance.setTouchdowns(2);
instance.setPassingAttempts(44);
instance.setPassingYards(285);
instance.setInterceptions(1);
instance.setCompletedPasses(35);
// CALL
double result = playerStats.calculateQbRating();
// VERIFY
// assuming here the correct result is 42.41, I really don't know
assertEquals(42.41, result);
}
#Test
public void testCalculateQbRatingZeroPassingAttempts() {
// SETUP
// passingAttempts=0 is not handled gracefully by your logic (it causes an ArithmeticException )
// you will probably want to fix this
instance.setPassingAttempts(0);
// CALL
double result = playerStats.calculateQbRating();
// VERIFY
// assuming here that you will return 0 when passingAttempts=0
assertEquals(0, result);
}
}
This test class should go in your test source directory (normally in yourproject/src/test/yourpackage/). It requires some imports which should be easily resolvable within the IDE since JUnit is usually available by default.
To run the test, right click on it and select something like 'Run test', 'Test file' or the like, depending on which IDE you are using (IDE's are development tools such as Eclipse, NetBeans or IntelliJ). You should see some test output indicating if the test succeeded (green) or if there were failures (red). Having such tests is useful because it forces you think about your design and write better code. (testable code is usually better than hard-to-test code) and because it warns you if new changes cause bugs in existing code (regression).
EDIT:
To create two players with different stats you have to create two instances (I added a name field so we can more easily distinguish the players):
NFLPlayer player1 = new NFLPlayer("adams");
NFLPlayer player2 = new NFLPlayer("jones");
And give them each their own statistics:
player1.setTouchdowns(2);
player1.setPassingAttempts(4);
player1.setPassingYards(6);
player1.setInterceptions(8);
player1.setCompletedPasses(10);
player2.setTouchdowns(1);
player2.setPassingAttempts(3);
player2.setPassingYards(5);
player2.setInterceptions(7);
player2.setCompletedPasses(9);
You could even create a list of players:
List<NFLPlayer> players = new ArrayList<>();
players.add(player1);
players.add(player2);
And then you could for instance print out all player ratings in a loop:
for(NFLPlayer player : players) {
// this uses the `toString` method I added in NFLPlayer
System.out.println(player);
}
you should not call the method name inside SOP instead System.out.println(playerStats.QBRating(touchdowns, passingAttempts, completedPasses,
passingYards, interceptions));
or override toString() method in your class and assign the method call to a local variable and print the value.
Also use some frameworks(Junit) instead of writing stubs
Related
I'm learning java at the moment and I've got a question about an object that got initialized and got a variable changed during the program execution.
public class Char {
private String name;
private int skill;
private int defense;
private int life;
private Weapon weapon = Weapon.FISTS;
private Potion potion = null;
So, I want this code to get the initial value of life that got initialized, but how would I access it?
public boolean isWeak() {
return life < this.life * 0.25;
}
So, this method is located in the Char class. I'm trying to get it to return a true value when it gets lower than 25%.
while (hero.isAlive() && monster.isAlive()) {
if (hero.isWeak() && hero.hasPotion()) {
hero.sip();
} else if (monster.isWeak() && monster.hasPotion()){
monster.sip();
} else {
System.out.println(monster.isWeak());
hero.attack(monster);
if (monster.isAlive()) {
monster.attack(hero);
}
System.out.println();
}
}
Here is the execution program. All the other methods work just fine, but as pointed out, it'll never return true because it can't be a quarter of itself. Don't mind the prints, I'm just testing it.
To do this, you need to create a second variable that stores the value passed into the constructor:
public class Char {
private String name;
private int skill;
private int defense;
private int initialLife;
private int life;
private Weapon weapon = Weapon.FISTS;
private Potion potion = null;
public Char(int initialLife //I am excluding all the other parameters you want to pass in
) {
this.life = initialLife;
this.initialLife = initialLife;
}
public boolean isWeak() {
return life < this.initialLife * 0.25;
}
}
As you can see, I store the initial life and I don't ever modify it. Since I modify the life variable, I can't use it to keep track of the initial value. Modifying a variable is a destructive process, and Java doesn't have a way to keep track of the history of variable values (unless you do it yourself as shown above).
So basically my program is a StudySchedule where it takes user input (StudyTime, Subjects, PrioritizedSubjects, PriorityScale) and then creates a schedule based off each of those values. It begins with a class CreateSchedule which takes all the user input and then my other class CalculateScheduleTime takes the input and makes calculations (Calculate does extend to Create).
But when I request the variables from CreateSchedule, to CalculateScheduleTime, the variables appear as 0.0 rather than the number I had put in.
class CreateSchedule extends Test {
public String ScheduleName;
public double userStudyTime;
public double userSubjects;
public double userPrioritySubjects;
public double userSubjectScale;
public String getScheduleName() {
ScheduleName = setScheduleName();
return (ScheduleName);
}
public double getuserStudyTime() {
userStudyTime = setuserStudyTime();
return (userStudyTime);
}
public double getuserSubjects() {
userSubjects = setuserSubjects();
return (userSubjects);
}
public double getuserPrioritySubjects() {
userPrioritySubjects = setuserPrioritySubjects();
return (userPrioritySubjects);
}
public double getuserPriorityScale() {
userSubjectScale = setuserPriorityScale();
return (userSubjectScale);
}
public static String setScheduleName(){
System.out.println("What would you like to name your Schedule?");
Scanner sch = new Scanner(System.in);
return sch.nextLine();
}
public static double setuserStudyTime(){
System.out.println("How many hours are you studying for?");
Scanner sch = new Scanner(System.in);
return sch.nextDouble();
}
public static double setuserSubjects (){
System.out.println("How many subjects are you studying?");
Scanner sch = new Scanner(System.in);
return sch.nextDouble();
}
public static double setuserPrioritySubjects (){
System.out.println("How many subjects are you prioritizing?");
Scanner sch = new Scanner(System.in);
return sch.nextDouble();
}
public static double setuserPriorityScale (){
System.out.println("On a scale of 1 - 5, how much priority would you like to give the prioritized subjects?");
Scanner sch = new Scanner(System.in);
return sch.nextDouble();
}
public double confirm() {
System.out.println("Input Results:");
System.out.println("Schedule Name: " + ScheduleName);
System.out.println("Study Time: " + userStudyTime);
System.out.println("Subjects: " + userSubjects);
System.out.println("Priority Subjects: " + userPrioritySubjects);
System.out.println("Priority Scale" + userSubjectScale);
return (0);
}
}
class CalculateScheduleTime extends CreateSchedule {
public double SubjectPriorityTime;
public double SubjectRemainderTime;
public CalculateScheduleTime() {
}
public double calcSubjectPriorityTime() {
System.out.println("Priority" + userSubjectScale);
double PriorityPercent = ((double) (userSubjectScale / 5.0));
System.out.println(userSubjectScale);
SubjectPriorityTime = ((double) (PriorityPercent * userStudyTime));
System.out.println("Time to Prioritized Subject is: " + SubjectPriorityTime);
return (SubjectPriorityTime);
}
public double calcSubjectRemainderTime() {
System.out.println("Remainder");
SubjectRemainderTime = ((double) (SubjectPriorityTime - userStudyTime));
System.out.println("Remainder time to Subject is: " + SubjectRemainderTime);
return (SubjectRemainderTime);
}
}
public class Test {
public static void main(String[] args) {
CreateSchedule user = new CreateSchedule();
user.getScheduleName();
user.getuserStudyTime();
user.getuserSubjects();
user.getuserPrioritySubjects();
user.getuserPriorityScale();
user.confirm();
CalculateScheduleTime calc = new CalculateScheduleTime();
calc.calcSubjectPriorityTime();
calc.calcSubjectRemainderTime();
}
}
That's not what subclassing is for.
A class describes what a given instance can do. "Dog" is a class. "Lassie" is an instance of it.
Subclassing is a thing you do to concepts, not instances. You might for example have a class "Animal", and a subclass "Dog": Dog simply specializes Animal: Any Dog is also an Animal and therefore can do and has all the properties that all Animals have, and perhaps a few additional things and properties (in java parlance: It would have all fields and methods of the superclass, and can add more. It cannot remove any).
When you write CreateSchedule user = new CreateSchedule(); that's like writing: Dog rover = new Dog(); - then you write CalculateScheduleTime calc = new CalculateScheduleTime(); which is like writing GermanSchnauser fifi = new GermanSchauser();.
You made a whole new dog, which gets its own copy of all those fields, which are all still 0 - uninitialized.
The 'calc' stuff should just go in CreateSchedule, probably. But there is a ton wrong with this code:
Classes represent tangible concepts. A good class name is 'Schedule'. Or perhaps 'ScheduleCreator'. 'CreateSchedule' is not a proper class name, and thinking about it as 'the code for creating schedules' is just plain incorrect, the right way to think about classes is about what they represent. "It is the code that explains what Schedules can do and how to create them", that's a proper way to think about it (and that class would be called Schedule. Not CreateSchedule).
methods named getX should not have sideeffects.
You should not be making a new scanner every time.
setters take an argument. They don't ask the user.
Separate concerns. A Schedule should just do schedule stuff - something else should be doing the interaction with the user. Either a main method or a class for this (perhaps TextBasedScheduleCreator).
Those calcX() methods store the result in a field, return it, and that field is never actually used anywhere. Just return it, don't have that field.
I am programming a Study in MotiveWave, a program used for (day)trading. The study is its own class. (info about MotiveWave's SDK found here: https://www.motivewave.com/sdk/javadoc/overview-summary.html)
public class L_V2 extends com.motivewave.platform.sdk.study.Study
My study uses 2 different timeframes: the 1 hour and the 4 hour bars. Both are calculated in a different function. Otherwise formulated: both use a different dataseries, as shown in the code below.
I have two values, being calculated on the 4 hour timeframe, called 'ma9' and 'ma11' that I would like to use in an 'if'-statement on the 1 hour timeframe.
This is the code for the 4 hour timeframe. It simply calculates 2 moving averages
#Override
protected void calculateValues(DataContext ctx)
{
int maPeriodTF2 = getSettings().getInteger(MA_PERIOD_TF2);
int ma2PeriodTF2 = getSettings().getInteger(MA2_PERIOD_TF2);
//Object maInput = getSettings().getInput(MA_INPUT, Enums.BarInput.CLOSE);
BarSize barSizeTF2 = getSettings().getBarSize(MA_BARSIZE_TF2);
DataSeries series2 = ctx.getDataSeries(barSizeTF2);
StudyHeader header = getHeader();
boolean updates = getSettings().isBarUpdates() || (header != null && header.requiresBarUpdates());
// Calculate Moving Average for the Secondary Data Series
for(int i = 1; i < series2.size(); i++) {
if (series2.isComplete(i)) continue;
if (!updates && !series2.isBarComplete(i)) continue;
// MA TF2
Double ma9 = series2.ma(getSettings().getMAMethod(MA_METHOD_TF2), i, maPeriodTF2, getSettings().getInput(MA_INPUT_TF2));
Double ma11 = series2.ma(getSettings().getMAMethod(MA2_METHOD_TF2), i, ma2PeriodTF2, getSettings().getInput(MA2_INPUT_TF2));
series2.setDouble(i, Values.MA9_H4, ma9);
series2.setDouble(i, Values.MA11_H4, ma11);
}
// Invoke the parent method to run the "calculate" method below for the primary (chart) data series
super.calculateValues(ctx);
I would now like to use those 2 values, 'ma9' and 'ma11' in another function, on the 1 hour timeframe:
#Override
protected void calculate(int index, DataContext ctx)
DataSeries series=ctx.getDataSeries();
if (ma9 < ma11 && other conditions)
{ctx.signal(index, Signals.YOU_SHOULD_BUY, "This would be my buying signal", series.getClose(index));
}
How can I export the ma9 and the ma11 so they become 'global' and I can re-use them in this other function ?
Basically, the idea is to store somewhere the values or just pass them appropriately after being computed.
There is a java pattern based on singleton that allow you to store/retrieve values inside a class (using a collection : HashMap). Any values could be added,retried in any classes based on predefined (key,value) using the construction Singelton.getInstance() with HashMap standard operation (put, get).
Maybe this example could be useful.
import java.util.Hashtable;
class Singleton extends Hashtable<String, Object> {
private static final long serialVersionUID = 1L;
private static Singleton one_instance = null;
private Singleton() {
};
public static Singleton getInstance() {
one_instance = (one_instance == null) ? new Singleton() : one_instance;
return one_instance;
}
}
import java.util.Random;
public class Reuse {
public static void main(String[] args) {
Reuse r = new Reuse();
Compute c = r.new Compute();
Singleton.getInstance().put("r1", c.getRandom());
Singleton.getInstance().put("r2", c.getRandom());
Singleton.getInstance().put("n", c.getName());
System.out.println(Singleton.getInstance().get("r1"));//print random_number_1
System.out.println(Singleton.getInstance().get("r2"));//print random_number_2
System.out.println(Singleton.getInstance().get("n"));// print name (value for key n)
}
class Compute
{
public Double getRandom()
{
return new Random().nextDouble();
}
public String getName()
{
return "name";
}
}
}
I had to create this point program a year ago, a year ago it worked fine. Now I have to revisit it and upon compiling and trying to run it I ran into the error of the fact that an abstract class cannot be instantiated. I have done some looking around online and figured out that some update or sort with Java has made it where the method of using PointClass point1 = new PointClass(); is no longer valid and will through an error.
I have yet to find an answer for fixing the error when trying to instantiate the class using a driver program. I also saw that in order to use an abstract class now, a subclass must be present. The thing is is that due to the instructions of the program I cannot use a subclass. Only the driver and the point class.
The program is very simple, just declare some points and call them from the abstract class in order to print to the screen. I need some help on figuring out the updated method to make this work again without the instantiated error.
The PointClass
public abstract class PointClass {
private int pointX;
private int pointY;
//set instance variables
public PointClass() { this.pointX = 10; this.pointY = 10; }
public PointClass(int x, int y){ this.pointX = x; this.pointY = y; }
//make getters and setters
public void setPointX(int x) { this.pointX = x; }
public void setPointY(int y) { this.pointY = y; }
public int getPointX() { return this.pointX; }
public int getPointY() { return this.pointY; }
//make string for format with driver
public String toString() { return "x = " + this.pointX + " y = " + this.pointY; }
}
The Driver
public class PointTest {
public static void main(String[] args){
System.out.println();
PointClass point1 = new PointClass(); //set point1 as no argument
PointClass point2 = new PointClass(11, 24); // set point2 as argument with x and y
System.out.println("Point1: " + point1); //display point1 from toString method
System.out.println();
System.out.println("Point2: " + point2); //display point2 from toString method
System.out.println("---------------------");
}
}
The best thing to do would be to remove the abstract keyword. There's no need for it. Point has no abstract methods.
If you can't do that for whatever reason, you can create inline anonymous classes by adding curly braces after each instantiation:
PointClass point1 = new PointClass() { };
PointClass point2 = new PointClass(11, 24) { };
By the way, your claim that this used to work is incorrect. It has never been possible to directly instantiate an abstract class. That is in fact the entire point of the keyword, to prevent a class from being instantiated.
I have information like this:
xxx 0 1 2 ...
Name Fred0 Fred1 Fred2
Stamina 2 6 7
Intel 5 4 1
Heart 4 8 2
Speed 5 3 6
So, I was informed previously that creating a 2D ArrayList to store something like this is "archaic" and was provided with a different way to set my code up. The reason I was using ArrayList<> is because I want to be able to generate new racers as needed, rather than designating an array to a size. If I could just use a simple array this would have been done a week ago. Now I've been screwing with it for a week and I still don't get how it works.
public class test {
public String name;
private int stamina;
private int heart;
private int intel;
private int speed;
public ArrayList<String> racers = new ArrayList<String>();
private void racerInfo(String name) {
this.name = name;
this.stamina = (int) Math.floor(Math.random()*10);
this.heart = (int) Math.floor(Math.random()*10);
this.intel = (int) Math.floor(Math.random()*10);
this.speed = (int) Math.floor(Math.random()*10);
}
public void generate() {
for ( int i=0; i<=10; i++) {
String name = "Fred" + i;
System.out.println(name);
racerInfo(name);
racers.add(name);
}
}
public int getStamina() {
return this.stamina;
}
public int getHeart() {
return this.heart;
}
public int getIntel() {
return this.intel;
}
public int getSpeed() {
return this.speed;
}
}
public class main {
public static test test = new test();
public static void main(String[] args) {
test.generate();
//Put stuff here to pull stamina of Fred2 for example.
}
}
Now, in the main class. How would I do something that should be relatively simple like pulling the Stamina value for Fred2.
I've been following the exact directions I've been given by others here to write most of this code. But at this time, I'm getting to the point of just re-writing it all so that each stat (name, stamina, intel, speed, etc.) is just logged as a separate ArrayList<>. But I can't figure out how to make a 2D ArrayList containing the original ArrayLists ie.
ArrayList<String> name = new ArrayList<String>();
ArrayList<Integer> stamina = new ArrayList<Integer>();
ArrayList<ArrayList<Object>> arrayOfArray = new ArrayList<ArrayList<Object>>();
Yes, I know the arrayOfArray is probably done wrong, but, again, I just get told it's Archaic and nobody'll tell me how I can do it right so I can just go. arrayOfArray.get(2,1) and pull information that I want/need.
Sorry for the information overload here. but I'm trying to just find the best possible solution for what I want to do. If you can tell me how to correctly pull off either way I will be eternally grateful you you and all of your descendants.
First of you should refactor your class test to class Racer, which is a meaningful name and follows the convention to start classnames with an uppercase letter. Furthermore you should add Stamina, Intel, Heart and Speed to the constructor:
public Racer(String name, int stamina, int intel, int heart, int speed) {
this.name = name;
this.stamina = stamina;
this.intel = intel;
this.heart = heart;
this.speed = speed;
}
Now you can create your racer as following:
Racer fred2 = new Racer("Fred2", 7, 1, 2, 6);
You can store your values in a HashMap. HashMap is a collection consisting of key-value pairs. For the key you can use a string (the name of the racer) and as value you take an instance of your class Racer:
HashMap<String, Racer>() racerMap = new HashMap<>();
racerMap.put("Fred2", fred2);
This you can do in a for-loop for all of your racers. Now you can get the racer objects from your HashMap by calling the getMethod and putting the name as parameter in it. This will return an object of class Racer and you can call the getter methods on this object:
racerMap.get("Fred2").getSpeed();
or
racerMap.get("Fred2").getIntel();
Edit: I just saw your generate method. This method should return the HashMap of racers. In your main method you create a new HashMap:
HashMap<String, Racer> racerMap = generate();
Now you can use the map as described above.