I just came to the problem where I want to call a function of an Object inside a HashMap. I already searched it up and found one thread but sadly I don't understand it.
So here's my code
public class Seat {
//some attributes
public int getNumber() {
return number;
}
public boolean isReserved() {
return status;
}
}
public class Hall {
private HashMap mySeats;
public HashMap getMeinePlaetze() {
return meinePlaetze;
}
public void createSeats() {
for (int i = 1; i <= this.getnumberOfSeats(); i++) {
this.getMySeats().put(i, new Seat(i, 1));
}
}
}
public class Main {
Hall h1 = new Hall(...);
h1.createSeats();
h1.getMySeats().get(2).isReserved(); //How do I have to write this to work out?
}
I hope my intend is reasonable. Feel free to correct me if my code sucks. I already apologize for it.
Thank you very much.
Since version 5, Java has a feature called Generics. You'll find a lot about generics on the web, from articles, blog posts, etc to very good answers here on StackOverflow.
Generics allows Java to be a strongly typed language. This means that variables in Java can not only be declared to be of some type (i.e. HashMap), but also to be of some type along with one or more generic type parameters (i.e. HashMap<K, V>, where K represents the type parameter of the keys of the map and V represents the type parameter of the values of the map).
In your example, you are using a raw HashMap (raw types are types that allow for generic type parameters to be specified, however the developer has not specified them). Raw types are considered bad practice and are highly error-prone, as you are experiencing right now.
HashMap allows two generic type parameters (one for the keys and another one for the values). In your case, you are using Integer for the keys and Seat for the values. Put into simple words, you are mapping integers to seats, or you can also say that your map is a map of integers to seats.
So, inside you Hall class, you should define your map with its generic type parameters:
private Map<Integer, Seat> mySeats = new HashMap<>();
Then, this code:
h1.getMySeats().get(2)
will return an instance of type Seat, because your map already knows that all its values are of type Seat.
So your code:
h1.getMySeats().get(2).isReserved();
will compile fine and will work without any errors.
Please note that, apart from declaring the generic types of your map, I've also changed two additional things.
First, I've created an actual instance of HashMap by using its constructor:
mySeats = new HashMap<>()
If you don't create an instance of your type with new, there won't be any HashMap instance where to put your seats later, and you'll get a NullpointerException (try it!).
Secondly, I've changed the type of the variable from HashMap to Map. HashMap is a class, while Map is just an interface. The thing is that the HashMap class implements the Map interface, so, unless your code explicitly needs to access a method of HashMap that is not declared in the Map interface (which is almost never the case), you will be fine with the mySeats variable being of type Map<Integer, Seat> instead of HashMap<Integer, Seat>. This is called programming to the interface and is a best practice that you should embrace from the very beginning. It will save you a lot of headaches in the future.
Following my tip in the comments, I wouldn't use a Map to link a meaningful row or number to a map-key or an array-index.
So, actually I would do it this way (because you asked, what I mean with my tip):
Seat:
public class Seat {
private final int row;
private final int number;
private boolean reserved = false;
public Seat(int row, int number) {
this.row = row;
this.number = number;
}
public boolean reserve() {
if (!reserved) {
reserved = true;
return reserved;
}
return !reserved;
}
public int getRow() {
return row;
}
public int getNumber() {
return number;
}
public boolean isReserved() {
return reserved;
}
public boolean is(int row, int number) {
return this.row == row && this.number == number;
}
#Override
public int hashCode() {
int hash = 7;
hash = 23 * hash + this.row;
hash = 23 * hash + this.number;
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Seat other = (Seat) obj;
if (this.row != other.row) {
return false;
}
return number == other.number;
}
}
Hall:
public class Hall {
public final Set<Seat> seats = new HashSet<>();
public Set<Seat> getSeats() {
return Collections.unmodifiableSet(seats);
}
public void createSeats(int lastRow, int seatsPerRow) { // This is an example; in case you have different count of seats per row, you better make an boolean addSeat(int row, int number) function; boolean to check if it has been added or if the seat already exists
for (int row = 1; row <= lastRow; row++) {
for (int number = 1; number <= seatsPerRow; number++) {
seats.add(new Seat(row, number));
}
}
}
public Seat get(int row, int number) {
for (Seat seat : seats) { // or you use seats.iterator; I personally hate Iterators; it is my subjective point of view.
if (seat.is(row, number)) {
return seat;
}
}
return null;
}
public boolean reserve(int row, int number) {
Seat seat = get(row, number);
if (seat != null) {
return seat.reserve();
}
return false;
}
}
And my Test-drive:
public class TestDrive {
public static void main(String[] args) {
Hall hall = new Hall();
int lastRow = 15;
int seatsPerRow = 10;
hall.createSeats(lastRow, seatsPerRow);
boolean reserved = hall.reserve(5, 9);
System.out.println("Seat(Row=5, Number=9) is reserved: " + (reserved == hall.get(5, 9).isReserved()));
boolean reservedAgain = hall.reserve(5, 9);
System.out.println("Seat(Row=5, Number=9) cannot be reserved again: " + (reservedAgain != hall.get(5, 9).isReserved()));
}
}
h1.getMySeats().get(2).isReserved();
Please use an IDE like IntelliJ IDEA. It will tell you about mistakes like forgetting parentheses while typing.
Related
I have a class making operations on a chess board. Every cell has its states. The board is an array whose declaration is:
private CellState[][] cellBoard = new CellState[8][8];
I have many methods that have 3 arguments: row (horizontal), file (vertical) and state. They traverse board cell by cell. To refactor repeating code, I wrote the following method:
private void traverseBoard(Command method) {
for(int row = 0; row < 8; row++) {
for(int file = 0; file < 8; file++) {
method.execute(row, file, cellBoard[row][file]);
}
}
}
protected interface Command {
public void execute(int x, int y, CELL_STATE state);
}
In one of the methods, I check if every cell is empty:
private boolean areAllEmpty() {
ExtendedBoolean empty = new ExtendedBoolean(true);
traverseBoard((i, j, state) -> {
if (state != CELL_STATE.EMPTY) {
empty.set(false);
}
});
return empty.is();
}
I could not use the primitive boolean, because it is immutable. For that purpose, I created a nested class:
private class ExtendedBoolean {
boolean bool;
public ExtendedBoolean(boolean bool) {
this.bool = bool;
}
public void set(boolean bool) {
this.bool = bool;
}
public boolean is() {
return bool;
}
}
I hope there is a better way of passing a method with multiple arguments inside a lambda expression. I am aware it is possible to use Runnable like in this answer. However, in that case I cannot pass any parameter.
I hope that I don't have to write ExtendedBoolean, whose only purpose is to wrap a primitive. I had to write ExtendedInteger as well.
Are my hopes reasonable?
EDIT: The collection of cell states has to be mutable. I change states of cells and then check them. I do it in a loop until condition is fulfilled.
You could use a Stream to represent your board, and thus benefit of all the Stream methods:
Stream<Cell> stream =
IntStream.range(0, 64)
.mapToObj(i -> {
int row = i / 8;
int column = i % 8;
return new Cell(row, column, cellBoard[row][column]);
});
where the Cell class would be defined as
private static class Cell {
private final int row;
private final int column;
private final CELL_STATE state;
public Cell(int row, int column, CELL_STATE state) {
this.row = row;
this.column = column;
this.state = state;
}
public int getRow() {
return row;
}
public int getColumn() {
return column;
}
public CELL_STATE getState() {
return state;
}
#Override
public String toString() {
return "Cell{" +
"row=" + row +
", column=" + column +
", state=" + state +
'}';
}
}
Now, to implement your usecase, all you would have to do would be
stream.allMatch(cell -> cell.getState() == CELL_STATE.EMPTY);
You can try to combine generics and lambdas together with something like this:
protected interface Command<T> {
public T execute(T prev, int x, int y, CELL_STATE state);
}
private <T> T traverseBoard(T initial, Command<T> method) {
T result = initial;
for(int row = 0; row < 8; row++) {
for(int file = 0; file < 8; file++) {
result = method.execute( result, row, file, null );
}
}
return result;
}
private boolean areAllEmpty() {
return traverseBoard( Boolean.FALSE, (b, i, j, state) -> {
if ( state != CELL_STATE.EMPTY ) {
return false;
}else{
return true;
}
} );
}
private int count() {
return traverseBoard( 0, (c, i, j, state) -> c += 1 );
}
I also throw in an example of how you can do count in order to see how state is maintained.
But I like #JB Nizet answer using streams.
One easy way is to write your own simple generic Mutable:
public class Mutable<T> {
T it;
public Mutable(T it) {
this.it = it;
}
public void set(T it) {
this.it = it;
}
public T get() {
return it;
}
}
You can then use a Mutable<Boolean> in your case and rely on autoboxing to make it handle boolean.
In lambdas all variables that are captured from the outside scope (clojure) need to be final, or effectively final, and thats why it does not let you directly change a variable, if Javas Implementation for clojures were like those of C# or JavaScript you would not need to use this.
A pattern used in Java is to declare an array with only 1 element in this case array with one boolean and then change the content of the array (i think it is ugly).
boolean[] empty = new boolean[]{false};
traverseBoard((i,j,state) -> empty[0] = true ) // Simple usage
I think this solution (my opinion) is ugly, another one is to create an Holder class, that is Generic, so whenever you need something similar you could used it.
As an example:
Holder<Student> studentHolder = new Holder<>(student);
doSomething( anotherStudent -> studentHolder.value = anotherStudent );
With this last approach be sure to create default ones for primitive types, so there is no Boxing/Unboxing overhead.
BooleanHolder boolHolder = new BooleanHolder(false);
Your traverseBoard method is correct if all you want to do is take some action for each cell. However, if you need to check some condition on each cell, you need another approach.
As I see it, the problem is that you need to design a method that traverses your board and returns a boolean instead of void. Here's something to start with:
private boolean allCellsInBoardMatch(Condition condition) {
for (int row = 0; row < 8; row++) {
for (int file = 0; file < 8; file++) {
if (!condition.check(row, file, cellBoard[row][file])) {
return false;
}
}
}
return true;
}
protected interface Condition {
boolean check(int x, int y, CELL_STATE state);
}
This approach, besides working as expected without needing a wrapper type, is more efficient, because it stops iterating as soon as the condition is not met for a cell, while the approach you were using was traversing the whole board.
Your example that checks if all the cells are empty could now be rewritten as follows:
private boolean areAllEmpty() {
return allCellsInBoardMatch((i, j, state) -> state == CELL_STATE.EMPTY);
}
I'm still a little confused with regards to the difference between static and dynamic. From what I know dynamic uses object while static use type and that dynamic is resolved during runtime while static is during compile time. so shouldn't this.lastName.compareTo(s1.lastName) use dynamic binding instead?
key.compareTo(list[position-1]) use dynamic binding
public static void insertionSort (Comparable[] list)
{
for (int index = 1; index < list.length; index++)
{
Comparable key = list[index];
int position = index;
while (position > 0 && key.compareTo(list[position-1]) < 0) // using dynamic binding
{
list[position] = list[position-1];
position--;
}
list[position] = key;
}
}
Why does (this.lastName.compareTo(s1.lastName)) use static binding?
private String firstName;
private String lastName;
private int totalSales;
#Override
public int compareTo(Object o) {
SalePerson s1 = (SalePerson)o;
if (this.totalSales > s1.getTotalSales())
{
return 1;
}
else if (this.totalSales < s1.getTotalSales())
{
return -1;
}
else //if they are equal
{
return (this.lastName.compareTo(s1.lastName)); //why is this static binding??
}
}
Your question isn't complete and doesn't include all relevant the code. However this is the basic difference between the different bindings
Java has both static and dynamic binding. Binding refers to when variable is bound to a particular data type.
Static/Early binding is done at compile time for: private, final and static methods and variables. And also for overloaded methods
Dynamic/late binding is done at runtime for: methods which can be overriden methods. This is what enables polymorphic behaviour at runtime.
To further demonstrate this point have a look at this code and see if you can determine when it would be early and late binding:
/* What is the output of the following program? */
public class EarlyLateBinding {
public boolean equals(EarlyLateBinding other) {
System.out.println("Inside of overloaded Test.equals");
return false;
}
public static void main(String[] args) {
Object t1 = new EarlyLateBinding(); //1
Object t2 = new EarlyLateBinding(); //2
EarlyLateBinding t3 = new EarlyLateBinding(); //3
Object o1 = new Object();
Thread.currentThread().getStackTrace();
int count = 0;
System.out.println(count++);
t1.equals(t2);//n
System.out.println(count++);
t1.equals(t3);//n
System.out.println(count++);
t3.equals(o1);
System.out.println(count++);
t3.equals(t3);
System.out.println(count++);
t3.equals(t2);
}
}
Answer:
++ is after the count and hence the result returned is the 0 before incrementing it. Hence starts with 0 and proceeds as you expect.
The only scenario where the equals methods of EarlyLateBinding object
is actually invoked is is statement 3.
This is because the equals method is overloaded (Note: the different
method signature as compared to the object class equals)
Hence the type EarlyLateBinding is bound to the variable t3 at
compile time.
.
in this code
public static void insertionSort (Comparable[] list)
{
for (int index = 1; index < list.length; index++)
{
Comparable key = list[index];
int position = index;
while (position > 0 && key.compareTo(list[position-1]) < 0)
{
list[position] = list[position-1];
position--;
}
list[position] = key;
}
}
key can be anything that implements the Comparable interface so in the compile time compiler doesn't know the exact type so type is resolved in the runtime by using the object that key referring to.
But in this code,
#Override
public int compareTo(Object o) {
SalePerson s1 = (SalePerson)o;
if (this.totalSales > s1.getTotalSales())
{
return 1;
}
else if (this.totalSales < s1.getTotalSales())
{
return -1;
}
else //if they are equal
{
return (this.lastName.compareTo(s1.lastName));
}
}
compiler knows the type of the s1 so it use the static binding
I have made an inheritance hierarchy with one super-class called Employe and two subclasses called Lecturer and Assistant. In addition to this I made a class called Subject which has an array of employees.
What I want to do here is create a method for adding Employe objects into the array.
I made the same one that works for ArrayList, but it didn't seem to work for Arrays.
If it is possible, how can I create a method for doing the same thing with arrays?
public class Subject {
private String subjectcode;
private Employe[] employees;
public Subject(String subjectcode) {
this.subjectcode = subjectcode;
Employe[] employees = new Employe[5];
}
public void setSubjectcode(String code) {
this.subjectcode = code;
}
public String getSubjectcode() {
return this.subjectcode;
}
public boolean addStaff(Employe employe) {
if (employe instanceof Lecturer || employe instanceof Assistant) {
this.employees.add(employe);
return true;
} else {
return false;
}
}
}
You need to use an ArrayList :
public class Subject
{
private String subjectcode;
private final List<Employee> employees = new ArrayList<Employee>();
public Subject(String subjectcode){
this.subjectcode = subjectcode;
}
public boolean addStaff(Employe employe){
return this.employees.add(employe);
}
Or if you still want to use an array :
public boolean addStaff(Employe employe){
List<Employee> tempList = Arrays.asList(this.employees);
boolean added = tempList.add(employe);
this.employees = tempList.toArray(this.employees);
return added;
}
Arrays cannot grow or shrink dynamically by themselves as ArrayLists do, that's why the don't have add() method — it'd stop working after array instance is full.
What you have with arrays are, essentially, a get(index) and set(index, value), so when you know that you will have at maximum N employees, Subject may look like this:
public class Subject {
private static final int N = 5;
private String subjectcode;
private Employe[] employees = new Employe[N];
private int size = 0;
public Subject(String subjectcode){
this.subjectcode = subjectcode;
}
public void setSubjectcode(String code){
this.subjectcode = code;
}
public String getSubjectcode(){
return this.subjectcode;
}
public boolean addStaff(Employe employe){
if (size == employees.length) {
// cannot add when is full
return false;
}
if(employe instanceof Lecturer || employe instanceof Assistant){
this.employees[size++] = employe;
return true;
}
return false;
}
}
On the other hand, if you don't know how many employees Subject may have even at a time when Subject is created (if you'd know it, you may pass N as a constructor argument), you'd have to implement method for growing internal array and call it whenever new employe is added, which may look like this:
private void ensureCapacity(int n) {
int oldCapacity = employees.length;
if (oldCapacity >= n) {
// there's nothing to do
return;
}
// grow at least in half, to minimize copying data on each add
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - n < 0)
newCapacity = n;
employees = Arrays.copyOf(employees, newCapacity);
}
public boolean addStaff(Employe employe) {
ensureCapacity(size + 1);
if (employe instanceof Lecturer || employe instanceof Assistant) {
this.employees[size++] = employe;
return true;
}
return false;
}
For better example of growing arrays see default implementation of ArrayList's ensureCapacity(int minCapacity) in JDK.
But again, this growing-shrinking stuff is just reimplementing what is done already in ArrayList for you.
In case of Java arrays, unlike ArrayList you do not have add method. So, you cannot add like it. Array operates as below:
String[] employees = new String[5];
employees[0] = "ad";
So, array needs index based approach, where you specify that at index 0 put this element, at index 1 put this element, and so on .... employees[0] = "as";
In your case, why you need to use array? I think ArrayList fits best, as per information you have provided.
so I'm currently doing an exercise for college that has several optional parts (because we havn't done this in class yet), one of them being to use lists instead of arrays (so it'd be variable size) and another one printing the list sorted by points (I'll get to that now)
So, I have the Player.java class which looks like this.
public class Player {
String name;
String password;
int chips;
int points;
public Player(String n, String pw, int c, int p) {
name = n;
password = pw;
chips = c;
points = p;
}
public String getName() {
return name;
}
public void setName(String n) {
name = n;
}
public void setPW(String pw) {
password = pw;
}
public String getPW() {
return password;
}
public void setChips(int c) {
chips = c;
}
public int getChips() {
return chips;
}
public void setPoints(int p) {
points = p;
}
public int getPoints() {
return points;
}
}
Pretty simple, then I'm creating a List with this (in another class):
List<Player> lplayer = new ArrayList<Player>();
Adding players with this:
lplayer.add(new Player(n,pw,c,p))`
And finally reading their stats with this:
public int search_Player (String n) {
String name;
int i = 0;
boolean found = false;
while ((i <= tp) && (!found)) {
name = lplayer.get(i).getName();
if (name.equals(n)) {
found = true;
}
i++;
}
return (found == true) ? i-1 : -1;
}
public Player show_Player (int i) {
return lplayer.get(i);
}
public void list_Players() {
Collections.sort(lplayer);
int i2;
if (tp > 0) { // variable which contains number of total players
for (int i = 0;i<tp;i++) {
i2 = i+1;
System.out.println ("\n"+i2+". "+lplayer.get(i).getName()+" [CHIPS: "+lplayer.get(i).getChips()+" - POINTS: "+lplayer.get(i).getPoints()+"]");
}
}
else {
System.out.println ("There are no players yet.");
}
}
So that's basically all the code. As you can see the I already have a list_Players function but that just prints it in the order it was added. I need a way to print in sorted by the points each player has (so basically a ranking).
As you can see I'm pretty new to java so please try not to come up with a very complicated way of doing it.
I've already searched for it and found things like Collections.sort(list) but I guess that's not what I need right here.
Thank you!
You can use the public static <T> void sort(List<T> list, Comparator<? super T> c) overload in Collections - provide the comparator you need (can be just an anonymous class) - and you are all set!
EDIT:
This describes how the method works. In brief, you'll implement your call as
Collections.sort(list, new Comparator<Player>() {
int compare(Player left, Player right) {
return left.getPoints() - right.getPoints(); // The order depends on the direction of sorting.
}
});
That's it!
Collections.sort(list) could definitely by a solution for your problem. It's a way to sort your collections provided by Java. If you are writing a "real world" application (not an exercise for collage) this would be the way you doing it.
To let Collections.sort(list) works, you have to implement an interface call Comparaple. By implementing this interface, the sort will know how to order your elements.
But because it's a exercise for collage, this is perhaps a little bit to easy. If you want (or must) implement you own sorting algorithm, try first to sort a common list of numbers (1, 5, 2, 7...). You can extend such an sorting algorithm easily for your own classes.
A new approach using lambdas, that is a lot shorter to write is
myList.sort((obj1, obj2)->(condition)?1:-1);
where you can use the objects for your condition, and anything greater than 0 returned means swap (in this case if condition returns true)
What I do not understand is why I am getting an error compiling my code when a String is in fact an object, and the compiler is saying otherwise. I dont know why I keep getting this error message
symbol: method compareTo(Object)
location: variable least of type Object
.\DataSet.java:17: error: cannot find symbol
else if(maximum.compareTo(x) < 0)
here is the code. I'm trying to utilize the class comparable to allow two objects to use the compareTo method. In the tester, I'm just trying to use a basic string object to compare.
public class DataSetTester
{
public static void main(String[] args)
{
DataSet ds = new DataSet();
String man = "dog";
String woman = "cat";
ds.add(man);
ds.add(woman);
System.out.println("Maximum Word: " + ds.getMaximum());
}
}
Class:
public class DataSet implements Comparable
{
private Object maximum;
private Object least;
private int count;
private int answer;
public void add(Object x)
{
if(count == 0){
least = x;
maximum = x;
}
else if(least.compareTo(x) > 0)
least = x;
else if(maximum.compareTo(x) < 0)
maximum = x;
count++;
}
public int compareTo(Object anObject)
{
return this.compareTo(anObject);
}
public Object getMaximum()
{
return maximum;
}
public Object getLeast()
{
return least;
}
}
Comparable Interface:
public interface Comparable
{
public int compareTo(Object anObject);
}
Of course String is an Object.
Comparable is generic now. Why do you feel the need to make those references Object if they are type String? Your code is poor; it's not a Java problem.
I don't see why DataSet needs to implement Comparable. You just need to compare incoming Strings as they're added. Do it this way and you'll fare better:
public class DataSet {
private String maximum;
private String least;
private int count;
private int answer;
public void add(String x) {
if(count == 0){
least = x;
maximum = x;
} else if (least.compareTo(x) > 0) {
least = x;
} else if(maximum.compareTo(x) < 0) {
maximum = x;
}
count++;
}
public String getMaximum() { return this.maximum; }
public String getLeast() { return this.least; }
public int getCount() { return this.count; }
}
The problem is that DataSet implements Comparable, but Object doesn't.
Instead of storing Objects, you want to store Comparables. However, if you do get this to compile, you will get into an infinite loop right here:
public int compareTo(Object anObject)
{
// Yeah, never stop loopin'!
return this.compareTo(anObject);
}
It's recommended that in newer code, you use the generic Comparable<T> interface. Your code would then look like this:
public class DataSet implements Comparable<DataSet>
{
private String maximum;
private String least;
private int count;
private int answer;
public void add(String x)
{
if(count == 0){
least = x;
maximum = x;
}
else if(least.compareTo(x) > 0)
least = x;
else if(maximum.compareTo(x) < 0)
maximum = x;
count++;
}
public int compareTo(DataSet anObject)
{
// I don't really know how you want this to work.
// Come up with your own criteria on what makes a DataSet greater or less than
// another one.
count - anObject.count
}
// Good practice to include this if you're doing a compareTo.
#Override
public boolean equals(Object other)
{
return (other instanceof DataSet) && compareTo((DataSet)other) == 0;
}
public String getMaximum()
{
return maximum;
}
public String getLeast()
{
return least;
}
}
Edit - just saw that you're comparing strings. In that case, you don't really need DataSet to implement Comparable. However, if you do need it for something else, what I wrote still stands.
least and maximum are simply Objects, and the Object class doesn't have a compareTo(...) method, simple as that. least and maximum need to be declared Comparable, not Object. And as written, it makes no sense declaring DataSet to implement the Comparable interface since there are no DataSet objects present and certainly none being compared.
java.lang.Object does not have a compareTo() method.
First of all there is an infinite loop in you code:
public int compareTo(Object anObject)
{
return this.compareTo(anObject);
}
this method is continuously calling itself.
Regarding your compile error: you have declared variable as Object, which obviously does not have a compareTo method.
There is no compareTo() method in Object. I guess you're looking for String.compareTo().
Type checking is done at compile time and not runtime. At compile time, least and maximum are considered to be objects of type Object and not String.