In all the searching I did, I could not find an example of this sort. My bad :(
I have an Optional object containing an array. I now need to traverse the array and locate a particular element inside it.
Codes and sample classes as follows:
public class Component {
private String name;
public Component(String ipName) {
this.name = ipName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Container {
private Component[] componentArray;
public Container(Component[] ipComponentArray) {
this.componentArray = ipComponentArray;
}
public Component[] getComponentArray() {
return componentArray;
}
public void setComponentArray(Component[] componentArray) {
this.componentArray = componentArray;
}
}
public class TestClass {
public static void main(String[] args) {
Container newContainer = getNewContainer();
System.out.println(checkIfComponentIsPresent("Two", newContainer)); //prints true
System.out.println(checkIfComponentIsPresent("Five", newContainer)); //prints false
}
private static Container getNewContainer() {
return new Container(new Component[] {new Component("One"), new Component("Two"), new Component("Three")});
}
private static boolean checkIfComponentIsPresent(String ipName, Container newContainer) {
boolean isPresent = false;
Optional<Component[]> componentArrayOptional = Optional.ofNullable(newContainer).map(Container::getComponentArray);
if(componentArrayOptional.isPresent()) {
Component[] componentArray = componentArrayOptional.get();
if(componentArray != null && componentArray.length > 0) {
for(Component component : componentArray) {
if(ipName.equals(component.getName())) {
isPresent = true;
break;
}
}
}
}
return isPresent;
}
}
Can someone please advise me how can I improve the method checkIfComponentIsPresent? I want to know how can we traverse an array inside an Optional object, without converting it into a list or stream.
I can do it using streams as follows:
private static boolean checkIfComponentIsPresentUsingStreams(String ipName, Container newContainer) {
boolean isPresent = false;
Optional<Component[]> componentArrayOptional = Optional.ofNullable(newContainer).map(Container::getComponentArray);
if(componentArrayOptional.isPresent()) {
Stream<Component> componentArrayStream = Arrays.stream(componentArrayOptional.get());
isPresent = componentArrayStream.filter(component -> ipName.equals(component.getName())).findFirst().isPresent();
}
return isPresent;
}
But I cannot use streams, actually my classes are huge, and the array itself can contain numerous elements. Using streams, will degrade the performance.
Thanks!
You can operate with actual object value inside map method:
boolean isPresent = Optional.ofNullable(newContainer)
.map(Container::getComponentArray)
.map(arr -> {
for (Component component : arr) {
if (Objects.equals(component.getName(), ipName)) {
return true;
}
}
return false;
})
.orElse(false);
Actually I am sure what makes you think Stream would slow down your app significantly. And therefore there is another solution using streams:
boolean isPresent = Optional.ofNullable(newContainer)
.map(Container::getComponentArray)
.map(arr -> Stream.of(arr).anyMatch(component -> Objects.equals(ipName, component.getName())))
.orElse(false);
Related
I have a function that sets the value if and only the value given is contained in with the enum declared. I'm then trying to get the value via get Method but I'm getting the default value. The setter method is not getting the new value and updating it.
public enum BranchLocations {ONE,TWO,THREE,FOUR,FIVE};
private String BranchName ="Branch Name";
public boolean setBranchLocation(String branchLocation) {
for (BranchLocations b : BranchLocations.values()) {
if (b.name().equals(branchLocation)) {
this.BranchName = branchLocation;
return true;
}
}
return false;
}
public String getBranchLocation() {
return this.BranchName ;
}
I'm learning enum currently and not very familiar with it. I'm just checking if the value is contained in the enum by a for loop and .equals method
clarification - tester im running it against
public class Main {
public static void main(String[] args){
Bank bank = new Bank("LhblVEWZXmtjn3gMykBaqfN& &h", Bank.BranchLocations.values()[0]);
System.out.println(Bank.BranchLocations.values()[0]);
System.out.println(Bank.BranchLocations.values()[1].toString());
String newBranchLocation = Bank.BranchLocations.values()[1].toString();
System.out.println(bank.getBranchLocation());
bank.setBranchLocation(newBranchLocation);
System.out.println(bank.getBranchLocation());
System.out.println(
(bank.setBranchLocation(newBranchLocation) && bank.getBranchLocation().equals(newBranchLocation)));
}
}
public enum BranchLocations {
ONE("ONE"),
TWO("TWO"),
THREE("THREE"),
FOUR("FOUR"),
FIVE("FIVE");
private String BranchName = new String();
BranchLocations(String val){BranchName = val;}
public String getBranchLocation() {return BranchName;}
public boolean setBranchLocation(String branchLocation) {
for (BranchLocations b : BranchLocations.values()) {
if (b.name().equals(branchLocation)) {
this.BranchName = branchLocation;
return true;
}
}
return false;
}
}
In the enum, you have just declared the names, not the values. But, in your method, you are retrieving the values for the test. This is not the intended behaviour.
Do:
if (b.toString().equals(branchLocation)) {
this.BranchName = branchLocation;
return true;
}
or define a value for each one of the names in the Enum:
public enum BranchLocations {
ONE("ONE"),
TWO("TWO"),
THREE("THREE"),
FOUR("FOUR"),
FIVE("FIVE")
};
I try to compare different types with hamcrest. But I don't understand, how I have to build my own Matcher for the following problem:
String[] exp = new String[]{"x", "y", "z"};
DAO[] cur = getFromExternalWebservice();
Assert.assertThat("wrong strings", exp, Matchers.arrayContainingInAnyOrder(cur));
cur is an array of the following class:
class DAO {
public String id;
public String name;
}
The test above should actually compare the Strings within exp and the name property of the DAO objects within the array cur. I cannot change something on DAO (like adding a toString() method).
I can transform the results from the webservice into a names array, which I send to the Matcher like this:
String names[] = new String[cur.length];
for (int i = 0; i < cur.length; i++) {
names[i] = cur[i].name;
}
Assert.assertThat("wrong strings", exp, Matchers.arrayContainingInAnyOrder(names));
But this is ugly, how I can build a Matcher which compares the Strings without any copy of data?
I have implemented a first idea:
public class IsIn extends BaseMatcher<String> {
class DAOIterator implements Iterable<String>, Iterator<String> {
private final DAO[] collection;
private int idx;
public DAOIterator(DAO[] elements) {
this.collection = elements;
idx = 0;
}
#Override
public boolean hasNext() {
return (this.collection.length > this.idx);
}
#Override
public String next() {
return this.collection[this.idx++].name;
}
#Override
public Iterator<String> iterator() {
return new DAOIterator(this.collection);
}
}
private final DAO[] collection;
public IsIn(DAO[] elements) {
this.collection = elements;
}
#Override
public boolean matches(Object o) {
for (DAO d : this.collection) {
if (o == null ? d.name == null : o.equals(d.name)) {
return true;
}
}
return false;
}
#Override
public void describeTo(Description buffer) {
buffer.appendText("one of ");
buffer.appendValueList("{", ", ", "}", new DAOIterator(this.collection));
}
}
Call this on JUnit testcase:
String[] exp = new String[]{"x", "y", "z"};
DAO[] cur = getFromExternalWebservice();
Assert.assertThat("wrong strings", Arrays.asList(exp), Matchers.everyItem(new IsIn(cur)));
I am trying to understand the Memento Pattern. For that purpose i am trying to implement the undo function. The problem is that when ever i save the old state of the originator in the queue and run a different function the save state changes to the current state. I really need help to understand what i am doing wrong. How can i make the vector to be immutable.
This is the memento class.
package memento;
public class Memento
{
private final boolean[] vectorState;
public Memento(boolean[] vector) {vectorState = vector;}
boolean[] getMemento() { return vectorState;}
}
The Originator just need to shift a vector of boolean to the left.
(TRUE,FALSE,FALSE) shift left returns: (FALSE,FALSE,TRUE). This is the implementation.
package memento;
public class ShilftLeftOriginator
{
private boolean[] vector;
public ShilftLeftOriginator(boolean[] vector) {this.vector = vector;}
public void execute()
{
final boolean firstValue = this.vector[0];
for (int i = 1; i < this.vector.length; i++) {
this.vector[i - 1] = this.vector[i];
}
this.vector[vector.length - 1] = firstValue;
}
public Memento saveToMemento() {return new Memento(vector);}
}
And the caretaker:
package memento;
import java.util.Arrays;
import java.util.Deque;
import java.util.LinkedList;
public final class BooleanVector {
private boolean[] vector;
private Deque<Memento> mementoList = new LinkedList<>();
public BooleanVector(boolean[] inputValues) {
this.vector = inputValues;
}
#Override
public boolean equals(Object obj)
{
if (obj == null) return false;
if (!(obj instanceof BooleanVector)) return false;
BooleanVector otherVector = (BooleanVector) obj;
return Arrays.equals(this.vector, otherVector.vector);
}
public void shiftLeft()
{
ShilftLeftOriginator shiftLeft = new ShilftLeftOriginator(vector);
mementoList.add(shiftLeft.saveToMemento());
shiftLeft.execute(); // This is my Problem. After execute ist call the value(vector) in mementoList changes
}
public void undo(){ this.vector = mementoList.pop().getMemento();}
}
And now the test class and the error that i am receiving.
package memento;
public class Main {
public static void main(String[] args) {
boolean[] inputValues = { false, true, false };
BooleanVector vector = new BooleanVector(inputValues);
vector.shiftLeft();
boolean[] expectedValues = new boolean[] { true, false, false };
BooleanVector expectedVector = new BooleanVector(expectedValues);
if (!vector.equals(expectedVector)) {
throw new IllegalStateException(vector.toString());
} else {
System.out.println("shiftleft working");
}
vector.undo();
expectedValues = new boolean[] { false, true, false };
expectedVector = new BooleanVector(expectedValues);
if (!vector.equals(expectedVector)) {
throw new IllegalStateException(vector.toString());
} else {
System.out.println("undo working");
}
}
}
The console output:
shiftleft working
Exception in thread "main" java.lang.IllegalStateException: [true, false, false]
at memento.Main.main(Main.java:26)
The problem is that you're always manipulating the same array. So if you shift left, you also shift left the array you stored in the Memento object, because it's all the same array.
To solve it, make a copy of the array in the constructor of the Memento object:
public Memento(boolean[] vector) {
vectorState = Arrays.copyOf(vector, vector.length);
}
Aside from that, you seem to have your classes mixed up. BooleanVector and ShilftLeftOriginator are the originator, while Main is the caretaker.
I can give you a little bit more expandable solution:
class Originator: abstract implementatino of the value T holder
public abstract class Originator<T> {
private T value;
private final CareTaker<T> careTaker;
protected Originator(T value, CareTaker<T> careTaker) {
this.value = value;
this.careTaker = careTaker;
}
public final T getValue() {
return value;
}
protected final void setValue(T value) {
careTaker.add(this.value);
this.value = value;
}
public final void undo() {
if (!careTaker.isEmpty())
value = careTaker.remove();
}
}
class BooleanVector: concrete implementation that holds boolean[]
public final class BooleanVector extends Originator<boolean[]> {
public BooleanVector(boolean[] obj) {
super(obj, new CareTaker<>());
}
public void leftShift() {
if (getValue() == null || getValue().length == 0)
return;
boolean[] arr = new boolean[getValue().length];
boolean tmp = arr[0];
System.arraycopy(getValue(), 1, arr, 0, getValue().length - 1);
arr[arr.length - 1] = tmp;
setValue(arr);
}
}
class CareTaker: implementation of values change history - memento
public final class CareTaker<T> {
private final Deque<Item<T>> stack = new LinkedList<>();
public void add(T value) {
stack.push(new Item<>(value));
}
public T remove() {
return stack.pop().data;
}
public boolean isEmpty() {
return stack.isEmpty();
}
private static final class Item<T> {
private final T data;
public Item(T data) {
this.data = data;
}
}
}
Demo:
public static void main(String[] args) {
BooleanVector originator = new BooleanVector(new boolean[] { false, true, false });
System.out.println(Arrays.toString(originator.getValue()));
System.out.println("---");
originator.leftShift();
System.out.println(Arrays.toString(originator.getValue()));
originator.undo();
System.out.println(Arrays.toString(originator.getValue()));
}
Output:
[false, true, false]
---
[true, false, false]
[false, true, false]
import java.util.ArrayList;
public class list {
protected ArrayList<String> a = new ArrayList<String>();
public boolean ad(String aa)
{
boolean t=true;
a.add(aa);
for(String value : courses)
{
if(a.contains(value))
{
a=false;
}
else
{
a=true;
}
}
return a;
}
}
this program should return false if arraylist course contains duplicate elements.else if we are inserting new element return true.
expected output for above code is
true
but it only returns false for any condition.
You can simply utilize ArrayList#contains to verify if an element already exists within the List.
public boolean addCourse(String course) {
if (courses.contains(course)) {
return false;
}
return courses.add(course);
}
You are adding course in the list and then iterating thr the list, so it always gives you true. ArrayList allows duplicates.
if(courses.contains(value))
will always return true as you are adding the course before this in arraylist.
Suggestion: You should use Set than list if you want to avoid duplicates.
Instead of using ArrayList, how about using HashSet to keep your courses ?
http://beginnersbook.com/2013/12/hashset-class-in-java-with-example/
Try the code below:
import java.util.ArrayList;
public class list {
protected ArrayList<String> courses = new ArrayList<String>();
protected String temp = "";
public list(String str, String str2) {
}
public boolean addCourse(String course) {
boolean a = true;
if (courses.isEmpty()) {
courses.add(course);
temp = course;
} else {
if (temp.equalsIgnoreCase(course)) {
a = false;
temp = "";
} else {
a = true;
courses.add(course);
temp = course;
}
}
return a;
}
public static void main(String[] args) {
list inst = new list("John", "WIU");
System.out.println(inst.addCourse("CS560"));
System.out.println(inst.addCourse("CS500"));
}
}
Simple way you can do:
For Each time executing else block so. remove else block it will work.
for(String value : courses)
{
if(courses.contains(value))
{
a=false;
break;
}
a=true;
}
This is my VO
public class SomeVO {
private String name;
private String usageCount;
private String numberofReturns;
private String trendNumber;
private String nonTrendNumber;
private String trendType;
private String auditType;
public SomeVO(String name,String usageCount,String numberofReturns,String trendNumber,String nonTrendNumber,String trendType,String auditType){
this.name = name;
this.usageCount = usageCount;
this.numberofReturns = numberofReturns;
this.trendNumber = trendNumber;
this.nonTrendNumber = nonTrendNumber;
this.trendType = trendType;
this.auditType = auditType;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsageCount() {
return usageCount;
}
public void setUsageCount(String usageCount) {
this.usageCount = usageCount;
}
public String getNumberofReturns() {
return numberofReturns;
}
public void setNumberofReturns(String numberofReturns) {
this.numberofReturns = numberofReturns;
}
public String getTrendNumber() {
return trendNumber;
}
public void setTrendNumber(String trendNumber) {
this.trendNumber = trendNumber;
}
public String getNonTrendNumber() {
return nonTrendNumber;
}
public void setNonTrendNumber(String nonTrendNumber) {
this.nonTrendNumber = nonTrendNumber;
}
public String getTrendType() {
return trendType;
}
public void setTrendType(String trendType) {
this.trendType = trendType;
}
public String getAuditType() {
return auditType;
}
public void setAuditType(String auditType) {
this.auditType = auditType;
}
}
Here is my values
List<SomeVO> myList = new ArrayList<SomeVO>();
SomeVO some = new SomeVO("A","0","0","123","123","Trend","AuditX");
myList.add(some);
some = new SomeVO("B","1","1","234","234","Non trend","AuditX");
myList.add(some);
some = new SomeVO("C","0","2","345","345","Trend","AuditX");
myList.add(some);
some = new SomeVO("D","2","3","546","546","Trend","AuditX");
myList.add(some);
some = new SomeVO("E","2","4","678","678","Non trend","AuditX");
myList.add(some);
some = new SomeVO("F","0","0","123","123","Non trend","AuditA");
myList.add(some);
some = new SomeVO("G","0","0","123","123","Trend","AuditB");
myList.add(some);
Here is my comparator
public String currentAudit = "AuditX";
public class AuditComparator implements Comparator<SomeVO> {
#Override
public int compare(SomeVO o1, SomeVO o2) {
if(currentAudit.equalsIgnoreCase(o1.getAuditType()) && currentAudit.equalsIgnoreCase(o2.getAuditType())) {
int value1 = o2.getUsageCount().compareTo(o1.getUsageCount());
if (value1 == 0) {
int value2 = o1.getNumberofReturns().compareTo(o2.getNumberofReturns());
if(o1.getTrendType().equalsIgnoreCase("Trend") && o2.getTrendType().equalsIgnoreCase("Trend")) {
if (value2 == 0) {
return o1.getTrendNumber().compareTo(o2.getTrendNumber());
} else {
return value2;
}
} else {
if (value2 == 0) {
return o1.getNonTrendNumber().compareTo(o2.getNonTrendNumber());
} else {
return value2;
}
}
}
return value1;
} else {
return 1;
}
}
}
I am trying to sort the VO based on below conditions
First only set of values of currentAudit should be taken in to
consideration i.e., AuditX
a) then it should be sorted with
Usage count in descending order
b) if same usage count found then it
should be sorted with Return count in ascending order
c) if same
return count then it should check for trendType, if trendType
="Trend" then it should sort with Trend number otherwise nonTrend number.
then it should consider rest all auditType's and sorted with
a),b),c) condition as like currentAudit. I tried achieving it and i
ended up with only above comparator. Expected result: D, A, C, E,
F, G. But i get G,F,D,E,B,A,C. Please help me to update the
comparator above.
Your comparator does not meet a simple condition: it is not stateless. A following should always be true: A>B => B<A. In your case, in some scenarios A>B and B>A.
I resolved it by splitting the actual list in to 2 list based on AuditX and rest in another list. Then used below comparator one by one, and then merged in to a result list. Works good.
for(SomeVO some:myList) {
if(some.getAuditType().equalsIgnoreCase("AuditX")) {
auditX.add(some);
} else {
auditY.add(some);
}
}
Collections.sort(auditX, new AuditComparator());
Collections.sort(auditY, new AuditComparator());
public class AuditComparator implements Comparator<SomeVO> {
#Override
public int compare(SomeVO o1, SomeVO o2) {
int value1 = o2.getUsageCount().compareTo(o1.getUsageCount());
if (value1 == 0) {
int value2 = o1.getNumberofReturns().compareTo(o2.getNumberofReturns());
if (value2 == 0) {
return (o1.getTrendType().equalsIgnoreCase("Trend") && o2.getTrendType().equalsIgnoreCase("Trend")) ?
o1.getTrendNumber().compareTo(o2.getTrendNumber()):o1.getNonTrendNumber().compareTo(o2.getNonTrendNumber());
} else {
return value2;
}
}
return value1;
}
The return 1 at the bottom of the comparator makes a bug.
The comparator shall only return 1 if the second element is bigger than the first one, but if they're different, you always return 1, so the very first sorting criteria will be messy.
// a helper for case insensitive comparison
private int compareIgnoreCase(String o1,String o2) {
return o1.toLowercase.compareTo(o2.toLowercase());
}
#Override
public int compare(SomeVO o1, SomeVO o2) {
int result=compareIgnoreCase(o1.getAuditType(),o2.getAuditType());
if (result==0) {
// we need to go to the 2nd criteria
result=o2.getUsageCount().compareTo(o1.getUsageCount());
}
if (result==0) {
// ok, 1st and 2nd criteria was the same, go to the 3rd
result=o1.getNumberofReturns().compareTo(o2.getNumberofReturns());
}
if (result==0) {
// check trends
...
}
return result;
}
I found that this representation of multiple comparison criteria makes the code much easier to follow. We first do the highest priority of comparison, and go on with further comparions if the previous comparisons returned that the two elements are the same (i.e. result is still zero).
In case you need to make a descending sorting at some level, simply put a -, e.g.:
result=-o1.something.compareTo(o2.something)
It is a good idea to have only one exit point in a method (this also makes easier to follow what is happening).