Constructor chaining and preparing arguments before calling this(aguments) - java

I am making a Yahtzee game. I want to supply a constructor for different cases. Suppose you couldn't be bothered to supply the names of the players that you want to create a new game with, I'd like to just create "Unnamed Player 1", "Unnamed Player 2", etc.
Here is how I am trying to do that:
public class YahtzeeGame {
private List<Player> players = new ArrayList<>();
public YahtzeeGame(String[] playerNames) {
for (String playerName : playerNames) {
players.add(new Player(playerName));
}
}
public YahtzeeGame(int numberOfPlayers) {
String[] playerNames = new String[numberOfPlayers];
for (int i = 0; i < numberOfPlayers; i++) {
playerNames[i] = "Unnamed player " + (i+1);
}
this(playerNames); // ERROR: "Constructor call must be the first statement in a constructor.
}
public YahtzeeGame(String playerName) {
this(new String[] {playerName});
}
public YahtzeeGame() {
this("Unnamed player");
}
}
This doesn't work of course, as per the error written in the comment.
Is there a way around this? Do I need a factory pattern for this?

Yes, there's fairly simple way around it, at least in this case: create a static method which will prepare the constructor argument for you. Call that from the this expression:
public YahtzeeGame(int numberOfPlayers) {
this(getUnnamedPlayers(numberOfPlayers));
}
private static String[] getUnnamedPlayers(int numberOfPlayers) {
String[] playerNames = new String[numberOfPlayers];
for (int i = 0; i < numberOfPlayers; i++) {
playerNames[i] = "Unnamed player " + (i+1);
}
return playerNames;
}
Note that it does have to be static, because you can't call any instance methods on this before the chained constructor, either.

Related

Passing method in other method Java

