This is a question from an exam past paper. I have completed the question and it works. However, i feel my implementation may be weak e.g. my use of static throughout the Gregorian class.
I was given three methods to write in any way i saw fit (in the Gregorian class) given a scenario for each. Was I right in using static on the three methods in the Gregorian class.
Also the day, month and year fields are meant to be immutable, is setting them as private enough? (once they are created the field values cannot be changed)
public class Date {
private int day;// needs to be immutable?
private String month;// needs to be immutable?
private int year;// needs to be immutable?
public Date(int theDay, String theMonth, int theYear) {
this.day = theDay;
this.month = theMonth;
this.year = theYear;
}
public int getDay() {
return day;
}
public String getMonth() {
return month;
}
public int getYear() {
return year;
}
}
public class Gregorian {
public static Date d;
public static boolean leapYear(){
if(d.getYear() %400==0 || (d.getYear()%4==0 && d.getYear()%100!=0)){
return true;
}else{
return false;
}
}
public static int getGregorianDateNumber(){
int a = (d.getYear()*384)*(32+d.getDay());
return a;
}
public static int getISO8601Date(){
int b = (d.getYear()*367)+d.getDay();
return b;
}
public static void main (String[] args){
d = new Date(9, "June", 8);
System.out.println(getGregorianDateNumber());
System.out.println(getISO8601Date());
System.out.println(leapYear());
}
}
Instead of the static methods and the static field d make them all non-static.
public class Gregorian {
private final Date d;
public Gregorian(Date d_) {
this.d = d_;
}
public boolean isLeapyear() {
... // implemented as above
}
... // Other methods as above, but all non-static.
}
And main as follows:
public static void main (String[] args){
Date d = new Date(9, "June", 8);
Gregorian g = new Gregorian(d);
System.out.println(g.getGregorianDateNumber());
System.out.println(g.getISO8601Date());
System.out.println(g.leapYear());
}
Strings are by default immutable.
private int day;// needs to be immutable?
private int year;// needs to
are not immutable fields as you defined. Their state can change. Make them final.
NOTE: Making a reference final doesn't mean object state can't be changed (In your case this note is irrelevant, because you are not referencing objects).
I'll agree with thinksteep - adding "final" to your fields will help keep them from being changed. Not having setters reinforces this.
In addition, I want to point out that
private String month;// needs to be immutable?
can be created as anything, from "January" to "Pie". If I may suggest, change it to an enum and establish the allowed values for months.
public enum MonthName {
JAN,FEB,MAR,APR,MAY,JUN,JUL,AUG,SEP,OCT,NOV,DEC;
}
Change your Date class to the following:
private final int day;
private final MonthName month;
private final int year;
public Date(int theDay, MonthName theMonth, int theYear) {
this.day = theDay;
this.month = theMonth;
this.year = theYear;
}
both day and year are primitives and There is already immutable version of int available which is Integer you can make use of that.
Second thing is, rather having a static reference to Date in Gregorian, pass the Date as an argument to each of the static methods. You can assure the thread safety then.
Related
So I have this assignment which I need to put data into a tree set. I have three classes they are :
Brother.java. The assignment said the constructor is not public, so I'm using the getInstance() to initialize Brother object
public class Brother {
String name;
int day;
int month;
private static Brother instance = null;
private Brother()
{
name = "0";
day = 0;
month = 0;
}
public static Brother getInstance()
{
if(instance == null)
{
instance = new Brother();
}
return instance;
}
}
Family class. This class is used to assign the brother object into the tree set with Brother as the objects.
import java.util.Set;
import java.util.TreeSet;
public class Family {
Set<Brother> Brothers;
public Family()
{
this.Brothers = new TreeSet<Brother>();
}
public Brother makeBrother()
{
Brother B = Brother.getInstance();
return B;
}
public boolean addBrother(String name, int day, int month)
{
Brother B = Brother.getInstance();
return Brothers.add(B);
}
}
And finally the main class
public class Main {
public static void main(String[] args) {
Family myFamily = new Family();
myFamily.makeBrother();
// myFamily.addBrother("Shane", 3, 2);
}
}
whenever I try to use myFamily.addBrother() I always got this error "Exception in thread "main" java.lang.ClassCastException: class Brother cannot be cast to class java.lang.Comparable (Brother is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')". What do I have to do with that? The program is perfectly fine when I use myFamily.makeBrother(). This algorithm is not all done yet but when I try to run it this happened to me and I cannot continue to the next step. Thank you before.
You are using a Set instead of a List because you want to avoid duplicates. To know which Brothers are duplicate, a TreeSet needs either a comparator, or the objects themselves need to implement Comparable.
Read the javadoc of TreeSet for more: https://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html
BTW that getInstance always returns the same instance. You'll probably need to change that to createInstance or something that actually creates new ones.
I agree with #GreyFairer, you have to provide a comparator in order to use Set, see this example:
Class Cast Exception problems with TreeSet
I hope it can helps you!
I see a few problems there.
You have defined Brother as a singleton. That means only one Brother instance will exist in your program. So all references to Brother will point to the same instace. I would avoid singleton for this class since doesn't makes sense.
If you what to use a TreeSet (without providing a Comparator for the Tree) then Brother must implement Comparable
Family.makeBrother just return the singleton Brother, but does not add it to the family tree, that's why you don't get the error.
This is a working rework of your code
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class FamilyTreeSet {
public static void main(String[] args) {
Family myFamily = new Family();
myFamily.addBrother("Shane", 3, 2);
myFamily.addBrother("Bob", 2, 4);
System.out.println(myFamily);
}
public static class Brother implements Comparable<Brother>{
private String name;
private int day;
private int month;
public Brother(String name, int day, int month) {
this.name = name;
this.day = day;
this.month = month;
}
public String getName() {
return name;
}
public int getDay() {
return day;
}
public int getMonth() {
return month;
}
#Override
public int compareTo(Brother o) {
return Comparator.comparing(Brother::getName, String.CASE_INSENSITIVE_ORDER).compare(this, o);
}
#Override
public String toString() {
return "Brother{" +
"name='" + name + '\'' +
", day=" + day +
", month=" + month +
'}';
}
}
public static class Family {
Set<Brother> Brothers;
public Family()
{
this.Brothers = new TreeSet<Brother>();
}
public boolean addBrother(String name, int day, int month)
{
Brother B = new Brother(name, day, month);
return Brothers.add(B);
}
#Override
public String toString() {
return "Family{" +
"Brothers=" + Brothers +
'}';
}
}
}
I'm using the each brother's name to compare brothers. Check that I first add Shane but in the output Bob goes first. If you want to compare brothers by birthday just change the compareTo.
Family{Brothers=[Brother{name='Bod', day=2, month=4}, Brother{name='Shane', day=3, month=2}]}
In the first part of my code I am reading data from a file and putting the fields into variables like this
Date date = rs.getDate(1);
Integer flightnumber = rs.getInt("FlightNumber");
Integer passengers = rs.getInt("Passengers");
so I need to put these variables into an ArrayList for example and then write a method that compares two variables with the ones in the list I created and returns an int being the passengers.
public int getPassengerNumbersFor(int flightNumber, LocalDate date)
The tricky part is that I cannot create any new classes and there isn't any getFlightNumber/ getDate implemented nor am I allowed to code one. I have been told that a HashMap can be used but in this case I would have one key and two values which wouldn't work (passengers is key, flightnumber and date are values maybe).
How can I store these 3 values and then write my method?
If you were "allowed" to create classes, I would suggest an immutable class:
public class Flight {
private final LocalDate localDate;
private final int number;
private final List<Passenger> passengers;
public Flight(LocalDate localDate, int number, List<Passenger> passengers) {
this.localDate = localDate;
this.number = number;
this.passengers = List.copyOf(passengers);
}
public LocalDate getLocalDate() {
return localDate;
}
public int getNumber() {
return number;
}
public List<Passenger> getPassengers() {
return passengers;
}
public int getPassengersNumber() {
return passengers.size();
}
...
}
Note the usage of the new Date-Time API.
And then you could have another class for all the flights:
public class Flights {
private final List<Flight> flights;
public Flights(List<Flight> flights) {
this.flights = new ArrayList<>(flights);
}
public Flight getFlight(LocalDate localDate, int number) {
return flights.stream()
.filter(flight -> flight.getLocalDate().equals(localDate))
.filter(flight -> flight.getNumber() == number)
.findAny()
.orElseThrow(InvalidFlightException::new);
}
public void addFlight(Flight flight) {
flights.add(flight);
}
...
}
This question already has answers here:
What does the 'static' keyword do in a class?
(22 answers)
Closed 3 years ago.
Can someone explain how the below code works without any exceptions. I am thinking when new instance is created for SUNDAY it creates a new instance for MONDAY (inside SUNDAY) too and then SUNDAY again (inside MONDAY) and so on... Something like recursive as they both are part of the class Week. But my understanding is wrong because the below code is working fine.
public class Week {
public static final Week SUNDAY = new Week("SUNDAY",0);
public static final Week MONDAY = new Week("MONDAY",1);
private String name;
private int val;
private Week(String name, int val) {
this.name = name;
this.val = val;
}
public int getIndex() {
return this.val;
}
#Override
public String toString() {
return this.name;
}
}
I got this doubt when I was reading about java enums.
You will see the mentioned behavior when SUNDAY and MONDAY are instance variables (non-static).
Since you have declared them as static those are the properties of the class and initialized when the Week class is loaded one after another. One object creation SUNDAY would not contain MONDAY in it and vice versa.
As I mentioned in the beginning, the below code won't run successfully as it will try to create instances recursively without an end.
public class Week {
public final Week SUNDAY = new Week("SUNDAY",0);
public final Week MONDAY = new Week("MONDAY",1);
private String name;
private int val;
private Week(String name, int val) {
this.name = name;
this.val = val;
}
public int getIndex() {
return this.val;
}
#Override
public String toString() {
return this.name;
}
public static void main(String[] args) {
new Week("TUESDAY", 2);
}
}
SUNDAY and MONDAY are static variables. Which means that they are class variables. Object of class Week will not have properties called SUNDAY and MONDAY
You can get more information regarding static here: What does the 'static' keyword do in a class?
Here is the exact instruction on what my professor has asked me to do:
Write a constructor with two parameters for int year and String player.
Use internal method call to setDetails to initialize the fields.
I have the class so far like this:
public class Card
{
private int year;
private String player;
public Card(String player, int year)
{
}
}
Not sure what the internal method call is, I have looked on the internet and StackOverflow and have not found anything that has benefited me. Any help is appreciated.
Thank you,
A first year programming student.
You need a method to set the details of the card, like this:
private final void setDetails(int year, String player) {
this.year = year;
this.player = player;
}
And then in the constructor, you can call setDetails(year, player).
Based on your statement here is the code that you 're asking for:
public class Card {
private int year;
private String player;
public Card(String player, int year) {
setDetails(player,year);
}
/*i'm making it public in case you want to call the setter directly
somewhere and final since i call an overridable method in the constructor*/
public final void setDetails(String player,int year) {
this.player=player;
this.year=year;
}
}
I am reading Uncle Bob's Clean Code. In chapter 16, the book shows how to refactor an example. There is one part that I cannot catch the purpose of writing in such way.
What the purpose of using protected keyword here?
Why do some methods like _getMinimumYear() start with an underscore?
Why do use a pair of method with same name rather than an abstract method like public abstract int getMinimumYear();
public abstract class DayDateFactory {
private static DayDateFactory factory = new SpreadsheetDateFactory();
public static void setInstance(DayDateFactory factory) {
DayDateFactory.factory = factory;
}
protected abstract DayDate _makeDate(int ordinal);
protected abstract DayDate _makeDate(int day, Month month, int year);
protected abstract DayDate _makeDate(int day, int month, int year);
protected abstract DayDate _makeDate(java.util.Date date);
protected abstract int _getMinimumYear();
protected abstract int _getMaximumYear();
public static DayDate makeDate(int ordinal) {
return factory._makeDate(ordinal);
}
public static DayDate makeDate(int day, Month month, int year) {
return factory._makeDate(day, month, year);
}
public static DayDate makeDate(int day, int month, int year) {
return factory._makeDate(day, month, year);
}
public static DayDate makeDate(java.util.Date date) {
return factory._makeDate(date);
}
public static int getMinimumYear() {
return factory._getMinimumYear();
}
public static int getMaximumYear() {
return factory._getMaximumYear();
}
}
public class SpreadsheetDateFactory extends DayDateFactory {
public DayDate _makeDate(int ordinal) {
return new SpreadsheetDate(ordinal);
}
public DayDate _makeDate(int day, Month month, int year) {
return new SpreadsheetDate(day, month, year);
}
public DayDate _makeDate(int day, int month, int year) {
return new SpreadsheetDate(day, month, year);
}
public DayDate _makeDate(Date date) {
final GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(date);
return new SpreadsheetDate(
calendar.get(Calendar.DATE),
Month.fromInt(calendar.get(Calendar.MONTH) + 1),
calendar.get(Calendar.YEAR));
}
protected int _getMinimumYear() {
return SpreadsheetDate.MINIMUM_YEAR_SUPPORTED;
}
protected int _getMaximumYear() {
return SpreadsheetDate.MAXIMUM_YEAR_SUPPORTED;
}
}
Python uses a leading underscore to say that the method is internal, and not part of any contract with the outside world. It seems like Uncle Bob is doing something similar, except here of course there's no tool support. Over time he has shifted his focus from writing for an audience familiar with C++ to writing for those familiar with scripting languages; he's probably expecting his readers have enough familiarity with Python or Ruby to recognize this sort of thing. So he is using a convention, just not a Java one.
Here Uncle Bob is putting underscores on the instance methods of the factory that he introduces. It seems like he's not intending that those methods be exposed (they are visible only to subclasses and to classes in the same package), subclasses of his factory will have to implement them but code outside of the package will not see them. He also wants to use the same names for the factory methods as he uses for the public static methods, but he needs a convention to keep them straight. I think he's trying to minimize the potential for confusing the instance methods of the internal factory with the exposed static methods, without introducing a separate interface for the factory.