Java method to return multiple values - java

I have a situation where I would like to return 2 values from a method. I am trying to figure out how to do this in Java. In C# I would just use 2 out parameters or a struct in this case but not sure what is best to do for Java (other than Pair as I may have to change this to 3 values, or having to create a new class to return object).
My example is this:
public void myMethod(Signal signal){
MyEnum enum = MyEnum.DEFAULT;
String country = "";
// based on signal, I need to get 2 values, one is string, other is
// an enumeration
if (signal.getAction() == "Toyota"){
enum = MyEnum.TOYOTA;
country = "Japan";
} else if (signal.getAction() == "Honda"){
enum = MyEnum.HONDA;
country = "Japan";
} else if (signal.getAction() == "VW"){
enum = MyEnum.VW;
country = "Germany";
} else {
enum = MyEnum.DEFAULT;
country = "Domestic";
}
// how to return both enum and country?
return ???
}
This is just an example to explain what I need (returning one-something, having 2 values, one is string, other is an enum in this case). So, ignore any issues with my string comparison or logic, my point is how to return something. For example, in C#, I could define a struct and return that struct, or I could use out parameters to return 2 values. But I am not sure how to do that elegantly in Java.

I think this is mainly an example of what Jon Skeet has suggested. (edited to include country)
Make your Enum carry the text and the conversion functionality.
public enum AutoMake {
HONDA("Honda", "Japan"),
TOYOTA("Toyota", "Japan"),
VW("Volkswagon", "Germany");
private String country;
private String text;
private AutoMake(String text, String country) {
this.text = text;
}
public static AutoMake getMake(String str){
AutoMake make = null;
AutoMake[] possible = AutoMake.values();
for(AutoMake m : possible){
if(m.getText().equals(str)){
make = m;
break;
}
}
return make;
}
/**
* #return the country
*/
public String getCountry() {
return country;
}
/**
* #return the text
*/
public String getText() {
return text;
}
}
And then store the the make as an enum in the car object
public class Car {
private AutoMake make;
private String model;
public Car() {
}
public Car(AutoMake make, String model) {
super();
this.make = make;
this.model = model;
}
/**
* #return the make
*/
public AutoMake getMake() {
return make;
}
/**
* #return the model
*/
public String getModel() {
return model;
}
/**
* #param make the make to set
*/
public void setMake(AutoMake make) {
this.make = make;
}
/**
* #param model the model to set
*/
public void setModel(String model) {
this.model = model;
}
}
and now you can get both text and enum values from the car object
car.getMake() // Enum
car.getMake.getText() // Text
car.getMake.getCountry // Country
You can convert from text to enum with
Enum make = AutoMake.getMake("Honda");
This would mean AutoMake.getMake(Signal.getAction()) could replace myMethod(signal) with the resulting Enum carrying both make and country.

If you really really want to have tuples in java you can import them from the scala standard lib. As both languages are compiled to the same byte code they can be used together in one project.
import scala.Tuple2;
public class ScalaInJava {
public static Tuple2<String, Integer> tupleFunction(){
return new Tuple2<>("Hello World", 1);
}
public static void main(String[] args) {
System.out.println(tupleFunction()._1());
}
}

Related

In Java, how would I make a class that is essentially a subclass of string, but sets an allowable length range?