I want to make a simple program to compare how long time takes rewrite and print out collection of Strings by `for loop`, `foreach` or `stream`. String is sentence where it replaces "i" by "y". In my case I made `count()` where I set to count `stream()` method but I want to make universal measuring method. But i dont know how to do it... It should works like: in Main class is `counter(forLoop);` It should call `forLoop();` from Method class `counter(forEach);` It should call `forEach();` from Metrod class`counter(stream);` It should call ` stream();` From Method class IDont know how to pass method as a parameter
I have class where are those metods:
import java.util.*;
import java.util.stream.*;
public class Methods {
private List<String> sentence = new ArrayList<>();
private String oldLetter = "i";
private String newLetter = "y";
private String methodType;
public String getMethodType() {
return methodType;
}
//making a collection with String
public void setSizeOfCollection(int size){
for (int i = 0; i < size; i++) {
sentence.add("Siti Zbinek plitce zvikal sirovi pelinek.");
}
}
public void forLoop(){
methodType = "For loop";
for (int i = 0; i < sentence.size(); i++) {
for (int j = 0; j < sentence.size(); j++) {
String replaceLetters = sentence.get(j);
replaceLetters = replaceLetters.replaceAll(oldLetter, newLetter);
sentence.set(j, replaceLetters);
}
System.out.println(sentence.get(i));
}
}
public void forEach(){
methodType = "For each";
String replacedLetters = "";
for(String oneLine: sentence){
for(String originalLetters: sentence){
replacedLetters = originalLetters.replaceAll(oldLetter,newLetter);
}
System.out.println(replacedLetters);
}
}
public void stream(){
methodType= "Stream";
sentence.stream()
.map(e->e.replaceAll(oldLetter,newLetter))
.collect(Collectors.toList())
.forEach(System.out::println);
}
}
This is count() that works fine, but only for method stream(). In comment is my imagine how it should be. But I dont know how it do by Java :(
import org.apache.commons.lang.time.*;
public class Counter {
private Methods methods;
private String methodType;
private StopWatch stopWatch = new StopWatch();
long timeTaken = 0;
//here should be something like any method as a parameter XXX xxx
// public void count(Methods methods XXX xxx)
public void count(Methods methods){
stopWatch.start();
// here sould be something what call any function by your choice, not only stream()
// methods.xxx;
methods.stream();
stopWatch.stop();
timeTaken= stopWatch.getTime();
System.out.println(methods.getMethodType()+" takes "+ timeTaken + " ms." );
}
}
And finally Main class
public class Main {
public static void main(String[] args) {
Methods methods = new Methods();
Counter counter = new Counter();
methods.setSizeOfCollection(10000);
counter.count(methods);
//here should be finally three times method, with different parameters:
// counter.count(methods, forEach);
// counter.count(methods, forLoop);
// counter.count(methods, stream);
}
}
Any advice please?
All your methods have the signature void(). Consequently, a reference to each method can be stored in a Runnable instance.
public void count(final Runnable method) {
stopWatch.start();
method.run();
stopWatch.stop();
timeTaken= stopWatch.getTime();
System.out.println(methods.getMethodType()+" takes "+ timeTaken + " ms.");
}
And then call as:
final Methods methods = new Methods();
final Counter counter = new Counter();
methods.setSizeOfCollection(10000);
counter.count(methods::stream); // or count(() -> methods.stream());
counter.count(methods::forEach); // count(() -> methods.forEach());
counter.count(methods::loop); // count(() -> methods.loop());
To be able to use method refs or lambdas, you need to have at least Java 8. For earlier Java versions, you would need to implement Runnable with an anonymous class, e.g.
counter.count(new Runnable() {
#Override public void run() { methods.stream(); }
});
or look up the methods by name via Reflection, but Reflection is usually the slowest option.
PS. Note however that your way of measuring method execution times is flawed; see How do I write a correct micro-benchmark in Java? for directions. This answer only explains the part of passing "methods" to another method.
you could pass the method name as a string and look for it with reflexion.

Trying to create a class that contains objects from another class

I have created a class called Album, which is this one:
public class Album {
private String Titulo;
private int temas;
private int ano;
public Album(String Titulo2, int temas2, int ano2) {
this.Titulo = Titulo2;
this.temas = temas2;
this.ano = ano2;
}
public Album(String Titulo2, int temas2) {
this.Titulo = Titulo2;
this.temas = temas2;
}
public int getAno() {
return this.ano;
}
public int getTemas() {
return this.temas;
}
public String getTitulo() {
return this.Titulo;
}
public void setAno(int ano) {
this.ano = ano;
}
public boolean foiEditadoNesteSeculo() {
if (this.ano > 2000) {
return true;
} else {
return false;
}
}
public void adicionaTemasBonus(int x) {
this.temas += x;
}
public void mostraAlbum() {
System.out.println(this.Titulo + " (editado em " + this.ano + "; tem " + this.temas + " temas)");
}
}
It works fine. The problem is that the teacher asked me to create a new class called Band and it has to have an array of Albums. The Band object should be declared with an int that represents the limit of the number of albums (the length of the array). I already have some idea on how to work with arrays, but I have no idea on how to create a type of array that contains objects from another class, and after how to use the attributes of the objects to return something. I think I can figure out the rest after I'm able to properly create the class, though.
Apologies, as it has been described in Portuguese and I don't have much experience in translating.
In my opinion this would be easier to manage with a List so you can add as many Albums as you want at any time, however, since the problem statement required Array I made an example of a Band class.
I also included main method to test the program at the bottom of the Band class:
public class Band {
private int totalAlbums;
private Album[] albums;
private int currentNumberOfAlbums;
public Band(int totalAlbums) {
this.totalAlbums = totalAlbums;
this.albums = new Album[totalAlbums];
this.currentNumberOfAlbums = 0;
}
public Band(Album[] albums) {
this.totalAlbums = albums.length;
this.albums = albums;
this.currentNumberOfAlbums = this.totalAlbums;
}
public void addNewAlbum(String titulo, int temas, int ano) {
if (this.currentNumberOfAlbums == totalAlbums) {
System.out.println("Warning: Cannot add any more albums, limit reached.");
return;
}
this.albums[this.currentNumberOfAlbums++] = new Album(titulo, temas, ano);
}
public void printAlbums() {
for (Album a : this.albums) {
a.mostraAlbum();
}
}
public static void main(String [] args) {
Band b = new Band(3);
b.addNewAlbum("The First", 4, 2001);
b.addNewAlbum("The Second", 98, 2055);
b.addNewAlbum("The Finale", 12, 2011);
b.addNewAlbum("The Extra", 12, 2111);
b.printAlbums();
}
}
There are a few things to look for in this code.
First, to address your direct question, you can simply use a custom class as an array like any other class/primitive with Album[].
Secondly, you will require a Band constructor that instantiates the array of Album based on an integer passed to it, so you know how many albums are the limit. You can see this with the this.albums = new Album[totalAlbums]; line.
Next, you need a way to add a new Album into the array of Album[]. This can be done a few different ways, but the way I chose was to create a method addNewAlbum(String, int, int) to do it for this example which will also increase currentNumberOfAlbums by 1 every time a new album is added. This is useful so you know when an Album is attempted to be added even though the totalAlbums are already full! This will prevent an ArrayIndexOutOfBoundsException in your code if addNewAlbum is called too many time.
Lastly, in addNewAlbum you need to call your Album constructor with new Album(titulo, temas, ano).
In my example main, a Band with limit of 3 albums is created, and 4 albums are attempted to be added into it, with the first 3 adding successfully, and the 4th not being added, but instead printing a warning for being outside the limit.
I also added a printAlbums() method which will use your mostraAlbum() to print each Album in the albums array.
Output:
Warning: Cannot add any more albums, limit reached.
The First (editado em 2001; tem 4 temas)
The Second (editado em 2055; tem 98 temas)
The Finale (editado em 2011; tem 12 temas)
EDIT:
I added the Band(Album[] albums) constructor, you can call this with:
Album[] albums = new Album[3];
//Add your albums into this variable
Band b = new Band(albums);
public class Band {
private Album[] albums;
private numberOfAlbums;
//...
// create an empty constructor
Band(){
albums = new Album[];
numberOfAlbums = 0;
}
// constructor that receives the albums
Band(Album[] albums){
this.albums = albums;
this.numberOfAlbums = albums.length;
}
// constructor that receives the number of albums
Band(int numOfAlbums){
this.numberOfAlbums = numOfAlbums;
this.albums = new Album[numOfAlbums];
}
// add getters and setters
// example of adding a new album
public void addNewAlbum(Album album){
if(this.numOfAlbums == this.albums.length){
// you need to create a new array with a bigger size, copy the existing data and insert the album
// or whatever you'd like
} else {
this.albums[this.numOfAlbums] = album;
// increment the numOfAlbums
this.numOfAlbums++;
}
}
}
private class Album {
//...
}
You just need to add [] to define that the field is an array.
public class Band {
private int totalAlbums;
private Album[] albums;
//...
}
private class Album {
//...
}
I hope this example helps you.
private Album[] albums; // array of album
private int albumLimit; // limit for album
public Band(int albumLimit) {
this.albumLimit = albumLimit; // initialize limit
this.albums = new Album[albumLimit]; // set limit of album array
}
// here it creates a new Album every time the loop runs
// you can fill the array in other ways too
public void fillAlbum() {
for (int i = 0; i < albumLimit; i++) {
String name = "name_" + i;
int team = i;
albums[i] = new Album(name, team);
}
}
public void printAlbum() {
for (int i = 0; i < albumLimit; i++) {
System.out.println("Name :" + albums[i].getTitulo());
System.out.println("Team :" + albums[i].getTemas());
System.out.println();
}
}
}

