Overriding `equals()` method gives unexpected result in `HashMap` - java

It is question from OCJP 6 exam, so it is intentionally not fully correct (but legal).
Given code:
class ToDos {
String day;
public ToDos(String d) {
day = d;
}
public boolean equals(Object o) {
return ((ToDos) o).day == day;
}
public int hashCode() { return 9; }
}
public class MapEQ {
public static void main(String[] args) {
Map<ToDos, String> map = new HashMap<ToDos, String>();
ToDos t1 = new ToDos("Monday");
ToDos t2 = new ToDos("Mond" + "a" + "y");
ToDos t3 = new ToDos("Tuesday");
map.put(t1, "a");
map.put(t2, "b");
map.put(t3, "c");
System.out.println(map.size());
}
}
Why output is 2? I mean, equals method is not overriden corretcly, so t1.day == t2.day supposed to be false! Am I'm missed something?

It's because:
"Mond" + "a" + "y"
is evaluated at compile time to "Monday" thus resulting in just one instance in string pool. There is a much simpler test to examine this behavior:
System.out.println("Mond" + "a" + "y" == "Monday"); //true
String y = "y";
System.out.println("Mond" + "a" + y == "Monday"); //false
final String y2 = "y";
System.out.println("Mond" + "a" + y2 == "Monday"); //true
Examples above should give you some overview on how the compiler treats string concatenation.
And to be on the safe side, always use:
return ((ToDos) o).day.equals(day);

Just adding to previous answers ... another example illustrating the point:
String a = "Monday";
String b = new String("Monday");
String c = "Monday";
(a == b) // false
(a.equals(b)) // true
(a == c) // true
(a.equals(c)) // true
Both a and c point to the same object in the String pool.

Related

writing a string on a boolean value from a record with getter/setter

[edit]when i run the current program and input "Bristol" it outputs
"Bristol is operated by Great Western and has false"
i need it to say "Bristol is operated by Great Western and has no free step access"
I have to use Boolean for StepFreeAccess, when run it should output "Bristol is operated by Great Western and has no free step access" Need a way where the:
s1 = setAccess(s1, false);
s2 = setAccess(s2, true);
s3 = setAccess(s3, true);
gets changed into String i.e true = "step free access" and false = "no step free access".
import java.util.Scanner;
public class ex8 {
public static void main (String [] args){
records s1 = new records();
records s2 = new records();
records s3 = new records();
s1 = setName(s1, "Bristol");
s2 = setName(s2, "Reading");
s3 = setName(s3, "York");
s1 = setCompany(s1,"Great Western");
s2 = setCompany(s2,"Great Western");
s3 = setCompany(s3,"Great Eastern");
s1 = setAccess(s1, false);
s2 = setAccess(s2, true);
s3 = setAccess(s3, true);
Scanner new1 = new Scanner(System.in);
System.out.println("What station do you need to know about?");
String answer = new1.nextLine();
if (answer.equals("Bristol")) {
System.out.println(s1.station +" is operated by "+ s1.operatingCompany +" and has "+s1.stepFreeAccess);
}
else if(answer.equals("Reading")) {
System.out.println(s2.station +" is operated by "+ s2.operatingCompany +" and has "+s2.stepFreeAccess);
}
else if(answer.equals("York")) {
System.out.println(s3.station +" is operated by "+ s3.operatingCompany +" and has "+s3.stepFreeAccess);
}
else {
System.out.println("I do not know that Station.");
}
}
// Getter methods
public static String getName (records s){
return s.station;
}
public static String getComapny (records s){
return s.operatingCompany;
}
public static Boolean getAccess (records s) {
return s.stepFreeAccess;
}
// Setter methods
public static records setName (records s, String station){
s.station = station;
return s;
}
public static records setCompany (records s, String company){
s.operatingCompany = company;
return s;
}
public static records setAccess(records s, Boolean access) {
s.stepFreeAccess = access;
return s;
}
}
public class records {
String station;
String operatingCompany;
Boolean stepFreeAccess;
}
In General:
Getters/Setters should be in a class with corisponding fields. For example the getAcces() method should be part of the class records
public boolean getAcces(){
return this.stepFreeAccess
}
public void setAcces(acces){
this.stepFreeAcces = access;
}
In your case I would recomend to write a constructor for records. The constructor should need Station, OperatingCompany and StepFreeAccess. In the constructor you give the corisponding fields their value.
To then solve your problem you could now set the getter from acces to deliver the needed String.
For example:
public String getAccess(){
if(this.access){
return *return String for true here*
}else{
return *return String for false here*
}
}
For Bristol case, you can try:
if (answer.equals("Bristol")) {
String aux = "";
if (s1.stepFreeAccess) aux = "step free access";
else aux = "no step free access";
System.out.println(s1.station +" is operated by "+ s1.operatingCompany +" and has "+aux);
}