I'm trying to make a new object type which is intended to act like a subclass of String. I'm aware a class cannot extend String. I'm making application that has requirements such as a Contact's first name cannot be longer than 10 characters, and cannot be null, the last name cannot be more than 15 characters.
I started off making the class like so:
package Models;
/**
* #author Charles Hilton
*
*/
public class LimitedString {
private String value;
private static final String descriptor;
private static final Integer minimumLength;
private static final Integer maximumLength;
private static final boolean nullable;
public LimitedString(String value, String descriptor, Integer maximumLength, Integer minimumLength, boolean isNullable) throws Exception {
if (minimumLength < 0) {
throw new IllegalArgumentException("Minimum length cannot be less than 0");
}
if (minimumLength > maximumLength) {
throw new IllegalArgumentException("Minimum length cannot be greater than maximum length");
}
this.minimumLength = minimumLength;
this.maximumLength = maximumLength;
this.nullable = isNullable;
this.descriptor = descriptor; // i.e. descriptor = "Contact First Name"
this.setValue(value);
}
LimitedString(String descriptor, Integer maximumLength, Integer minimumLength, boolean isNullable) {
if (minimumLength < 0) {
throw new IllegalArgumentException("Minimum length cannot be less than 0");
}
if (minimumLength > maximumLength) {
throw new IllegalArgumentException("Minimum length cannot be greater than maximum length");
}
this.minimumLength = minimumLength;
this.maximumLength = maximumLength;
this.nullable = isNullable;
this.descriptor = descriptor; // i.e. descriptor = "Contact First Name"
this.setValue(value);
}
public String ToString() {
return this.value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
if (value == null && !nullable) throw new IllegalArgumentException("The value cannot be null.");
if (value.length() < minimumLength || value.length() > maximumLength) {
throw new IllegalArgumentException(String.format("#s must be between %s character(s) and %s characters long.", descriptor, minimumLength, maximumLength));
}
this.value = value;
}
public static String getDescriptor() {
return descriptor;
}
public static Integer getMinimumlength() {
return minimumLength;
}
public static Integer getMaximumlength() {
return maximumLength;
}
public static boolean isNullable() {
return nullable;
}
}
then using it in a Contact class like so:
/**
*
*/
package Models;
/**
* #author Charles Hilton
*
*/
public class Contact {
private LimitedString firstName = new LimitedString("First Name", 10, 1, false);
private LimitedString lastName = new LimitedString("Last Name", 15, 1, false);
private Contact() {};
public Contact(String lastName, String firstName) {
this.setLastName(lastName);
this.setFirstName(firstName);
}
public String getFirstName() {
return firstName.getValue();
}
public void setFirstName(String firstName) {
this.firstName.setValue(firstName);
}
public String getLastName() {
return lastName.getValue();
}
public void setLastName(String lastName) {
this.lastName.setValue(lastName);
}
}
I'm worried that it could be optimized better. For starters, in LimitedString. I made several fields static and final with the intention of trying to minimize memory usage as more contacts are added to a collection, which I apparently can't do the way I have it setup right now.
CharSequence
To directly answer your question, I suggest writing a class that implements the CharSequence interface. String, StringBuilder, and some other classes implement that interface.
If you want to be able to add more text to an existing object of your class, your class should also implement Appendable.
I imagine your class would contain a String. If appendable, perhaps a StringBuilder.
I don’t see the need for your descriptor field.
Rather than carry a nullable field, consider writing two classes. One is a subclass of the other, one tolerating a null, the other not.
Jakarta Bean Validation
A better solution to needs like null-checks, and like limiting the size of a field, is Jakarta Bean Validation. See specification page; Version 3 is current. See project page (a bit outdated).
Some validators are provided. And you can write your own validators.
You can invoke validators in your code. And the validators can be invoked by a user-interface built in JavaFX or built in Vaadin Flow.
I believe that the provided validators NotNull and Size would accomplish your goals. But NotBlank is better than NotNull as it also checks that the non-null text contains at least one non-whitespace character.
#NotBlank
#Size( min=1 , max=10 )
private String firstName ;

Override void method with calculation of private access variable

