Object becoming null outside return statements - java

this may be a simple problem, but I've looked for an answer and I'm just not finding it anywhere. I'm trying to use a method to check if an inputted answer is correct compared to the actual answer. The actual answer is defined by a setter, and the getter works also. But in the method where it's compared it becomes null. This isn't a question about why comparing them returns null, but why correctAnswer is null in the first place. I'm confused because getCorrectAnswer() works as intended.
Here is the code:
public class MultipleChoiceQuestion implements Question
{
String question;
String correctAnswer;
public String getQuestion()
{
return question;
}
public boolean isCorrectAnswer(String answer)
{
if (answer != correctAnswer)
{
return false;
}
return true;
}
public String getCorrectAnswer()
{
return correctAnswer;
}
public void setQuestion(String questionText){
question = questionText;
}
public void setAnswer(String answer){
correctAnswer = answer;
}
}
"answer != correctAnswer" doesn't work because correctAnswer is null in that method.

You shouldn’t use equality for classes unless you want to check that two are perfectly identical, that is, the same object. You should use Object.equals. So answer.equals(correctAnswer) is more correct. Also, are you sure that the setter was called first?

Related

How to compare sets without comparing the content

So, I have two Sets with elements of my class Capability.
public class Capability {
private String name;
public Capability(){
//
}
public Capability(String name){
this.name = name;
//this.id = count.getAndIncrement();
}
public String getName(){
return name;
}
#Override
public String toString(){
return "Capability: "+name+".";
}
}
Please disregard the value of this class over a String, this is for future expansion.
I'm trying to compare two sets that I've gotten from importing a json file, so they are not the same object, nor contain the same object, just have the same content.
public boolean allCapabilitiesMet(){
int count = 0;
for(Capability taskCap : this.getReqCapabilities()){
for(Capability primCap : this.getPrimitive().getCapabilities())
{
System.out.println(taskCap.equals(primCap));
System.out.println(taskCap.getName().equals(primCap.getName()));
if(taskCap.equals(primCap)){
count++;
}
}
}
return count == this.getReqCapabilities().size();
//return this.getPrimitive().getCapabilities().containsAll(this.getReqCapabilities());
}
The goal is to see if one set is a subset of the other, which I could do with the commented return before I switched to importing from the json file.
The thing is, I could fix this right now by simply changing the if clause to the string comparison, because that does indeed work. This would be terrible once I start adding other fields to the main class.
Is there anything I can do to compare the sets content without manually checking their content?
So I just replaced the equals() and hashCode() methods in Capability after adding an id field.
#Override
public boolean equals(Object obj){
if(this == obj)
return true;
if(obj == null || obj.getClass() != this.getClass())
return false;
Capability cap = (Capability) obj;
return (cap.getName().equals(this.getName()) && cap.getId() == this.getId());
}
#Override
public int hashCode()
{
return (int) this.id;
}
With this, I can use the solution that I'd originally planned for the comparison
public boolean allCapabilitiesMet(){
return this.getPrimitive().getCapabilities().containsAll(this.getReqCapabilities());
}
Is there any issue with this implementation? Sadly, I'll have to add a term to the if statement everytime I want to add a field to Capability. Is there any other way?

A real life example of public properties being bad

Countless times I've read that public properties on a class are a major faux pas, but I fail to see why on data that doesn't get transformed going in/out.
example of something I would write
public class Employee
{
public String firstName;
public String lastName;
private int ssn = 0;
public boolean setSsn(String s)
{
//makes perfect sense why something like an ssn would use a getter setter
//some code to validate ssn
if(!validSsn(s)){
ssn = 0;
return false;
}
ssn = raw;
return true;
}
public String getSsn()
{
return ssn;
}
private boolean validSsn(String s)
{
//validation goes here
retrun val;
}
//I don't understand why I should make firstName private
// and then write
public void setFirstName(String s)
{
firstName = s;
}
public String getFirstName(String s)
{
return firstName;
}
}
please provide a scenario in which this would cause a problem and please be specific, not "because it causes issues when other people use your code" WHY? Why does it cause issues. Thanks in advance for constructive criticism and detailed answers :D
Imagine that your code has gone to production. I write a front-end that uses your Employee class that accesses firstName and lastName directly.
6 months go by, and now there's a new business requirement that you add validation to the name fields.
Where are you going to add it? You're going to have to make the fields private and add set methods, and this will force me and everyone else using your code to re-write our apps.
If you had encapsulated that data properly in the first place, all we'd have to do is recompile using the new version of the library with your code.

