This a little something I stumbled upon while programming and I wonder whether anyone could provide me with some insights here.
Imagine you have some enum-like classes, i.e. classes with loads of instances defined as constants of the class. As an example consider something like
public class ChildName {
private static final Map<String, ChildName> LUT = new TreeMap<>();
private final String name;
private ChildName(String name) {
this.name = name.toLowerCase();
LUT.put(name, this);
}
public static Collection<ChildName> getNames() {
return LUT.values();
}
public static ChildName fromValue(String name) {
return LUT.get(name);
}
public static final ChildName SARAH = new ChildName("Sarah");
public static final ChildName MEGAN = new ChildName("Megan");
public static final ChildName SANDY = new ChildName("Sandy");
public static final ChildName JOHN = new ChildName("John");
public static final ChildName BORIS = new ChildName("Boris");
// etc...
}
Now, one could argue that it might be necessary to split up between boy's names and girl's names (or consider names from different countries or whatever, you get the idea). The idea would be that you can still list all of the possible names, but also all the names for boys or all the names for girls. This could be done with something like
public class ChildName {
private static final Map<String, ChildName> LUT = new TreeMap<>();
private final String name;
protected ChildName(String name) {
this.name = name.toLowerCase();
LUT.put(name, this);
}
public static Collection<ChildName> getNames() {
return LUT.values();
}
public static ChildName fromValue(String name) {
return LUT.get(name);
}
// maybe here there are some gender-neutral names as constants left
public static final ChildName ALEX = new ChildName("Alex");
}
public class GirlsName {
private static final Map<String, ChildName> LUT = new TreeMap<>();
private GirlsName(String name) {
super(name);
LUT.put(name, this);
}
public static Collection<ChildName> getNames() {
return LUT.values();
}
public static final ChildName SARAH = new ChildName("Sarah");
public static final ChildName MEGAN = new ChildName("Megan");
public static final ChildName SANDY = new ChildName("Sandy");
// etc...
}
public class BoysName {
private static final Map<String, ChildName> LUT = new TreeMap<>();
private BoysName(String name) {
super(name);
LUT.put(name, this);
}
public static Collection<ChildName> getNames() {
return LUT.values();
}
public static final ChildName JOHN = new ChildName("John");
public static final ChildName BORIS = new ChildName("Boris");
// etc...
}
which could lead to huge Maps in each of the classes with massive overlaps.
There is probably not that much of a problem concerning efficiency or memory in this case, but despite that, it is still quite redundant and does not feel pretty.
It can be argued that the Map in the upper class could be omitted (assume the gender-neutral names are just duplicated in the subclasses or so) and the collection of all results could be retrieved from combining the collections of the subclasses. However, I would like to avoid this approach from a design point of view (imagine how messy that might get in case of a subclass for each country on this planet).
A more elegant solution (in my eyes) would be to keep a Map in every class, but in such a way that they share entries. Now I was wondering whether someone would now if this could be possible using a basic Map implementation. Other suggestions to solve this kind of problem are of course also welcome.
PS: I am aware that my proposal for an elegant solution is in fact not that much better, but I just can't come up with a better idea and I can't stop wondering how such kind of map could be implemented
Go one step further than enum-like, and make them enums:
interface ChildName {}
enum GirlsName implements ChildName {
Sarah, Megan, Sandy
}
enum BoysName implements ChildName {
John, Boris
}
Now look up map is not needed:
ChildName name = BoysName.valueOf("Boris");
I'll let you write the code to find either boy's or girl's name.
I would suggest using an actual enum, and instead of grouping them into distinct classes, storing attributes such as country and gender on the ChildName class, then filtering and grouping as necessary.
public enum Gender {
MALE, FEMALE
}
public enum Country {
USA, CA, UK
}
public enum ChildName {
SARAH(FEMALE, USA),
MEGAN(FEMALE, CA),
SANDY(FEMALE, UK),
JOHN(MALE, USA),
BORIS(MALE, UK);
private static final Map<String, ChildName> LUT;
static {
LUT = Array.stream(values())
.collect(Collectors.groupingBy(c -> c.name().toLowerCase()));
}
public static Collection<ChildName> getNames() {
return Arrays.asList(values());
}
public static ChildName fromValue(String name) {
return LUT.get(name.toLowerCase());
}
// some examples of filtering and grouping
// if necessary, they can be cached statically (like LUT)
public static List<String> getMaleNames() {
return Arrays.stream(values())
.filter(c -> c.getGender() == MALE)
.map(ChildName::name)
.collect(Collectors.toList());
}
public static Map<Gender, List<ChildName>> getGenderMapForCountry(Country country) {
return Arrays.stream(values())
.filter(c -> c.getCountry() == country)
.collect(Collectors.groupingBy(ChildName::getGender));
}
private final Gender gender;
private final Country country;
ChildName(Gender gender, Country country) {
this.gender = gender;
this.country = country;
}
public Gender getGender() {
return gender;
}
public Country getCountry() {
return country;
}
}
Related
I want to pass a static list through an interface.
So that I can execute the following code.
updateSingleItem(new InformationListModule(getNameByUUID(uid), value));
I am looking for the cleanest way to create a static list where I can output the name based on an ID. I want to pass this list to different classes.
How can I create a static list with which I can execute the command "getNameByUUID(uid)".
Maybe someone can tell me what is the cleanest solution and give a small example.
would be glad.
Vielen Lieben dank.
I have now implemented it this way.
public abstract class BluetoothUUIDs {
/* UUID SERVICES */
public static final HashMap<String, String> BLE_SERVICE_UUID_NAME;
public static final HashMap <String, String> BLE_SERVICE_UUID_TYPE;
/* UUID ATTRIBUTES */
...
{
/* UUID SERVICES TO NAME */
BLE_SERVICE_UUID_NAME = new HashMap<>();
.....
BLE_SERVICE_UUID_TYPE.put("1800","org.bluetooth.service.generic_access");
...
I don't know if it's the best, but it's a way.
You could consider using an EnumMap.
import java.util.EnumMap;
public enum UUIDs {
UUID_1("1800", "org.bluetooth.service.generic_access"),
// additional UUID‘s..
private final String uuid;
private final String name;
UUIDs(String uuid, String name) {
this.uuid = uuid;
this.name = name;
}
public String getUuid() {
return uuid;
}
public String getName() {
return name;
}
private static final EnumMap<UUIDs, String> uuidToName = new EnumMap<>(UUIDs.class);
private static final EnumMap<UUIDs, String> uuidToType = new EnumMap<>(UUIDs.class);
static {
for (UUIDs uuid : UUIDs.values()) {
uuidToName.put(uuid, uuid.getName());
uuidToType.put(uuid, uuid.getUuid());
}
}
public static String getNameByUuid(String uuid) {
for (UUIDs u : UUIDs.values()) {
if (u.getUuid().equals(uuid)) {
return u.getName();
}
}
return null;
}
public static String getUuidByName(String name) {
for (UUIDs u : UUIDs.values()) {
if (u.getName().equals(name)) {
return u.getUuid();
}
}
return null;
}
}
You can access the EnumMap in other classes by calling the methods getNameByUuid and getUuidByName.
String name = UUIDs.getNameByUuid("1800");
String uuid = UUIDs.getUuidByName("org.bluetooth.service.generic_access");
This is a suggestion you could try/use.
So I have this GameType class:
public class GameType {
private final String name;
public GameType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
and I have a list of my game types, so, basically I want to print all of my GameType classes' name field and I am using Java 8, this is what I have done so far:
List<String> list = new ArrayList<>();
gameTypes.forEach(gameType -> list.add(gameType.getName()));
System.out.println(list);
So, what I am asking is, is there a better way to do that?
You can try this:
System.out.println(gameTypes.stream()
.map(GameType::getName)
.collect(Collectors.toList()));
I'm trying to find a good way to orginize a group of constant values that are used simply for immutable data.
Here is what I'm currently attempting:
public class FishType {
//PredatorFishType extends FishType
public static final PredatorFishType SHARK = new PredatorFishType(5, 20, "Shark");
public static final FishType CAT_FISH = new FishType("Cat Fish");
private String name;
private FishType(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
I use reflection to gather the final values into a collection aswell. I used to utilize enum but was forced to think of a new way to do this when different types of fish came into play such as the predator which contains other data such as food and so on. These constants are only used for data displaying purposes and have no reason to be mutated.
If there is some way to have multiple enum types within the same enum (If that makes any sense at all), that'd be great.
Thanks for reading.
You can either use constructor overloading or a combination of overloading and a wrapper class. If you know for certain that this data is immutable and will always be that way, I don't see anything wrong with sticking to enums for it. For the sake of putting it into one class, I've included the enums in the EnumTester class, but you may not want to do that.
Here's an example that prints "Cat Fish 5 20 Shark" and "Cow Fish" when run, using nothing but enums and a wrapper class. You could put accessors wherever you need them, depending on what you actually want to do with the information - I'm trying to demonstrate how to compose the two enums, not how to use them.
package enums;
public class EnumTester
{
public enum MainType {
CAT_FISH("Cat Fish"), DOG_FISH("Dog Fish"), COW_FISH("Cow Fish"); //everything has a name...
private String name;
private MainType(String name){
this.name = name;
}
public String getTypeDetails(){
return name;
}
}
public enum SubType {
PREDATOR(5, 20, "Shark"), PREY(), MANATEE(); //but not everything has any additional information
private boolean isFullSubType;
private int val1;
private int val2;
private String subName;
private SubType(int val1, int val2, String subName){
this.isFullSubType = true;
this.val1 = val1;
this.val2 = val2;
this.subName = subName;
}
private SubType(){
this.isFullSubType = false;
this.val1 = -1;
this.val2 = -1;
this.subName = "none";
}
public String getSubTypeDetails()
{
if( isFullSubType ) {
return val1 + " " + val2 + " " + subName;
}
else {
return "";
}
}
}
private MainType mainType;
private SubType subType;
public EnumTester(MainType mainType, SubType subType)
{
this.mainType = mainType;
this.subType = subType;
}
public static void main(String[] args)
{
EnumTester kittyShark = new EnumTester(MainType.CAT_FISH, SubType.PREDATOR);
System.out.println(kittyShark.printDetails());
EnumTester cowManatee = new EnumTester(MainType.COW_FISH, SubType.MANATEE);
System.out.println(cowManatee.printDetails());
}
public String printDetails(){
return mainType.getTypeDetails()+" "+subType.getSubTypeDetails();
}
}
I typically follow a similar pattern to what you've done above. I might make the class FishTypes to be the collector, just to keep the FishType interface a bit cleaner. You can also invent some syntactic sugar to help you collect registered FishTypes:
public static final Set<FishType> registeredFish = new HashSet<>();
public static final PredatorFishType SHARK = register(new PredatorFishType(5, 20, "Shark"));
public static final FishType CAT_FISH = register(new FishType("Cat Fish"));
public static <T extends FishType> T register(T fishType) {
registeredFish.add(fishType);
return fishType;
}
I have a set with String and i want to create hash map with String key and Node Object value.
and this is my code
Set<String> cities = new HashSet<>();
Map<String, Node> allCity = new HashMap<>();
Iterator<String> c = cities.iterator();
while(c.hasNext()){
String name = c.next();
Node cit = new Node(name);
allCity.put(name, cit);
}
my problem is when i read first from c iterator and correctly make new object and put it to hash map but when second object was create in my hash map the previous object value was change like this
first read
key = "New York"
Value = Node (and the value of node is New York)
second read
Key = "Los Angles"
Value = Node (and the value of node is Los Angles)
and my first read Value with New York key was change to Los Angles.
myNode class
public class Node{
private static String city;
private static double pathCost;
private ArrayList<Edge> neighbours;
private Node parent;
public Node(String cityName){
city = cityName;
neighbours = new ArrayList<>();
}
public static String getValue() {
return city;
}
public static void setValue(String city) {
Node.city = city;
}
public static double getPathCost() {
return pathCost;
}
public static void setPathCost(double pathCost) {
Node.pathCost = pathCost;
}
public static String getCity() {
return city;
}
public static void setCity(String city) {
Node.city = city;
}
public ArrayList<Edge> getNeighbours() {
return neighbours;
}
public void setNeighbours(ArrayList<Edge> neighbours) {
this.neighbours = neighbours;
}
public void addNeighbours(Edge n){
this.neighbours.add(n);
}
public Node getParent() {
return parent;
}
public void setParent(Node parent) {
this.parent = parent;
}
#Override
public String toString() {
return city;
}
}
Please help me.
That's because you made the city (and pathCost) fields static. A static field belongs to the class, not to a specific instance of this class. Each node has a specific city, so you want to mek the city field an instance field, and not a static field.
Read the Java tutorial about class members.
The city member in your Node class is static. This means all the Nodes share the same city, and when one instance updates it (e.g., in the constructor), the change applies for all of them.
To resolve this issue, you could change city to be an instance member:
public class Node{
private String city;
...
Without looking thoroughly there is a major mistake here:
private static String city;
city is node (i.e. instance) data and should not be static.
Since it is static in your case, all nodes share one value for city, which most probably isn't what you want. The same applies to pathCost.
I am trying to print the first element on the two arrays in my Athlete class, country and name. I also need to create a object that simulates three dive attemps an athlete had (that is initially set to zero). I am new to OOP and I dont know how to go abouts doing this in my main... as far as constructors go. This is what i have done so far...
this is the main:
import java.util.Random;
import java.util.List;
public class Assignment1 {
public static void main(String[] args) {
Athlete art = new Athlete(name[0], country[0], performance[0]);
}
}
I just really am not sure what to do...
And this is the class with the arrays.
import java.util.Random;
import java.util.List;
public class Athlete {
public String[] name = {"Art", "Dan", "Jen"};
public String[] country = {"Canada", "Germant", "USA"};
//Here i would like to create something that would be representing 3 dive attemps (that relate to dive and score. eventually.)
Athlete(String[] name, String[] country, Performance[] performance) {
this.name = name;
this.country=country;
this.performance=performance;
}
public Performance Perform(Dive dive){
dive.getDiveName();
return null;
}
public String[] getName() {
return name;
}
public void setName(String[] name) {
this.name = name;
}
public String[] getCountry() {
return country;
}
public void setCountry(String[] country) {
this.country = country;
}
}
thanks in advance for any help and input!
btw there is other classes too, just not relevant atm..
First, as for your Athlete class, you can remove your Getter and Setter methods since you have declared your instance variables with an access modifier of public. You can access the variables via <ClassName>.<variableName>.
However, if you really want to use that Getter and Setter, change the public modifier to private instead.
Second, for the constructor, you're trying to do a simple technique called shadowing. Shadowing is when you have a method having a parameter with the same name as the declared variable. This is an example of shadowing:
----------Shadowing sample----------
You have the following class:
public String name;
public Person(String name){
this.name = name; // This is Shadowing
}
In your main method for example, you instantiate the Person class as follow:
Person person = new Person("theolc");
Variable name will be equal to "theolc".
----------End of shadowing----------
Let's go back to your question, if you just want to print the first element with your current code, you may remove the Getter and Setter. Remove your parameters on your constructor.
public class Athlete {
public String[] name = {"Art", "Dan", "Jen"};
public String[] country = {"Canada", "Germany", "USA"};
public Athlete() {
}
In your main method, you could do this.
public static void main(String[] args) {
Athlete art = new Athlete();
System.out.println(art.name[0]);
System.out.println(art.country[0]);
}
}
Currently you can't access the arrays named name and country, because they are member variables of your Athelete class.
Based on what it looks like you're trying to do, this will not work.
These arrays belong in your main class.
Your attempt at an athlete class seems to be dealing with a group of athletes, which is a design fault.
Define a class to represent a single athlete, with fields that represent the athlete's attributes:
public class Athlete {
private final String name;
private final String country;
private List<Performance> performances = new ArrayList<Performance>();
// other fields as required
public Athlete (String name, String country) {
this.name = name;
this.country = country;
}
// getters omitted
public List<Performance> getPerformances() {
return performances;
}
public Performance perform(Dive dive) {
// not sure what your intention is here, but something like this:
Performance p = new Performance(dive, this);
// add new performance to list
performances.add(p);
return p;
}
}
Then your main method would use ti like this:
public class Assignment1 {
public static void main(String[] args) {
String[] name = {"Art", "Dan", "Jen"};
String[] country = {"Canada", "Germant", "USA"};
Dive[] dive = new Dive[]{new Dive("somersault"), new Dive("foo"), new Dive("bar")};
for (int i = 0; i < name.length; i++) {
Athlete athlete = new Athlete(name[i], country[i]);
Performance performance = athlete.perform(dive[i]);
// do something with athlete and/or performance
}
}
}
I think you are a little messed up with what you doing.
Athlete is an object, athlete has a name, i has a city where he lives.
Athlete can dive.
public class Athlete {
private String name;
private String city;
public Athlete (String name, String city){
this.name = name;
this.city = city;
}
--create method dive, (i am not sure what exactly i has to do)
public void dive (){}
}
public class Main{
public static void main (String [] args){
String name = in.next(); //enter name from keyboad
String city = in.next(); //enter city form keybord
--create a new object athlete and pass paramenters name and city into the object
Athlete a = new Athlete (name, city);
}
}
public static void main(String[] args) {
public String[] name = {"Art", "Dan", "Jen"};
public String[] country = {"Canada", "Germant", "USA"};
// initialize your performance array here too.
//Your constructor takes arrays as an argument so you need to be sure to pass in the arrays and not just objects.
Athlete art = new Athlete(name, country, performance);
}
First off, the arrays are pointless, let's get rid of them: all they are doing is providing values for mock data. How you construct mock objects has been debated ad nauseum, but clearly, the code to create the fake Athletes should be inside of a unit test. I would use Joshua Bloch's static builder for the Athlete class, but you only have two attributes right now, so just pass those in a Constructor. Would look like this:
class Athlete {
private String name;
private String country;
private List<Dive> dives;
public Athlete(String name, String country){
this.name = name;
this.country = country;
}
public String getName(){
return this.name;
}
public String getCountry(){
return this.country;
}
public String getDives(){
return this.dives;
}
public void addDive(Dive dive){
this.dives.add(dive);
}
}
Then for the Dive class:
class Dive {
private Athlete athlete;
private Date date;
private double score;
public Dive(Athlete athlete, double score){
this.athlete = athlete;
this.score = score;
this.date = new Date();
}
public Athlete getAthlete(){
return this.athlete;
}
public Athlete getAthlete(){
return this.athlete;
}
public Athlete getAthlete(){
return this.athlete;
}
}
Then make a unit test and just construct the classes, and manipulate them, make sure that they are working. Right now they don't do anything so all you could do is assert that they are retaining the Dives that you are putting in them. Example:
#Test
public void testThatDivesRetainInformation(){
Athlete art = new Athlete("Art", "Canada");
Dive art1 = new Dive(art, 8.5);
Dive art2 = new Dive(art, 8.0);
Dive art3 = new Dive(art, 8.8);
Dive art4 = new Dive(art, 9.2);
assertThat(art.getDives().size(), is(5));
}
Then you could go through and add tests for things like, making sure that you can't construct a dive without an athlete, etc.
You could move construction of the athletes into the setup method of the test so you could use it all over the place. Most IDEs have support for doing that with a refactoring.