I am doing an assignment requiring me to create a program to store information on tools. The initial class is used to test the results of other classes. The other 4 are made up of a super class called Equipment and has to be abstract, and then 3 child classes.
I have managed to get the equipment class sorted (I think), but can not work out how to override the replacementYear property which is private as the math to return the result changes for each class.
Math for the battery powered class is
Replacement Year = Length of Warranty + Purchase Year
Do I need to create an object to complete the math in each class and use a return statement with the replacementYear I am overriding?
Sorry if it not extremely clear but below is the code.
//Parent
abstract class Equipment {
private String make;
private String model;
private int purchaseYear;
private String replacementYear;
//Constructor for Equipment
public Equipment()
{
make = " ";
model = " ";
purchaseYear = 0;
}
abstract void replacementYear();
public String getMake()
{
return make;
}
public void setMake(String newMake) {
this.make = newMake;
}
public String getModel()
{
return model;
}
public void setModel(String newModel) {
this.model = newModel;
}
public int getPurchaseYear()
{
return this.purchaseYear;
}
}
The child class:
class BatteryPoweredEquipment extends Equipment {
private int warranty = 0;
//Constructor
public void BatteryPoweredEquipment()
{ }
//set & get warranty
public int getWarranty()
{
return warranty;
}
public void setWarranty(int newWarranty)
{
this.warranty = newWarranty;
}
//override
#Override
void replacementYear() {
System.out.println(warranty + this.getPurchaseYear());
}
}
yea, if replacement year needs to computed differently for each type of equipment, then make this method abstract in the abstract superclass so that each extending class can override this to have their custom logic
First of all, you need to create an Equipment constructor that actually accepts all its properties, otherwise, your subclasses would be a pain to use (you would need to call each setter to actually build the object). Talking about setters, that is something you don't really or want (I guess that make, model, purchaseYear do not really change after the Equipment is built and replacementYear should be computed while constructing the object the first time). Additionally, please make use of the new Java Time API (which includes Year and Period instead of modeling years and warranty period as int). After doing this your Equipment class would look as follows:
import java.time.Year;
abstract class Equipment {
private String make;
private String model;
private Year purchaseYear;
private Year replacementYear;
//Constructor for Equipment
public Equipment(String make, String model, Year purchaseYear, Year replacementYear) {
this.make = make;
this.model = model;
this.purchaseYear = purchaseYear;
this.replacementYear = replacementYear;
}
public String getMake() {
return make;
}
public String getModel() {
return model;
}
public Year getPurchaseYear() {
return this.purchaseYear;
}
public Year getReplacementYear() {
return replacementYear;
}
}
Now you also need to adjust your child classes. BatteryPoweredEquipment would look as follows:
import java.time.Period;
import java.time.Year;
class BatteryPoweredEquipment extends Equipment {
private Period warranty;
public BatteryPoweredEquipment(String make, String model, Year purchaseYear, Period warranty) {
super(make, model, purchaseYear, purchaseYear.plus(warranty));
this.warranty = warranty;
}
public Period getWarranty() {
return warranty;
}
}

How do I read this Generics correctly from JSON?