Best practice for saving data in abstract classes

So, just as an example, let's say we have an abstract class called Question, that question contains a lot of strings, one for the question itself, one for the answer and two responses posted to the user, if he got the question right / wrong.
public abstract class Question {
private final String question;
private final String answer;
private final String answerCorrect;
private final String answerWrong;
}
My question basically is, what would be a common way to initialize all of the strings? So far I've made up 2 versions on how to do it, they have their up- and downsides and I wanted to know, if there was some kind of "best coding practice" for this.
Version A
Initialize everything in the constructor.
public abstract class Question {
//...
public Question(String question, String answer, String answerCorrect, String answerWrong) {
this.question = question;
this.answer = answer;
this.answerCorrect = answerCorrect;
this.answerWrong = answerWrong;
}
}
This seems pretty convenient, the only problem I have with this is that users will not be sure, in which order the strings have to be.
public class ExampleClass extends Question {
public ExampleClass() {
super("I think, that's the answer", "and that's the question", "answer wrong?", "answer right?");
}
}
Version B
Don't initialize instantly and wait for the user to do it.
public abstract class Question {
//...
public Question() {
this.question = "";
this.answer = "";
this.answerCorrect = "";
this.answerWrong = "";
}
public void setQuestion(String question) {
this.question = question;
}
//...
}
This makes it easier to initialize variables, but the Strings can't be final anymore and it's not guaranteed that the user will initialize all of them.
I've also thought about letting the child-class implement abstract methods that are called in the constructor of Question to initialize all the strings and to keep them final, but that version seemed a little too strange to me.
Are there other / better ways to do it? What version should I prefer?
Thanks in advance for your support.
Version A is the way to go. You're right, though, if you do not tell your users (the other developers I'm assuming) which parameter is which, there is no way for them to know where to type what.
This is where Javadoc comes in handy.
Here's an example:
/**
* Create a new instance of Question given the following parameters:
*
* #param question This is the question
* #param answer This is the answer
* #param answerCorrect Whenever someone guesses correct, print this
* #param answerWrong Whenever someone guesses wrong, print this
*/
public Question(String question, String answer, String answerCorrect, String answerWrong) {
this.question = question;
this.answer = answer;
this.answerCorrect = answerCorrect;
this.answerWrong = answerWrong;
}
This might be overkill, but I believe you could use a builder here...
public class Question
{
private final String question;
private final String answer;
private final String answerCorrect;
private final String answerWrong;
Question(QuestionBuilder builder) {
this.question = builder.question;
this.answer = builder.answer;
this.answerCorrect = builder.answerCorrect;
this.answerWrong = builder.answerWrong;
}
// public getters omitted to shorten answer
#Override
public String toString(){
return String.format("question: '%s', answer: '%s', answerCorrect: '%s', answerWrong: '%s'", question, answer, answerCorrect, answerWrong);
}
public static void main(String[] args) {
QuestionBuilder qb = new QuestionBuilder();
qb = qb.question("This is the question").answer("This is the answer").answerCorrect("Correct answer").answerWrong("Wrong Answer");
Question question = new Question(qb);
System.out.println(question);
}
public static class QuestionBuilder{
private String question;
private String answer;
private String answerCorrect;
private String answerWrong;
public QuestionBuilder question(String question) {
this.question = question;
return this;
}
public QuestionBuilder answer(String answer) {
this.answer = answer;
return this;
}
public QuestionBuilder answerCorrect(String answerCorrect) {
this.answerCorrect = answerCorrect;
return this;
}
public QuestionBuilder answerWrong(String answerWrong) {
this.answerWrong = answerWrong;
return this;
}
}
}
Gives the output
question: 'This is the question', answer: 'This is the answer', answerCorrect: 'Correct answer', answerWrong: 'Wrong Answer'
Note: I realize the original question was in reference to an abstract class. I used a concrete class so I could give a working example, although the solution can be adapted for use with an abstract class.
Instead of thinking of the attributes (such as question) as just variables, think of the restrictions on their values that must be obeyed for the classes to behave correctly. Can they be null? Can they be empty? Now design your methods and the constructor so it is impossible for those restrictions to be broken. You might find that the only way you can do this is to set initial values in the constructor (your version A). You might have to add pre-condition checks to your constructor and setter methods, which check the values given a throw a suitable exception (NullPointerException or IllegalArgumentException) if the values passed to them would result in the restrictions being broken.
Also, consider whether it really makes sense to change the value of an attribute after the object is constructed. If not, then the attribute should not a setter, making your version B impossible.