Comparing two time values [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 5 years ago.
I have participated in a challenge, in which the requirement is to compare two time values t1 and t2, and print First if t1 occurs before t2 ; otherwise, print Second.
And, t1 != t2.
Sample Input:
2
10:19PM 02:49AM
08:49AM 09:10AM
Sample Output:
Second
First
My code:
import java.util.*;
public class Solution {
static String timeCompare(String t1, String t2){
// Complete this function
String half1 = t1.substring(t1.length()-2); // gets AM/PM value
String half2 = t2.substring(t2.length()-2);
String time1 = t1.substring(0, t1.length()-2);
String time2 = t2.substring(0, t2.length()-2);
//System.out.println(time1);
int hour1 = Integer.parseInt(time1.split(":")[0]);
int hour2 = Integer.parseInt(time2.split(":")[0]);
int min1 = Integer.parseInt(time1.split(":")[1]);
int min2 = Integer.parseInt(time2.split(":")[1]);
if(hour1 == 12) {
hour1 = 0;
//System.out.println(hour1);;
}
if(hour2 == 12) {
hour2 = 0;
}
//System.out.println(hour1+" , "+hour2);
if(half1.equals(half2)){
// System.out.println(1);
if(hour1 == hour2){
if(min1 > min2){
return "Second";
}
else{
return "First";
}
}
else if(hour1 > hour2){
return "Second";
}
else{
//System.out.println(2);
return "First";
}
}
else if (half1 == "AM"){
return "First";
}
else{
return "Second";
}
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int q = in.nextInt();
for(int a0 = 0; a0 < q; a0++){
String t1 = in.next();
String t2 = in.next();
String result = timeCompare(t1, t2);
System.out.println(result);
}
}
}
I am not sure what am I doing wrong. But only 1 out of 10 test cases passed.
Can you tell what's wrong?
half1 == "AM" Here you have made a mistake. For String comparison , You need to use String#equals() method.
So change that line with half1.equals("AM"). This will do your work.
Refer to example here:
import java.time.LocalTime;
public class Main {
public static void main(String[] args) {
LocalTime t1 = LocalTime.of(10, 10, 0)
LocalTime t2 = LocalTime.of(11, 11, 0);
int result = t2.compareTo(t1);
if(result < 0){
System.out.println("Second");
}else if(result > 0 ){
System.out.println("First");
}else{
System.out.println("Same Time");
}
}
}
The code above generates the following result:
Second

How do I change the value of a boolean within a method - Java?

I read in a book that when you change the value of a method parameter that's a boolean or other basic datatype within the method it only is changed within the method and remains the same outside. I want to know if there is some way for me to actually change it within the method. For example:
public class Change {
void convert(boolean x, boolean y, boolean z) { //i want to set x,y, and z to false in this
x = false;
y = false;
z = false;
}
}
//Now in my main class:
public static void main(String[] args) {
boolean part1 = true;
boolean part2 = true;
boolean part3 = true;
System.out.println(part1 + " " + part2 + " " + part3);
Change myChange = new Change();
myChange.convert(part1,part2,part3);
System.out.println(part1 + " " + part2 + " " + part3);
}
EDIT1: These answers were good but not quite what i want to acheive. I want to put in part1, part2, and part3 when i call the method than i want them to be set to false within the method. The specific reason i asked this question was because im trying to code a battleship and i have a subroutine class with a method that when its called it checks if a ship has been sunk. If the there was a sink than the method will set a ton of boolean variables to false.
EDIT2: Just to clarify, I want something like this:
void convert(thing1,thing2,thing3,thing4) {
//some code here that sets thing1,thing2,thing3, and thing4 to false
}
// than in main:
boolean test1 = true;
boolean test2 = true;
boolean test3 = true;
boolean test4 = true;
convert(test1,test2,test3,test4);
System.out.println(test1 + " " + test2 + "....");
//and that should print out false, false, false, false
You can do it with this methodology
// these are called instance variables
private boolean x = false;
private boolean y = false;
private boolean z = false;
// this is a setter
public static void changeBool(boolean x, boolean y, boolean z) {
this.x = x;
this.y = y;
this.z = z;
}
Call the method like this
changeBool(true, true, false);
The values for x, y, and z are now changed.
This is a common problem in Java - pass-by-value vs. pass-by-reference. Java is always pass-by-value, where you're thinking of it as pass-by-reference.
Like #Rafael has said, you need to use instance variables to do what you want. I've gone a bit further and edited your source code to do what you want:
public class Change {
boolean part1;
boolean part2;
boolean part3;
Change(boolean x, boolean y, boolean z) {
part1 = x;
part2 = y;
part3 = z;
}
void convert(boolean x, boolean y, boolean z) { //this now sets the class variables to whatever you pass into the method
part1 = x;
part2 = y;
part3 = z;
}
// Now in my main class:
public static void main(String[] args) {
Change myChange = new Change(true, true, true);
System.out.println(myChange.part1 + " " + myChange.part2 + " "
+ myChange.part3);
myChange.convert(false, false, false);
System.out.println(myChange.part1 + " " + myChange.part2 + " "
+ myChange.part3);
}
}

Java - using logical OR in do while

I'm fairly new at this programming, so please do bear with me.
In teaching myself I'm attempting to write a Batteleships game; not OO at the moment, but rather procedural - little steps at a time.
I have a method to read the coordinates to fire at, these coordinates I want to then validate to make sure that, well, they're valid.
There is one method that checks that they are numbers and within the correct range, the other method is 'supposed' to check through what has already been entered.
The issue I'm finding is that I'm not breaking out of the do while loop to progress, the while bit is using logical OR on the two aforementioned methods. In writing these methods, they both do what they're supposed to do, well I'm not entirely sure about the method that checks whether a coordinate has already been fired at.
Some pointers would be really appreciated (on any aspect of it), thanks!
Code:
public static String inputCoords(List<String> coordsFired){
Scanner sc = new Scanner(System.in);
//Console c = System.console();
String coordsEntered;
do {
System.out.println("in do\\while");
System.out.println("Enter coordinates as 'x, y': ");
coordsEntered = sc.nextLine();
System.out.println("end of do\\while loop");
} while(!validateCoords(coordsEntered)
|| !coordsFiredAt(coordsEntered, coordsFired));
coordsFired.add(coordsEntered);
System.out.println("contents of List<String> coordsFired" + coordsFired);
return coordsEntered;
}
public static boolean validateCoords(String coordsEntered){
boolean results;
int x, y;
String strx = splitCoordsString(coordsEntered, 'x');
String stry = splitCoordsString(coordsEntered, 'y');
if (numericCheckCoordsFire(strx) && numericCheckCoordsFire(stry)) {
x = Integer.parseInt(strx);
y = Integer.parseInt(stry);
if (x > 25 || y > 25) {
results = false;
System.out.println("The dimensions of the board are 25 x 25, 'x,y' entered must be less than this. You entered '" + strx + "' for x and '" + stry + "' for y.");
} else {
results = true;
}
} else {
results = false;
System.out.println("Coords are supposed to be numbers... You entered '" + strx + "' for x and '" + stry + "' for y.");
}
System.out.println(results);
return results;
}
public static boolean coordsFiredAt(String coordsEntered, List<String> coordsFired) {
boolean results = false;
// go through each item in the list and compare against coordsEntered
for (String s : coordsFired) {
System.out.println("in for loop, printing iterated var" + s);
if (s.equals(coordsEntered)) {
// put these matched coordsFire into listHit
results = false;
} else {
System.out.println("already fired at " + coordsEntered);
results = true;
}
}
return results;
}
I propose you add OOP a little and create a class for Coords:
public class Coords {
private final int x;
private final int y;
public Coords(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
/**
* This method is used for Coords comparison
*/
#Override
public boolean equals(Object o) {
Coords coords = (Coords) o;
return y == coords.y && coords.x ==x;
}
/**
* This method is used to output coords.
*/
#Override
public String toString() {
return "(" + x + "," + y + ")";
}
}
So you code will look somethink like this:
public static Coords inputCoords(List<Coords> coordsFired) {
Scanner sc = new Scanner(System.in);
//Console c = System.console();
Coords coords;
do {
System.out.println("in do\\while");
System.out.println("Enter coordinates as 'x, y': ");
String coordsEntered = sc.nextLine();
coords = parseCoords(coordsEntered);
System.out.println("end of do\\while loop");
} while (coords == null || !areCoordsValid(coords) || !areCoordsNotFired(coords, coordsFired));
coordsFired.add(coords);
System.out.println("contents of List<String> coordsFired" + coordsFired);
return coords;
}
public static boolean areCoordsValid(Coords coords) {
boolean result = true;
if (coords.getX() > 25 || coords.getY() > 25) { // I think you also need to validate that it is possible values
result = false;
System.out.println("The dimensions of the board are 25 x 25, 'x,y' entered must be less than this. " +
"You entered '" + coords.getX() + "' for x and '" + coords.getY() + "' for y.");
}
return result;
}
public static boolean areCoordsNotFired(Coords coords, List<Coords> firedCoards) {
boolean result = true;
if (firedCoards.contains(coords)) {
result = false;
System.out.println("You already fired at " + coords.getX() + "," + coords.getY());
}
return result;
}
public static Coords parseCoords(String coordsEntered) {
Coords coords = null;
try {
String[] splittedCoords = coordsEntered.split(","); // Method splits values by comma. It should return an array of Strings with x value at the first element and y at the second one;
if (splittedCoords.length == 2) {
String x = splittedCoords[0].trim(); // Method removes all spaces at the beginning and ending of a passed String
String y = splittedCoords[1].trim();
coords = new Coords(Integer.parseInt(x), Integer.parseInt(y)); //Creates new instance of Coords class. x and y are passed as constructor params.
} else {
System.out.println("Format for coords is wrong. You entered '" + coordsEntered + "'.");
}
} catch (NumberFormatException e) { // Integer.parseInt throws an exception if the string does not contain parsable integer.
// We catch an exception and handle it by writing a message
System.out.println("Coords are supposed to be numbers... You entered '" + coordsEntered + "'.");
}
return coords;
}
Also Set is more applicable in this case. Set contains no duplicate elements and Set.contains() method works faster then List.contains(). But if you want to use Set you should implement both equals() and hashCode() methods.
You want to loop if the coords are invalid or already fired.
So shouldn't the while condition be:
while(!validateCoords(coordsEntered)
|| coordsFiredAt(coordsEntered, coordsFired))

Sort algorithm problems on java comparable

I want to do a specific sort. I am using java's comparable interface which means the return of my compare method must return -1 +1 or 0 depending on the equality of the two compared, then I am sorting using Collections. My trouble comes from how I wish to compare.
I have a key that is made up of either of the following
[keyName]
[siteName].[keyName]
[siteName].[pageName].[keyName]
so as an example "mysite.alampshade.color"
the tricky part is the sites must be sorted first, followed by keyname, followed by pageName. but firstly by the keynames, then site name, in the order of the number of sections to the property. Sorry. its a little complicated, an example may help. here is the order they must be:
alpha
beta
charlie
sitea.alpha
sitea.charlie
sitea.pagea.beta
sitea.pageb.beta
sitea.pagea.charlie
siteb.alpha
siteb.delta
siteb.pagef.alpha
siteb.pageb.echo
siteb.pageb.golf
siteb.pagea.hotel
siteb.pageb.hotel
siteb.pagec.hotel
I have tried many different ways and have thrown away code a few times but still cant get it perfect. some pseudocode would be of great help if not some java.
EDIT:
to add another possibly simplier to understand example
the following is sorted how I need it
a
b
c
z
a.b
a.c
a.d
a.z
a.b.a
a.c.a
a.b.b
a.b.c
a.c.c
a.a.d
b.a
b.b
b.z
b.a.a
b.b.a
b.a.b
c.c.f
Another option, making it recursive you avoid the problem if there is ever more entries.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
public class SortTest {
public static void main(String[] args) {
String[] test = new String[]{
"a",
"b",
"b.a",
"b.a.a",
"a.a.a",
"a.b.a",
"a.a",
"a.b",
"b.a.b",
"b.b.a"
};
Arrays.sort(test, new Comparator<String>() {
int compareComplexList(List<String> a, List<String> b, List<int[]> positions, int order ) {
int minimum = a.size() < b.size() ? a.size() - 1 : b.size() - 1;
if (a.get(positions.get(minimum)[order]).compareTo(b.get(positions.get(minimum)[order])) != 0)
return a.get(positions.get(minimum)[order]).compareTo(b.get(positions.get(minimum)[order]));
else if (order < minimum - 1) return compareComplexList(a,b, positions, ++order);
else return Double.compare(a.size(),b.size());
}
public int compare(String a, String b) {
List<String> partsA = Arrays.asList(a.split("\\."));
List<String> partsB = Arrays.asList(b.split("\\."));
List<int[]> orders = new ArrayList<int[]>();
orders.add(new int[] {0});
orders.add(new int[] {0,1});
orders.add(new int[] {0,2,1});
return compareComplexList(partsA, partsB, orders,0);
}
});
System.out.println("Sorted: "+Arrays.toString(test));
}
}
Should be good now.
public int compare(String a, String b) {
String[] partsA = a.split("\\.");
String[] partsB = b.split("\\.");
// If first term is different, we exit.
if (partsA[0].compareTo(partsB[0]) != 0) return partsA[0].compareTo(partsB[0]);
// Else, first term is identical.
else {
// Same number of parts
if (partsA.length == partsB.length) {
// 2 parts, we compare the 2nd part.
if (partsA.length == 2) {
return partsA[1].compareTo(partsB[1]);
// 3 parts, we compare the 3rd part first, then the 2nd part
} else {
if (partsA[2].compareTo(partsB[2]) != 0) return partsA[2].compareTo(partsB[2]);
return partsA[1].compareTo(partsB[1]);
}
// Different number of parts
} else {
// If A has only 1 part, it's first
if (partsA.length == 1) return -1;
// If B has only 1 part, it's first
if (partsB.length == 1) return 1;
// Case 2 vs 3 parts, we compare the 3rd part with the 2nd part of the other. If it's equal, the shorter is first.
if (partsA.length == 3) {
if (partsA[2].compareTo(partsB[1]) != 0) return partsA[2].compareTo(partsB[1]);
else return 1;
} else {
if (partsA[1].compareTo(partsB[2]) != 0) return partsA[1].compareTo(partsB[2]);
else return -1;
}
}
}
}
My other answer started getting too gnarly. Here's a better, more natural solution:
public class StrangeComparator {
private static class Entry implements Comparable<Entry> {
// What to split with.
static final String dot = Pattern.quote(".");
// The parts.
final String key;
final String page;
final String site;
public Entry(String s) {
String [] parts = s.split(dot);
switch (parts.length) {
case 1:
key = parts[0];
page = "";
site = "";
break;
case 2:
key = parts[1];
page = "";
site = parts[0];
break;
case 3:
key = parts[2];
page = parts[1];
site = parts[0];
break;
default:
throw new IllegalArgumentException("There must be at least one part to an entry.");
}
}
#Override
public int compareTo(Entry t) {
int diff = site.compareTo(t.site);
if ( diff == 0 ) {
diff = page.compareTo(t.page);
}
if ( diff == 0 ) {
diff = key.compareTo(t.key);
}
return diff;
}
#Override
public String toString () {
return (site.length() > 0 ? site + "." : "")
+ (page.length() > 0 ? page + "." : "")
+ key;
}
}
public void test() {
String[] test = new String[]{
"alpha",
"beta",
"charlie",
"zeta", // Added to demonstrate correctness.
"sitea.alpha",
"sitea.charlie",
"sitea.pagea.beta",
"sitea.pageb.beta",
"sitea.pagea.charlie",
"siteb.alpha",
"siteb.delta",
"siteb.pagef.alpha",
"siteb.pageb.echo",
"siteb.pageb.golf",
"siteb.pagea.hotel",
"siteb.pageb.hotel",
"siteb.pagec.hotel"
};
Arrays.sort(test);
System.out.println("Normal sort: " + Separator.separate("\n", "\n", test));
Entry[] entries = new Entry[test.length];
for ( int i = 0; i < test.length; i++ ) {
entries[i] = new Entry(test[i]);
}
Arrays.sort(entries);
System.out.println("Special sort: " + Separator.separate("\n", "\n", entries));
}
public static void main(String args[]) {
new StrangeComparator().test();
}
}
Output order is:
alpha
beta
charlie
zeta
sitea.alpha
sitea.charlie
sitea.pagea.beta
sitea.pagea.charlie
sitea.pageb.beta
siteb.alpha
siteb.delta
siteb.pagea.hotel
siteb.pageb.echo
siteb.pageb.golf
siteb.pageb.hotel
siteb.pagec.hotel
siteb.pagef.alpha
Which kinda does what you say but doesn't match your example.
Here's an alternative - if a component is found to contain less that 3 parts then parts are added at the start to take up the slack. It then uses a sort order array to define which columns should be compared next:
public void test() {
String[] test = new String[]{
"alpha",
"beta",
"charlie",
"zeta", // Added to demonstrate correctness.
"sitea.alpha",
"sitea.charlie",
"sitea.pagea.beta",
"sitea.pageb.beta",
"sitea.pagea.charlie",
"siteb.alpha",
"siteb.delta",
"siteb.pagef.alpha",
"siteb.pageb.echo",
"siteb.pageb.golf",
"siteb.pagea.hotel",
"siteb.pageb.hotel",
"siteb.pagec.hotel"
};
Arrays.sort(test);
System.out.println("Normal sort: "+Arrays.toString(test));
Arrays.sort(test, new Comparator<String>() {
// How many columns to pad to.
final int padTo = 3;
// What to pad with.
final String padWith = "";
// What order to compare the resultant columns in.
final int[] order = {0, 2, 1};
#Override
public int compare(String s1, String s2) {
String[] s1parts = padArray(s1.split(Pattern.quote(".")), padTo, padWith);
String[] s2parts = padArray(s2.split(Pattern.quote(".")), padTo, padWith);
int diff = 0;
for ( int i = 0; diff == 0 && i < order.length; i++ ) {
diff = s1parts[order[i]].compareTo(s2parts[order[i]]);
}
return diff;
}
String [] padArray(String[] array, int padTo, String padWith) {
String [] padded = new String[padTo];
for ( int i = 0; i < padded.length; i++ ) {
padded[padded.length - i - 1] = i < array.length ? array[i]: padWith;
}
return padded;
}
});
System.out.println("Special sort: "+Arrays.toString(test));
}
prints (more or less):
Normal sort: [alpha,
beta,
charlie,
sitea.alpha,
sitea.charlie,
sitea.pagea.beta,
sitea.pagea.charlie,
sitea.pageb.beta,
siteb.alpha,
siteb.delta,
siteb.pagea.hotel,
siteb.pageb.echo,
siteb.pageb.golf,
siteb.pageb.hotel,
siteb.pagec.hotel,
siteb.pagef.alpha,
zeta]
Special sort: [alpha,
beta,
charlie,
sitea.alpha,
sitea.charlie,
siteb.alpha,
siteb.delta,
zeta,
siteb.pagef.alpha,
sitea.pagea.beta,
sitea.pageb.beta,
sitea.pagea.charlie,
siteb.pageb.echo,
siteb.pageb.golf,
siteb.pagea.hotel,
siteb.pageb.hotel,
siteb.pagec.hotel]
There does seem to be some ambiguity in your requirements but this code is structured so you can, with trivial tweaks, achieve most interpretations of your comparison quite simply.

Categories