I'm reasonably confident in my first generics container, but stuck on how to word the casting on the client side. This is what was working before I got involved in learning <T> stuff:
CommonNounContainer typeContainer = new Json().fromJson(CommonNounContainer.class, result);
I was looking at having to create a different container for each class, and that doesn't seem like good design. Below is my updated, non-working attempt to read in my new generics container:
JSONContainer<CommonNoun> typeContainer = new Json().fromJson(JSONContainer.class, result);
My IDE doesn't care for this phrasing, noting:
Type safety: The expression of type JSONContainer needs unchecked
conversion to conform to JSONContainer
When executed, my err log reads:
result = {"myObject":{"cid":{"oid":129},"name":"technology","form":1},"children":[]}
com.badlogic.gdx.utils.SerializationException: Field not found: cid (java.lang.Object)
Serialization trace:
{}.myObject.cid
myObject (semanticWeb.rep.concept.JSONContainer)
at com.badlogic.gdx.utils.Json.readFields(Json.java:854)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1011)
at com.badlogic.gdx.utils.Json.readFields(Json.java:863)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1011)
at com.badlogic.gdx.utils.Json.fromJson(Json.java:789)
at com.b2tclient.net.Communicator$2.handleHttpResponse(Communicator.java:95)
at com.badlogic.gdx.net.NetJavaImpl$2.run(NetJavaImpl.java:224)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:830)
I'm sure there's some way I'm supposed to include a reference to the CommonNoun type to the right of the equals sign, but I haven't been able to figure it out. How do I do it? There's lots of applicable posts concerning generics, casting, JSON, and stripping away of class information. One of them I tried to follow that wasn't about the casting above regarded adding the T class as a private variable within the container during construction:
How do I get a class instance of generic type T?
but I ran into similar syntax issues trying to refer to the class correctly, just in a different spot along the process. I have my doubts, too, that I can read this class variable from the JSON file before telling JSON how to classify the information in the file.
Javadoc for the fromJson(Class<T>, String) method:
Type Parameters:
<T>
Parameters:
type May be null if the type is unknown.
json
Returns:
May be null.
I may already have a viable answer submitted by deduper, but, as requested, here are the CommonNounContainer and JSONContainer classes:
import java.util.ArrayList;
public class CommonNounContainer {
private CommonNoun myCommonNoun;
private ArrayList<CommonNounContainer> children;
public CommonNounContainer(CommonNoun concept) {
myCommonNoun = concept;
children = new ArrayList<CommonNounContainer>();
}
//Creates an empty shell. This would be for categories you want to group by, but not display/select in the select box.
public CommonNounContainer() {
children = new ArrayList<CommonNounContainer>();
}
public void addChildren(ArrayList<CommonNounContainer> newChildren) {
children.addAll(newChildren);
}
public void addChild(CommonNoun concept) {
children.add(new CommonNounContainer(concept));
}
public ArrayList<CommonNounContainer> getChildren() {
return children;
}
public CommonNoun getValue() {
return myCommonNoun;
}
public boolean hasChildren() {
if (children.size() > 0) return true;
else return false;
}
public String toString() {
return myCommonNoun.toString();
}
}
public class JSONContainer<T> {
private T myObject;
private ArrayList<JSONContainer<T>> children;
// public Class<T> typeParameterClass;
public JSONContainer() {
}
public JSONContainer(T anObject) {
myObject = anObject;
children = new ArrayList<JSONContainer<T>>();
}
/* public JSONContainer(T anObject, Class<T> typeParameterClass) {
myObject = anObject;
children = new ArrayList<JSONContainer<T>>();
this.typeParameterClass = typeParameterClass;
}
*/
public void addChildren(ArrayList<JSONContainer<T>> newChildren) {
children.addAll(newChildren);
}
public void addChild(T concept) {
children.add(new JSONContainer<T>(concept));
}
public ArrayList<JSONContainer<T>> getChildren() {
return children;
}
public T getValue() {
return myObject;
}
public boolean hasChildren() {
if (children.size() > 0) return true;
else return false;
}
public String toString() {
return myObject.toString();
}
}
Additional classes requested:
public class CommonNoun extends Concept {
/**
*
*/
private static final long serialVersionUID = 6444629581712454049L;
public CommonNoun() {
super();
}
public CommonNoun(String name, ConceptID cidIn) {
super(name, cidIn);
this.form = ConceptDefs.COMMON_NOUN;
}
}
public class Concept implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2561549161503772431L;
private ConceptID cid = null;
private final String name;
Integer form = 0;
// ArrayList<ProperRelationship> myRelationships = null;
/* #Deprecated
public Concept(String name) {
this.name = name;
}*/
public Concept() {
name = "";
}
public Concept(String name, ConceptID cidIn) {
// this(name);
this.name = name;
cid = cidIn;
}
/*
* This should be over-ridden by any subclasses
*/
public Integer getForm() {
return form;
}
public ConceptID getID() {
return cid;
}
public void setID(ConceptID cidIn) {
cid = cidIn;
}
//this doesn't make any sense. Throw exception?
public String getName() {
return name;
}
public boolean isCommon() {
return true;
}
/**
*
* #return
*/
#Override
public String toString() {
return getName() + "(" + cid.toString() + ")";
}
public boolean equals(Concept other) {
return ((getID().equals(other.getID())));
}
}
public class ConceptID implements Serializable {
long oid;
public ConceptID() {
oid = -1;
}
public ConceptID(long oid) {
this.oid = oid;
}
public long getValue() {
return oid;
}
/**
*
* #return
*/
#Override
public String toString() {
return Long.toString(oid);
}
public Long toLong() {
return Long.valueOf(oid);
}
public boolean equals(ConceptID other) {
return (oid == other.getValue());
}
/**
* Factory model for generating ConceptIDs
*
* This one is here as a convenience as many IDs come in as a String from web POSTs
* #param idAsString
* #return
*/
static public ConceptID parseIntoID(String idAsString) {
ConceptID returnID = null;
try {
returnID = new ConceptID( Long.parseLong(idAsString) );
} catch (Exception e) {
System.err.println("Expected the string, " + idAsString + ", to be Long parsable.");
e.printStackTrace();
}
return returnID;
}
TL;DR:
Proposed Fix…
System.out.println( new Json( ).toJson( new JSONContainer<>( ... ) ) to see the correct string format of a JSONContainer's JSON.
Make sure your result input argument to Json.fromJson(Class<T>, String) is in the same format printed out in 1.
e.g. {myObject:{class:CommonNoun,cid:{oid:139},name:Jada Pinkett Smith,form:69},children:[{myObject:{class:CommonNoun,cid:{oid:666},name:Jaden Pinkett Smith,form:-666},children:[]},{myObject:{class:CommonNoun,cid:{oid:69},name:Willow Pinkett Smith,form:69},children:[]}]}
The long answer…
„My IDE doesn't care for this phrasing, noting:“
Type safety: The expression of type JSONContainer needs unchecked conversion to conform to JSONContainer
It's the compiler warning you about heap pollution. The IDE merely translated this compiler warning (which is what you'd see on the command line)…
...Communicator.java uses unchecked or unsafe operations.
...Recompile with -Xlint:unchecked for details.
…into the more user-friendly message the IDE showed you.
It is only a warning; not an error. To make that warning go away, change this: JSONContainer<CommonNoun> typeContainer = ... to this: JSONContainer typeContainer = ...
„When executed, my err log reads:“
result = {"myObject":{"cid":{"oid":129},"name":"technology","form":1},"children":[]}
com.badlogic.gdx.utils.SerializationException: Field not found: cid (java.lang.Object)...
The most likely cause of that error is — like the error message says — either your JSONContainer class or your CommonNoun class does not have the cid field that is present in the JSON string you're trying to deserialize.
I was able to reproduce that error with this…
...
private static final String JADEN_AS_JSON = "{jden:{class:CommonNoun,person:Jaden,place:Hollywood,thing:HashBeen}}";
private static final String JADEN_FAILS_AS_ACTOR = "{jden:{class:CommonNoun,person:Jaden,place:Hollywood,thing:HasBeen, cid:{oid:129} }}";
static public void main( String ... args ){
out.printf( "%1$22s%n", "foo");
JSONContainer< CommonNoun > wtf = new JSONContainer< > ( );
CommonNoun wtBrattyF = new CommonNoun( "Jaden Pinkett Smith", "Hollywood", "HasBeen" );
wtf.setJden( wtBrattyF );
out.printf( "%1$42s%n", wtf );
Json jden = new Json();
out.printf("%1$59s%n", jden.toJson( wtf ) );
JSONContainer wtReifiableF = jden.fromJson(JSONContainer.class, JADEN_AS_JSON); /* This is fine */
out.printf("%1$59s%n", jden.toJson( wtReifiableF ) );
JSONContainer/*< CommonNoun >*/ wtUnReifiableF = jden.fromJson( JSONContainer.class, JADEN_AS_JSON );
wtUnReifiableF = jden.fromJson( JSONContainer.class, JADEN_FAILS_AS_ACTOR ); /* This causes the error you reported */
}
...
Early on it succeeds; but later on it fails…
JSONContainer [ jden: CommonNoun [ person: Jaden Pinkett Smith, place: Hollywood, thing: HasBeen ] ]
{jden:{class:CommonNoun,person:Jaden Pinkett Smith,place:Hollywood,thing:HasBeen}}
{jden:{class:CommonNoun,person:Jaden,place:Hollywood,thing:HashBeen}}
Exception in thread "main" com.badlogic.gdx.utils.SerializationException: Field not found: cid (CommonNoun)
Serialization trace:
{}.jden.cid
jden (JSONContainer)
at com.badlogic.gdx.utils.Json.readFields(Json.java:893)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1074)
at com.badlogic.gdx.utils.Json.readFields(Json.java:902)
at com.badlogic.gdx.utils.Json.readValue(Json.java:1074)
at com.badlogic.gdx.utils.Json.fromJson(Json.java:829)
at DeduperAnswer.main(DeduperAnswer.java:33)
I have now confirmed by experimentation that given the existence of a Cid class…
public class Cid {
int oid;
/* ... getter and setter elided ... */
}
… And given the existence of a CommonNoun class that HAS A Cid…
public class CommonNoun {
Cid cid;
String name;
int form;
/* ... getters and setters elided ... */
}
…Then trying to deserialize a JSONContainer from a result that has the following value, will produce the exact same error you originally reported…
result = {"myObject":{"cid":{"oid":129},"name":"technology","form":1},"children":[]}
If your actual CommonNoun class is implemented like my stand-in above (with a Cid field), then you need to retry your json.fromJson(Class<?>, String) call with your result string formatted like…
{myObject:{class:CommonNoun,cid:{oid:139},name:Jada Pinkett Smith,form:69},children:[{myObject:{class:CommonNoun,cid:{oid:666},name:Jaden Pinkett Smith,form:-666},children:[]},{myObject:{class:CommonNoun,cid:{oid:69},name:Willow Pinkett Smith,form:69},children:[]}]}