How to use a String in an Entity class hash code?

I'm making a web app that queries an SQL db. I'm under the impression that I need to use entity classes and facade classes to allow persistence - across the whole site. The entity class templates have hashcodes and 1.) Im not sure if I need them and 2.) If I do, they want int's but all I have are String so, how to convert them to int and then back to String? Because I need the String value to appear on the site and the hash wants int's.
heres the code (imports have been remove to protect the innocent...):
#Embeddable
public class ComputerOwnersPK implements Serializable {
#Basic(optional=false)
#NotNull
#Column(name="Computer_Name")
private int computerNameId;
#Basic(optional=false)
#NotNull
#Column(name="User_ID")
private int userId;
public ComputerOwnersPK() {
}
public ComputerOwnersPK(int computerNameId,int userId) {
this.computerNameId=computerNameId;
this.userId=userId;
}
public int getComputerNameId() {
return computerNameId;
}
public void setComputerNameId(int computerNameId) {
this.computerNameId=computerNameId;
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId=userId;
}
#Override
public int hashCode() {
int hash=0;
hash+=(int) computerNameId;
hash+=(int) userId;
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if(!(object instanceof ComputerOwnersPK)) {
return false;
}
ComputerOwnersPK other=(ComputerOwnersPK) object;
if(this.computerNameId!=other.userId) {
return false;
}
if(this.userId!=other.userId) {
return false;
}
return true;
}
#Override
public String toString() {
return "entity.ComputerOwnersPK[ computerNameId="+computerNameId+", userId="+userId+" ]";
}
}
Based on your comments I'm assuming you want computerNameId and userId to be Strings in your mapping and you have them mapped to ints because you don't know how to do the hashcode stuff.
In your hashCode method you should be able to concatenate the strings and then call hashcode on them. Very similar to what you are already doing.
private String computerNameId;
private String userId;
#Override
public int hashCode() {
// concatenate the interesting string fields
// and take the hashcode of the resulting String
return (computerNameId + userId).hashCode();
}
Make sure in your equals method you also change from != operators to !.equals method call for checking equality. Finally make sure you are keeping the contract between equals and hashCode or you could be in for some nasty surprises. Two objects that are equal must also have the same hashCode. Two objects that have the same hashCode may or may not be equal.

what's wrong with my class definition?

Why won't this class compile?
class Exam {
private int score;
// constructor initializes score to 99
public void Exam() {
score = 99;
}
// returns the current value of score
private int getScore() {
return score;
}
// returns the String representation of the Object
public String toString() {
return "The score is " + getScore();
}
}
Your constructor shouldn't have a return type. Not even void.
public Exam() {
score = 99;
}
A construct should not contain the void keyword:
public Exam() {
score = 99;
}
A constructor returns a reference the the newly created object. But you don't have to write it. So thinking it is void is wrong as well.
Constructors don't need return types. Remove void and you should be set.
In a constructor you don't use void.
Write the constructor as:
public Exam() {
score = 99;
}
The main problem is the missing package declaration.
package yourpkg;
class Exam {
Additionally, the return type on the for Exam() makes it a function instead of a constructor and will result in a warning.
Just a suggestion not related to the concrete problem:
private int score;
// returns the current value of score
private int getScore() {
return score;
}
There is no point in having that getScore() if your going to keep it private. Make it public.
Also, always use the #Override annotation whenever your intention is to override some method. Compiler will let you known in case you are failing to do so. That means bug prevention.
e.g.
// returns the String representation of the Object
#Override
public String toString() {
return "The score is " + getScore();
}

Categories

Resources