Storing object into an array - Java

I am relatively new to Java and I have taken some light courses on it. I am trying to emulate an exercise that I had a while back and I am having some trouble.
I have two classes. One is taking in data and the other is storing it.
public class Car{
public Car(String name, String color)
{
this.name = name,
this.color = color
}
How can I store this into the array (not an array list) that I created in this class:
public class CarDatabase {
Car[] carList = new Car[100];
public CarDatabase()
{
// System.out.println("test");
}
public void createAccount(String name, String color)
{
// this is where I am having trouble
for (int i = 0; i < carList.length; i++)
{
System.out.println("Successfully created: " + name +
"." + "Color of car: " + color);
break;
}
}
I don't have a main method yet but I will need one later on to for example, PRINT out this array and that is what I can't wrap my head around - how do I store DATA/OBJECTS into the "CarDatabase" array so I can call methods with it later (instead of just being able to print it)?
Any help would be appreciated.
Thanks!
Not really sure what you are trying to achieve but I'll give it a go.
You could modify your CarDatabase class like so -
public class CarDatabase {
Car[] carList = new Car[100];
int carsStored;
// No need for a constructor since we don't need any initialization.
// The default constructor will do it's job.
public void createAccount(String name, String color) {
carList[carsStored++] = new Car(name, color);
}
}
And your main method could look like -
public static void main(String[] args) {
CarDatabase database = new CarDatabase();
database.createAccount("Lambo", "Red");
database.createAccount("Punto", "White");
// To loop through your database, you can then do
for(int i = 0; i < database.carList.length; i++) {
Car car = database.carList[i];
// Now you can call methods on car object.
}
}
Hope that helps.

Better way to call common method on randomly selected object in java

Nice day to everybody.
I have an abstract class with the method runRandomExercise(), and several classes that extends it to add different kind of exercise.
I now want to chose a random type exercise, so I need to randomly choose one of the classes, and call runRandomExercise() on that.
For now I am manually coding this, which is not the very best solution I think. However, I can’t store just the classes in the array since the class type is different, and if I use object[] I can’t call the runRandomExercise() method. Any smart way to handle this?
Here is my code till now. It works, but it’s gonna be a pain to add other classes...
/*Specific classes that extend abstract class TrainingClass with the runRandomExercise() method*/
private MatheMagic mMathMag;
private Mnemonics mMnemonics;
private String[] mTrainingClasses;
/*Initialize classes*/
mMathMag = new MatheMagic();
mMnemonics = new Mnemonics();
/*Manually store classe names*/
mTrainingClasses = new String[2];
mTrainingClasses[0] = "mMathMag";
mTrainingClasses[1] = "mMnemonics";
/*Return random exercise*/
public String[] RandomExercise() {
Random aGenerator = new Random();
/*Get random class name*/
int rnd = aGenerator.nextInt(mTrainingClasses.length);
String aChosen = mTrainingClasses[rnd];
String[] aRes = new String[2];
if (aChosen == "mMathMag") {
aRes = mMathMag.runRandomExercise();
} else if (aChosen == "mMnemonics") {
aRes = mMnemonics.runRandomExercise();
}
return aRes;
}
EDIT
Here is how TrainingClass is defined:
/** Common interface for all exercises */
public interface Exercise {
public String[] run();
}
/** Common interface for all training classes */
public abstract class TrainingClass {
private Random mRandGen = new Random();
public ArrayList<Exercise> mExerciseTypes = new ArrayList<Exercise>();
/** Run a random exercise */
public String[] runRandomExercise() {
int i = mRandGen.nextInt(mExerciseTypes.size());
return mExerciseTypes.get(i).run();
}
}
/*Specific training class*/
public class MatheMagic extends TrainingClass {
public MatheMagic() {
class SomeExercise implements Exercise {
public String[] run() {
String[] mRes = new String[2];
mRes[0] = "Question type 1";
mRes[1] = "Answer type 1";
return mRes;
}
}
class SomeOtherExercise implements Exercise {
public String[] run() {
String[] mRes = new String[2];
mRes[0] = "Question type 2";
mRes[1] = "Answer type 2";
return mRes;
}
}
SomeExercise mN = new SomeExercise();
SomeOtherExercise mS = new SomeOtherExercise();
mExerciseTypes.add(mN);
mExerciseTypes.add(mS);
}
}
Easy solution is to create an interface with the common method and have all your classes extend it.
Create a collection or array of that type instead of Object; you can simply iterate through or randomly select and call the method you want.
It feels like a Command pattern from GoF to me.
public interface Exercise {
void execute();
}
Now your classes do this:
public class MatheMagic implements Execise {
public void execute() {
// special logic here.
}
}
Then you can do this:
int numExercises = 1;
Exercise [] exercises = new Exercise[numExercises];
exercises[0] = new MatheMagic();
for (Exercise exercise : exercises) {
exercise.execute();
}
Yes, yes you can store all those Classes in an array and then call them at random. How? Create an interface and in all your classes derive from that interface. That way you can invoke based on interface, and not on implementation.

How do you pass in an array from the main method to another method in java?

I have an array of Person in my main method, and I have to pass in that array to PlayGame() method in the class Game. How do you do that?
public class RollOff {
public static void main(String[] args) throws IOException{
int numPeople;
int a;
System.out.println("How many people will play the game?");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
numPeople = Integer.parseInt(s);
if ((numPeople >= 2) && (numPeople <= 10)) {
Person[] p = new Person[numPeople];
for (a = 0; a < numPeople; a++) {
p[0] = new Person(a);
}
}
}
}
public class Game extends RollOff{
int numPeople;
int a;
void PlayGame() {
}
}
You need to use parameters to do that:
void playGame(Person[] p){
...
}
Now simply call
public static void main(String[] args){
...
game.playGame(p);
}
Because playGame is not a static method, you'll either need to make it static and call Game.playGame(p) or you'll need to create an instance of Game: Game game = new Game() followed by a call of game, as shown in the example above.
public void play(Person[] person) {
// code
}
// The call
play(person);
You can simply add a Person array parameter to the PlayGame
void playGame(Person[] personArray){//logic of the method}
Then all you have to do is call the playGame method from the main method by creating a new instance of the class Game
Game game = new Game();
game.PlayGame(p);
here "p" is your persons array.
The main class should create an instance of Game, and pass the array of players to the constructor:
Game game = new Game(p);
game.playGame();
The Game class should thus have the following field and constructor:
private Person[] players;
public Game(Person[] players) {
this.players = players;
}
Note that methods should start with a lower-case letter to follow Java naming conventions, and that your loop has a bug: it always sets the first element of the array instead of initializing every element.
Finally, give meaningful names to variables: players is much more readable than p.

Categories