I want to test if it adds all of the elements into the group array using Junit.
Here's the code:
public class Group{
private String groupName;
private ArrayList<Item> group = new ArrayList<Item>();
public Group(String groupName) {
super();
this.groupName = groupName;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public void addItem(Item item) {
group.add(item);
}
public Item getItem(int index) {
return group.get(index);
}
public String toString(boolean includePrice) {
String string = "Group \"" + groupName + "\" contains...\n";
for (int i = 0; i < group.size(); i++) {
Item item = group.get(i);
String itemString = includePrice? item.toString() : item.getDisplayName();
string = string + (i + 1) + ") " + itemString + "\n";
}
return string;
}
}
There are 2 ways to test if addItem method adds all of the elements into the group array-
1st way
Create a method getItems like this
public List<Item> getItems() {
return group;
}
and in the junit test call the getItems method to check if all the elements are added
#Test
void shouldAddAllItems1() {
Group group = new Group("group1");
List<Item> expectedItems = Arrays.asList(new Item("item1"), new Item("item2"));
group.addItem(new Item("item1"));
group.addItem(new Item("item2"));
assertEquals(expectedItems, group.getItems());
}
2nd way
Use the getItem(int index) method to check if all the elements are added.
#Test
void shouldAddAllItems2() {
Group group = new Group("group2");
group.addItem(new Item("item1"));
group.addItem(new Item("item2"));
assertEquals(new Item("item1"), group.getItem(0));
assertEquals(new Item("item2"), group.getItem(1));
}
Note: For both solutions, you will need to override the equals and hashcode methods in Item class for the equality check to work.
Related
right now I have the following:
ObservableList<Person> personsList;
and my UI for displaying the person list is tied to personsList.
Person is something like below:
class Person {
Name name
// other details
List<SomeItem> list;
}
// Item is immutable, but SomeItem can mutate by setting and getting the Items
class SomeItem {
Item item
Item item2
}
The issue is SomeItem is mutable, so I would want any changes to SomeItem be propagated to the original personsList.
How would I achieve something like that?? Based on googling I kind of have the following modifications, but I am not sure if they work!
class Person {
Name name
// other details
List<SomeItem> list; // <-- change to ObservableListValue<SomeItem>
}
// Item is immutable, but SomeItem can mutate by setting and getting the Items
class SomeItem {
Item item // <-- change to ObservablePropertyBase<Item>
Item item2 // <-- change to ObservablePropertyBase<Item>
}
From what I understand, this changes would make SomeItem report when any ObservablePropertyBase<Item> changes, and then ObservableListValue<SomeItem> would propagate this changes up, which would be caught by personsList?
Edit: Question 2:
Is it possible to force refresh personsList? Lets say I make an overall update to a specific SomeItem, then I can refresh the entire personsList?
You can fire Change events by creating an ObservableList with an extractor.
Here is an example:
Name.java:
public class Name {
private final String name;
public Name(String name) {
this.name = name;
}
public final String getName() {
return name;
}
}
Item.java:
public class Item {
private final String name;
public Item(String name) {
this.name = name;
}
public final String getName() {
return name;
}
#Override
public String toString() {
return name;
}
}
SomeItem.java:
public class SomeItem {
private final ObjectProperty<Item> item1 = new SimpleObjectProperty<>(this, "item1");
private final ObjectProperty<Item> item2 = new SimpleObjectProperty<>(this, "item2");
public SomeItem(Item item1, Item item2) {
this.item1.set(item1);
this.item2.set(item2);
}
public final ObjectProperty<Item> item1Property() {
return item1;
}
public final Item getItem1() {
return item1.get();
}
public final void setItem1(Item item) {
item1.set(item);
}
public final ObjectProperty<Item> item2Property() {
return item2;
}
public final Item getItem2() {
return item2.get();
}
public final void setItem2(Item item) {
item2.set(item);
}
#Override
public String toString() {
return "[" + item1.get() + ", " + item2.get() + "]";
}
}
Person.java:
public class Person {
private final Name name;
private final ObservableList<SomeItem> someItems = FXCollections.observableArrayList(someItem ->
new Observable[]{someItem.item1Property(), someItem.item2Property()});
public Person(Name name, SomeItem... someItems) {
this.name = name;
this.someItems.addAll(someItems);
}
public final Name getName() {
return name;
}
public final ObservableList<SomeItem> getSomeItems() {
return someItems;
}
#Override
public String toString() {
return "[name=" + name.getName() + ", someItems=" + someItems + "]";
}
}
App.java:
public class App extends Application {
#Override
public void start(Stage stage) {
SomeItem someItem1 = new SomeItem(new Item("item1"), new Item("item2"));
SomeItem someItem2 = new SomeItem(new Item("item3"), new Item("item4"));
SomeItem someItem3 = new SomeItem(new Item("item5"), new Item("item6"));
SomeItem someItem4 = new SomeItem(new Item("item7"), new Item("item8"));
Person person1 = new Person(new Name("person1"), someItem1, someItem2);
Person person2 = new Person(new Name("person2"), someItem3, someItem4);
ObservableList<Person> persons = FXCollections.observableArrayList(person ->
new Observable[]{person.someItemsProperty()});
persons.addAll(person1, person2);
persons.addListener((ListChangeListener<Person>) c -> {
while (c.next()) {
if (c.wasUpdated()) {
System.out.println("Updated persons:");
IntStream.range(c.getFrom(), c.getTo())
.mapToObj(index -> "Person at index " + index + " was updated to: " + c.getList().get(index))
.forEach(System.out::println);
}
}
});
// Update items to trigger change event for testing
someItem1.setItem1(new Item("item1Updated"));
someItem4.setItem2(new Item("item8Updated"));
}
public static void main(String[] args) {
launch();
}
}
Output:
Updated persons:
Person at index 0 was updated to: [name=person1, someItems=[[item1Updated, item2], [item3, item4]]]
Updated persons:
Person at index 1 was updated to: [name=person2, someItems=[[item5, item6], [item7, item8Updated]]]
I have a String like below with three or four values seperated by |||, so when split on ||| it can give three string single pipe seperated or four strings pipe seperated
james|12343|ascxZCCVVsss|||Alex|341234|asdasdUsadf|21444|||.....
I wanted to create a list of Person objects
class Person {
String name;
String id;
String accessCode;
String optionalID;
// Getters and setters left out for brevity
}
Also I have a builder class to build it.
public String getParsed(String str) throws JsonProcessingException {
String[] strSplit = str.split(Pattern.quote("|||"));
List<Person> perList = new ArrayList<>();
Arrays.stream(strSplit).forEach(item -> {
String[] val = item.split(Pattern.quote("|"));
if (val.length >= 2) {
perList.add(PersonBuilder.asPerson()
.withName(val[0])
.withId(val[1])
.withAccessCode(val[3])
.withOptionalId(val.length > 2 ? val[3] : StringUtils.EMPTY)
.build());
}
});
if (!CollectionUtils.isEmpty(perList)) {
return mapper.writeValueAsString(perList);
}
return StringUtils.EMPTY;
}
This code works. but Im wondering if there is a better way of doing this using Java 8. Also using index reference is a scary thing for me :)
Some cosmetic change is possible to replace {...} block with shorter map / filter stream methods instead of forEach:
public String getParsed(String str) throws JsonProcessingException {
List<Person> perList = Arrays.stream(str.split(Pattern.quote("|||")))
.map(item -> item.split(Pattern.quote("|"))) // Stream<String[]>
.filter(val -> val.length >= 3)
.map(val -> PersonBuilder.asPerson()
.withName(val[0])
.withId(val[1])
.withAccessCode(val[2])
.withOptionalId(val.length > 3 ? val[3] : StringUtils.EMPTY)
.build()
)
.collect(Collectors.toList());
return perList.isEmpty()
? StringUtils.EMPTY
: mapper.writeValueAsString(perList);
}
However, if a valid JSON String should be returned from this method, it may be better to return mapper.writeValueAsString(perList); which supplies "[]" for an empty list instead of "".
I think your solution is pretty well. I just can only offer to make it a bit more efficient: not using streams and process the given String only once:
public static List<Person> getPersons(String str) {
List<Person> persons = new ArrayList<>();
Queue<String> queue = new LinkedList<>();
int fromIndex = 0;
while (true) {
int index = str.indexOf('|', fromIndex);
if (index < 0)
queue.add(str.substring(fromIndex));
else if (index != fromIndex)
queue.add(str.substring(fromIndex, index));
if (index < 0 || index == fromIndex) {
String name = queue.remove();
String id = queue.remove();
String accessCode = queue.remove();
String optionalID = queue.isEmpty() ? StringUtils.EMPTY : queue.remove();
persons.add(new Person(name, id, accessCode, optionalID));
if (index < 0)
break;
index++;
}
fromIndex = index + 1;
}
return persons;
}
P.S. Below is a bit complicated alternative solution, but it looks like OOP style. It uses custom Iterator to find Person in the given String.
public final class Person {
private final String name;
private final String id;
private final String accessCode;
private final String optionalId;
public static Builder builder() {
return new Builder();
}
private Person(Builder builder) {
name = builder.name;
id = builder.id;
accessCode = builder.accessCode;
optionalId = builder.optionalId;
}
public static final class Builder {
private String name;
private String id;
private String accessCode;
private String optionalId = StringUtils.EMPTY;
public Person build() {
return new Person(this);
}
public Builder setName(String name) {
this.name = name;
return this;
}
public Builder setId(String id) {
this.id = id;
return this;
}
public Builder setAccessCode(String accessCode) {
this.accessCode = accessCode;
return this;
}
public Builder setOptionalId(String optionalId) {
this.optionalId = optionalId;
return this;
}
}
#Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", id='" + id + '\'' +
", accessCode='" + accessCode + '\'' +
", optionalID='" + id + '\'' +
'}';
}
}
public final class PersonStream {
public static Stream<Person> createFrom(String str) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
new PersonIterator(str), Spliterator.ORDERED), false);
}
private PersonStream() {
}
private static final class PersonIterator implements Iterator<Person> {
private final String str;
private Person person;
private int fromIndex;
public PersonIterator(String str) {
this.str = str;
}
#Override
public boolean hasNext() {
return person != null || fromIndex >= 0;
}
#Override
public Person next() {
if (!hasNext())
throw new NoSuchElementException();
if (person == null) {
String name = readNextPart();
String id = readNextPart();
String accessCode = readNextPart();
String optionalId = readNextPart();
person = Person.builder()
.setName(name)
.setId(id)
.setAccessCode(accessCode)
.setOptionalId(optionalId)
.build();
if (fromIndex >= 0)
fromIndex += optionalId == null ? 1 : 2;
}
try {
return person;
} finally {
person = null;
}
}
private String readNextPart() {
int index = str.indexOf('|', fromIndex);
if (index == fromIndex) {
fromIndex++;
return null;
}
try {
return index < 0 ? str.substring(fromIndex)
: str.substring(fromIndex, index);
} finally {
fromIndex = index < 0 ? -1 : index + 1;
}
}
}
}
As result, the Demo will be very simple:
public static void main(String... args) {
String str = "james|12343|ascxZCCVVsss|||Alex|341234|asdasdUsadf|21444";
PersonStream.createFrom(str).forEach(System.out::println);
}
You said you wanted to Build a list of Person objects but your method is returning a String. Perhaps I am either oversimplifying or not understanding what you want. But here is what I came up with. For this demo, I am using a Person record which is basically an immutable class.
record Person(
String getName,
String getId,
String getAccessCode,
String getOptionalID) {}
String s =
"james|12343|ascxZCCVVsss|||Alex|341234|asdasdUsadf|21444";
List<Person> list = Arrays.stream(s.split("\\Q|||\\E"))
.map(r->r.split("\\|"))
.filter(arr->arr.length >= 3)
.map(v->new Person(v[0], v[1], v[2], v.length == 4 ? v[3] : ""))
.toList();
list.forEach(System.out::println);
Prints
Person[getName=james, getId=12343, getAccessCode=ascxZCCVVsss, getOptionalID=]
Person[getName=Alex, getId=341234, getAccessCode=asdasdUsadf, getOptionalID=2144
4]
I am trying to ignore the existing item that I added in the duplicate.
Normally, if the item does not exist it will eventually added the item to the
LinkedList
When I try to added item again, I just wanted to ignore the adding process and the increment the value by 1.
But the problem is it keep adding the items to the LinkedList.
Can someone explain to me?
class Item{
Store store;
String name;
String code;
String number;
public Item(String name, String code){
this.name = name;
this.code = code;
number = 0;
}
public boolean itemExists(String name, String code){
return this.name.equals(name) && this.code.equals(code);
}
public void increment(){ number++; }
#Override
public String toString(){ return store.getName()+ " " + name + " " + code + " " +number; }
}
Items will be added to the factory.
class Factory{
private LinkedList<Item> items = new LinkedList<Item>():
private String name;
private String number;
public Factory(String name, String number){
this.name = name;
this.number = number;
}
public void getName(){
return name;
}
public void addItem(String name, String code){
items.add(new Item(this, name, code));
}
#Override
public String toString(){ return name + " " + number; }
public List<Item> getItems{
return items;
}
}
The factory then delivery to the store.
class Store{
private LinkedList<Factory> factories = new LinkedList<>();
public Store(){
factories.add(new Factory("MayFlower", "01");
factories.add(new Factory("SunFlower", "02");
factories.get(0).addItem("GTA", "001A");
factories.get(0).addItem("GTA", "002A");
factories.get(0).addItem("GTA", "003A");
factories.get(1).addItem("Sonic", "022A");
factories.get(1).addItem("Sonic", "023B");
factories.get(1).addItem("Sonic", "024C");
}
public List<Item> getItemFromFact(){
List<Item> temp = new ArrayList<>();
for(Factory factory: factories)
for(Item item: factory.getItems())
temp.add(item);
return temp;
}
}
The customer buy items at the store.
class Customer{
private LinkedList<Item> items = new LinkedList<>();
public static void main(String args[]){
new Customer.view();
}
private void view(){
for(Item item: items)
System.out.println(item);
}
private void adding(){
String name = "GTA";
String code = "001A":
List<Item> item = item(name, code);
if(!item.isEmpty()){
items.add(item);
item.increment(); // will increment the value;
}
else{
System.out.println("Item does not exists");
}
}
private List<Item> item(String name, String code){
List<item> temp = new ArrayList<>();
List<item> fromStore = new Store().getItemFromFact();
for(Item item: fromStore)
if(item.itemExists(name, code))
temp.add(item)
return temp;
}
}
The main problem is in the item class under item(). If I try with the same item again, it will just add another it become like this.
MayFlower GTA 001A 1
MayFlower GTA 001A 1
The result should be
MayFlower GTA 001A 2
after I added another item.
I problem I have is that I don't know how to match the item from exisiting.
If someone know the solution.
That's would be very helpful thanks.
There are so many problems in your design and code. I've discussed some of them as given below:
I do not understand why you need a reference to Store in Item. An Item should not know which Store or Factory it is going to belong to.
I also didn't understand the purpose of the attribute, number in Store. An Item shouldn't know how many numbers of it is present in a Store or Factory. If you keep it for any reason, it should be of a numeric type (e.g. int, double etc.) so that you can perform arithmetic operations on it.
Instead of a LinkedList of Item objects in Factory, you should have a variable of type, Map<String, Integer> and you can call it stock. The key in this Map is the unique identifier of the item, which is the combination code and name as per your requirement and the value will be the available number/quantity of the Item. Given below is a minimal verifiable example of how you can maintain stock:
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
class Item {
String name;
String code;
public Item(String name, String code) {
this.name = name;
this.code = code;
}
public String getName() {
return name;
}
public String getCode() {
return code;
}
#Override
public String toString() {
return "Name: " + name + "Code :" + code;
}
}
class Factory {
private Map<String, Integer> stock = new HashMap<String, Integer>();
private String name;
public Factory(String name) {
this.name = name;
}
public void addItem(Item item) {
if (item != null) {
String key = item.getName() + ":" + item.getCode();
stock.put(key, stock.getOrDefault(key, 0) + 1);
}
}
public void showStock() {
for (Entry<String, Integer> entry : stock.entrySet()) {
System.out.println("Item = " + entry.getKey() + ", Available quantity = " + entry.getValue());
}
}
}
public class Main {
public static void main(String[] args) {
Factory factory = new Factory("MayFlower");
factory.addItem(new Item("GTA", "001A"));
factory.addItem(new Item("GTA", "001A"));
factory.addItem(new Item("GTA", "002A"));
factory.addItem(new Item("GTA", "003A"));
factory.addItem(new Item("GTA", "003A"));
factory.addItem(new Item("GTA", "003A"));
factory.showStock();
}
}
Output:
Item = GTA:002A, Available quantity = 1
Item = GTA:003A, Available quantity = 3
Item = GTA:001A, Available quantity = 2
I have a class called "Sprache" and need a attribute "getSprache", who is a get methode. I want to display all "getSprache" to a Jcombobox. I actually have a DefaultComboboxModel.
How can I do it?
Do I need a list?
How looks a loop for the model?
public class Sprache {
private int id;
private String sprache;
private String kuerzel;
public int getId() {
return id;
}
public String getSprache() {
return sprache;
}
public String getKuerzel() {
return kuerzel;
}
private void setId(int id) {
this.id = id;
}
private void setSprache(String sprache) {
this.sprache = sprache;
}
private void setKuerzel(String kuerzel) {
this.kuerzel = kuerzel;
}
#Override
public String toString() {
return "Sprache [id=" + id + ", sprache=" + sprache + ", kuerzel=" + kuerzel + "]";
}
}
If your class Sprache contains one "Sprache" (language), then you can iterate through all of them and call #getSprache() on each and store the return value in an String array:
// Instantiate Classes
Sprache sprache1 = new Sprache();
sprache1.setId(0);
sprache1.setKuerzel("EN");
sprache1.setSprache("English");
Sprache sprache2 = new Sprache();
sprache2.setId(1);
sprache2.setKuerzel("DE");
sprache2.setSprache("Deutsch");
List<Sprache> sprachen = new ArrayList<>(2);
sprachen.add(sprache1);
sprachen.add(sprache2);
// Create an array from the langues
String sprachenStringArray[] = {sprache1.getSprache(), sprache2.getSprache()};
// Alternative way
String sprachenStringArray[] = new String[sprachen.size()];
for (int i = 0; i < sprachen.size(); i++)
{
sprachenStringArray[i] = sprachen.get(i).getSprache();
}
// Create combo box model
DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>(sprachenStringArray);
How can I achieve a custom sorting to the content of field name:
first element: P followed by numbers [1-9]{2} always on first
followed by : P followed by numbers 0[0-9]
followed by : S
followed by numbers [1-9]{2}
and then the rest in normal order i1.getName().compareToIgnoreCase(i2.getName())
private static Comparator<Item> itemComperator = new Comparator<Item>() {
#Override
public int compare(Item i1, Item i2) {
if (i1.getName().matches("P[1-9]{2}") && i2.getName().matches("P0[0-9]"))
return -1;
else if (i1.getName().matches("S[1-9]{2}"))
return -1;
else
return i1.getName().compareToIgnoreCase(i2.getName());
}
};
#Test
public void sortItem() {
Item item01 = new Item(1, "R59");
Item item02 = new Item(2, "S48");
Item item03 = new Item(3, "P01");
Item item04 = new Item(4, "P25");
Item item05 = new Item(5, "R99");
List<Item> items = Arrays.asList(item01, item02, item03, item04, item05);
System.out.println("before sorting");
long seed = System.nanoTime();
Collections.shuffle(items, new Random(seed));
for (Item i : items) {
System.out.println(i.getId() + " " + i.getName());
}
System.out.println("after sorting");
Collections.sort(items, itemComperator);
for (Item i : items) {
System.out.println(i.getId() + " " + i.getName());
}
}
public class Item {
private int id;
private String name;
public Item(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
output expected:
after sorting
4 P25
3 P01
2 S48
1 R59
5 R99
I think that I would first map each of the inputs to a "kind" number, which is based upon the list of criteria above. For example:
int kind(String input) {
if (input.matches("P[1-9]{2}") {
return 0;
} else if (input.matches("P0[0-9]")) {
return 1;
} else if (input.matches("S.*")) {
return 2;
} else if (input.matches("[1-9]{2}")) {
return 3;
} else {
return 4;
}
}
This gives you a way to see if the two strings are of the same "kind"; if not, return the ordering based on the kind. If they are the same kind, just compare them using (case insensitive) lexicographic ordering (you don't specify, but I assume you want e.g. "P11" to come before "P22"):
public int compare(Item a, Item b) {
String nameA = a.getName();
String nameB = b.getName();
int kindA = kind(nameA);
int kindB = kind(nameB);
if (kindA != kindB) {
return Integer.compare(kindA, kindB);
} else {
return nameA.compareToIgnoreCase(nameB);
}
}