get several method's return values from a class in one statement

Item searchByPattern(String pat)
{
for(Iterator iter = items.iterator(); iter.hasNext(); )
{
Item item = (Item)iter.next();
if ((xxxxxxxxxxxx).matches(".*"+pat+".*"))
{
return item;
}
}
}
The above code is part of a class from my java program
public class Item
{
private String title;
private int playingTime;
private boolean gotIt;
private String comment;
/**
* Initialise the fields of the item.
*/
public Item(String theTitle, int time)
{
title = theTitle;
playingTime = time;
gotIt = true;
comment = "";
}
public String getTitle() {
return title;
}
/**
* Enter a comment for this item.
*/
public void setComment(String comment)
{
this.comment = comment;
}
/**
* Return the comment for this item.
*/
public String getComment()
{
return comment;
}
/**
* Set the flag indicating whether we own this item.
*/
public void setOwn(boolean ownIt)
{
gotIt = ownIt;
}
/**
* Return information whether we own a copy of this item.
*/
public boolean getOwn()
{
return gotIt;
}
public int getPlayingTime()
{
return playingTime;
}
/**
* Print details about this item to the text terminal.
*/
public void print()
{
System.out.println("Title: " + title);
if(gotIt) {
System.out.println("Got it: Yes");
} else {
System.out.println("Got it: No");
}
System.out.println("Playing time: " + playingTime);
System.out.println("Comment: " + comment);
}
}
I want to access all the methods that return values from class Item and once it matches the statement in Item searchByPattern, it will return the object.
I knew that I can do it by or operator like item.getTitle().matches(".*"+pat+".*") ||item.getComment().matches(".*"+pat+".*")||.......
but is it possible to get the same result by using a method in (xxxxxxxxxx)?
This isn't directly possible to do, however there are a few things you can try (from easiest to hard):
Just check all String type methods yourself in your code.
Add a special method in Item that does the match so Item class can decide itself when it matches. Here again you will need to make check all Strings manually.
You could add a method to Item that returns all methods that return a String as functions:
Code:
List<Supplier<String>> getAllStringMethods() {
return Arrays.asList(this::getComment, this::getTitle);
}
You can then use that to check all Strings one at a time by doing:
boolean match = item.getAllStrings().stream()
.map(Supplier::get)
.anyMatch(s -> s.matches("pattern"));
You can use Reflection to inspect the Item.class to find all methods that take no parameters and return a String, and then invoke them one by one. This is complicated and slow, and beyond the scope of this answer to explain further.

What's good practice of creating input validation method in Java?

If I want to validate my input, should I make validation code as private helper methods or create a separate static helper class? Does the validation code increase the size of the object?
More Information
Let's say I have a class
import java.util.Vector;
public class Place {
private final double longitude;
private final double latitude;
private final String id;
private String address;
private String name;
private String types;
private String icon;
private String phoneNumber;
private String websiteUrl;
private int rating;
private Vector<Integer> challenges;
public static class Builder {
// required parameter
private final double longitude;
private final double latitude;
private final String id;
// optional parameter
private String address = "n/a";
private String name = "n/a";
private String icon = "n/a";
private String phoneNumber = "n/a";
private String websiteUrl = "n/a";
private String types = "n/a";
private Vector<Integer> challenges = new Vector<Integer>();
private int rating = 0;
public Builder(double longitude, double latitude, String id) {
assert(longitude >= -180.0 && longitude <= 180.0);
assert(latitude >= -90.0 && longitude <= 90.0);
this.longitude = longitude;
this.latitude = latitude;
this.id = id;
}
public Builder address(String address) {
this.address = address;
return this;
}
public Builder types(String types) {
this.types = types;
return this;
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder icon(String icon) {
this.icon = icon;
return this;
}
public Builder phoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
return this;
}
public Builder websiteUrl(String websiteUrl) {
this.websiteUrl = websiteUrl;
return this;
}
public Builder builder(int rating) {
this.rating = rating;
return this;
}
public Place build() {
return new Place(this);
}
}
public Place(Builder builder) {
// required parameters
longitude = builder.longitude;
latitude = builder.latitude;
id = builder.id;
// optional parameters
address = builder.address;
types = builder.types;
name = builder.name;
icon = builder.icon;
phoneNumber = builder.phoneNumber;
websiteUrl = builder.websiteUrl;
rating = builder.rating;
challenges = builder.challenges;
}
public double getLongitude() {
return longitude;
}
public double getLatitude() {
return latitude;
}
public String getId() {
return id;
}
public void setAddress(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
public String getTypes() {
return types;
}
public void setTypes(String types) {
this.types = types;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setIconUrl(String icon) {
this.icon = icon;
}
public String getIcon() {
return icon;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setWebsiteUrl(String websiteUrl) {
this.websiteUrl = websiteUrl;
}
public String getWebsiteUrl() {
return websiteUrl;
}
public void setRating(int rating) {
this.rating = rating;
}
public int getRating() {
return rating;
}
#Override
public String toString() {
return "(" + Double.toString(longitude) + ", " + Double.toString(latitude) + ")";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Place other = (Place) obj;
if (id == null) {
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
return true;
}
public Vector<Integer> getChallenges() {
return new Vector<Integer>(challenges);
}
public void addChallenges(Integer i) {
this.challenges.add(i);
}
public void showChallenges() {
for (Integer i : challenges) {
System.out.print(i + ", ");
}
}
}
If I have to validate address argument before setting it, where should I put the code for validating address in this case?
If you are talking just seeing if the entered String is formatted correctly or if the length is right, then you would use a private method. If you would on the other hand check if the address is correct (look it up on a map) or any more advanced stuff, it would make sense to create a AddressValidator interface and call it from that private method.
The reason for the private method being that you call this both from a constructor, setter or any other method that could suppy an address. The reason for the interface being that you might want to have e.g. an online / offline AddressValidator (MockAddressValidator, or one that calls a different class for each country etc).
As an AddressValidator could be reused in other classes, and to keep your code clean, I would create it as a top level interface + OnlineAddressValidator. This makes your class better readable as well. For full configurability, you might want to think about how you are going to supply the AddressValidator instance, e.g. through the constructor or one defined as a static final validator.
public interface AddressValidator {
static class AddressValidatorResult {
// some results, you might want to return some useful feedback (if not valid)
boolean isValid() {
throw new IllegalStateException("Method not implemented yet");
}
}
public static class AddressValidationException extends Exception {
private AddressValidationException(AddressValidatorResult result) {
// add some implementation
}
}
// don't throw ValidateException here, invalid addresses are normal for
// validators, even if they aren't for the application that uses them
AddressValidatorResult validateAddress(String address);
// don't throw ValidateException here, invalid addresses are normal for
// validators, even if they aren't for the application that uses them
}
public class DefaultAddressValidator implements AddressValidator {
public static class Params {
// some parameters for this specific validator
}
private final Params params;
public DefaultAddressValidator(Params params) {
// creates this validator
this.params = params;
}
#Override
public AddressValidatorResult validateAddress(String address) {
// perform your code here
// I don't like "return null" as it may lead to bugs
throw new IllegalStateException("Method not implemented yet");
}
}
// and use it like this
private void validateAddress(String address) throws AddressValidationException {
// e.g. field AddressValidator set in constructor
AddressValidatorResult result = addressValidator.validateAddress(address);
if (!result.isValid()) {
throw new AddressValidationException(result);
}
}
Should I make validation code as private helper methods or create a separate static helper class?
This totally depends on your context. It's impossible to say what should be the best design, without knowing what you are trying to realise.
After you edit: IMO, it is still not easy to tell you. If you only have to validate the address in one single point of your application (id: the setter method), I would validate it inside the setter method. If the input was invalid, I whould throw an IllegalArgumentException.
Does the validation code increase the size of the object?
However, the answer to your second question is No. To understand why, you have to know what Object Oriented Programming is.
Some references:
http://en.wikipedia.org/wiki/Object-oriented_programming
http://en.wikipedia.org/wiki/Class_(computer_science)
Should I make validation code as private helper methods or create a
separate static helper class?
It depends if you think that you'll need to reuse the same method also in another class for the same purpose(input validation) it is better write the method in a separate static helper class so you can reuse the method and maintain it easily.
If you write the same private helper method in several class each time that you need to make a changes you have to edit each method in each class, with a static helper class you change the code in one place only ...
Read about PropertyChangeListener and Bean Validation.
I tend to validate within the get() and set() methods wherever possible - calling external static methods for common tasks such as checking dates or cleaning input (i.e. to avoid sql injection)
If you only use (and are only ever going to use) the validation within one class, keep it as a private helper method. If in doubt, I tend to pull the functionality out into a static helper class. It makes very little difference to the amount of code, is no more effort to implement, and is much more flexible.
The short answer is: you should implement your validation code the way that your framework tells you to. Typically, this is a public method or an annotation. An interface could work too. If you add code, your class size will increase.
Data validation should be automatically called by your software's infrastructure. This helps to prevent programmers from forgetting to call the appropriate code. So, the methods should be public (an interface would work too).
Frameworks like Struts, Spring, Hibernate and have their own validation systems. Java EE leverages bean validation.
I recommend bean validation, because it performs validation regardless of the input source. When most people think of input validation, they think of data coming from the user e.g. HTTP Request, command console, Swing text field. Spring and Struts validation is often fine for those situations. But in long lived programs developed for enterprises, other data feeds often get introduced e.g. SQL database updates from another programs, database restoration after a crash, enterprise service bus, JMS.
That is why I prefer bean validation. The downside is that "safe sources" (data that you know is untainted) are validated unnecessarily. But with today's processing power, that should rarely be a significant concern.
Java EE Tutorial

Categories

Resources