Violation of DRY principle in Java - java

I have three methods that filter an array of devices by a field.
public void filtrateByType(Device[] devices, String type) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
if (devices[i].getType() == null && type == null) {
continue;
} else if (devices[i].getType() == null) {
devices[i] = null;
continue;
}
if (!devices[i].getType().equals(type)) {
devices[i] = null;
}
}
}
The other methods are similar. The only difference is calling another getter of field on which filtering is applied. For example, there is a call to getModel() instead getType(). Does this violate the DRY principle and how can I change it such that it doesn't (without generics)?
P.S.
It's a homework and unfortunatelly we don't use generics yet. I also can't change the signature of methods. I have a clue that I can create inner class with one method that will call needed getter and return a value. So, I need to put all my checks inside this method, but I don't really understand how do it with my logic (especially with "continue").

You can create an interface DeviceValueExtractor that looks like this:
#FunctionalInterface
public interface DeviceValueExtractor {
Object extractValue(Device device);
}
Now rewrite your method to:
public void filterByType(Device[] devices, DeviceValueExtractor extractor, Object expect) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
Object actual = extractor.extractValue(devices[i]);
if (actual == null && expect== null) {
continue;
} else if (actual == null) {
devices[i] = null;
continue;
}
if (!Objects.equals(actual, expect)) {
devices[i] = null;
}
}
}
Usage:
filterByType(devices, Device::getType, "Hello");
Note: I used Object due to the requirement not to have generics - because the only method called is equals this is actually No Big Deal.
However for some more type safety, you can introduce generics (and do away with DeviceValueExtractor:
public static <T> void filterByType(Device[] devices, Function<Device, T> extractor, T expect) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
Object actual = extractor.apply(devices[i]);
if (actual == null && expect== null) {
continue;
} else if (actual == null) {
devices[i] = null;
continue;
}
if (!Objects.equals(actual, expect)) {
devices[i] = null;
}
}
}

Perhaps a some Java 8 magic would help here:
public void filtrateByType(Device[] devices, String type) {
filtrateBy(devices, Device::getType, type);
}
public void filtrateBy(Device[] devices, Function<? super Device, String> attributeGetter, String attribute) {
if (devices == null) {
return;
}
for (int i = 0; i < devices.length; i++) {
if (devices[i] == null) {
continue;
}
if (attributeGetter.apply(devices[i]) == null && attribute == null) {
continue;
} else if (attributeGetter.apply(devices[i]) == null) {
devices[i] = null;
continue;
}
if (!attributeGetter.apply(devices[i]).equals(attribute)) {
devices[i] = null;
}
}
}

This is simpler version. You can use raw types, but this would be more error prone.
public static <T> void filtrateByType(T[] objects, Function<T, String> function, String type) {
if (objects == null || type == null)
return;
for (int i = 0; i < objects.length; i++) {
if (objects[i] == null) continue;
String match = function.apply(objects[i]);
if (match == null || !match.equals(type))
objects[i] = null;
}
}
However, I suspect what you really want is to use the Stream API
Device[] filtered = Stream.of(devices)
.filter(d -> Objects.equals(d.getType(), type))
.toArray(Device[]::new);

Related

What could be shortest code for this -- is any possibility with switch Case?

The below code has many duplicate lines, looking for a short thing for this.
if(null!= commonShipmentSplInstr.getIsGiftOrder() && GIFT_ORDER_FLAG.equalsIgnoreCase(commonShipmentSplInstr.getIsGiftOrder())) {
printObj.setDOCUMENT(INVOICE_DOCUMENT_FOR_PROSHIP_GIFT_ORDER);
giftMessageLine1 = commonShipmentSplInstr.getGiftMessageLine1();
giftMessageLine2 = commonShipmentSplInstr.getGiftMessageLine2();
giftMessageLine3 = commonShipmentSplInstr.getGiftMessageLine3();
} else if(null!= commonShipmentSplInstr.getSplInstr6() && GIFT_ORDER_FLAG.equalsIgnoreCase(commonShipmentSplInstr.getSplInstr6())) {
printObj.setDOCUMENT(INVOICE_DOCUMENT_FOR_PROSHIP_GIFT_ORDER);
giftMessageLine1 = commonShipmentSplInstr.getGiftMessageLine1();
giftMessageLine2 = commonShipmentSplInstr.getGiftMessageLine2();
giftMessageLine3 = commonShipmentSplInstr.getGiftMessageLine3();
} else if (null != sellingChannel && InvoiceHelper.isZolaSellingChannel(sellingChannel)) {
printObj.setDOCUMENT(INVOICE_DOCUMENT_FOR_PROSHIP_ZOLA_ORDER);
} else {
printObj.setDOCUMENT(DOCUMENT_FOR_PRINT_INVOICE_LABEL_FOR_PROSHIP);
}
In the setDOCUMENT method, all are Constants.
Just combine the two first if clause into one, they seem to be doing exactly the same:
if(commonShipmentSplInstr != null && (GIFT_ORDER_FLAG.equalsIgnoreCase(commonShipmentSplInstr.getIsGiftOrder()) || GIFT_ORDER_FLAG.equalsIgnoreCase(commonShipmentSplInstr.getSplInstr6()))) {
printObj.setDOCUMENT(INVOICE_DOCUMENT_FOR_PROSHIP_GIFT_ORDER);
giftMessageLine1 = commonShipmentSplInstr.getGiftMessageLine1();
giftMessageLine2 = commonShipmentSplInstr.getGiftMessageLine2();
giftMessageLine3 = commonShipmentSplInstr.getGiftMessageLine3();
}
else if (null != sellingChannel && InvoiceHelper.isZolaSellingChannel(sellingChannel)) {
printObj.setDOCUMENT(INVOICE_DOCUMENT_FOR_PROSHIP_ZOLA_ORDER);
}
else {
printObj.setDOCUMENT(DOCUMENT_FOR_PRINT_INVOICE_LABEL_FOR_PROSHIP);
}

How to implement skiplist in java (adding values, checking for values)?

I want to write a method that allows me to insert a value to the list (generic implementation). Furthermore i want to check wether a value in already in the list or not. I just want to know wether this is how its supposed to be or not.
In order to check wether a value is already contained within the list:
public boolean contains(T value) {
boolean searchedValue;
if (head == null || baseListLength == 0) {
searchedValue= false;
} else {
IndexListEntry<T> blub= head;
while ((blub.next != null) && (blub.next.value.compareTo(value) <= 0)) {
value= blub.next;
}
searchedValue= baseList.contains(value, blub.pointer);
}
return searchedValue;
}
and to add any value to the list:
public boolean addValue(T value) {
BaseListEntry<T> offs= baseList.add(value);
if (indexListLength < indexMaxLength) {
if (head == null) {
head = new IndexListEntry<T>(value, null, offs);
} else {
IndexListEntry<T> temp= head;
while ((temp.next != null) && (temp.next.value.compareTo(value) < 0)) {
temp= temp.next;
}
if (temp.next == null) {
temp.next = new IndexListEntry<T>(value, null, offs);
} else {
temp.next = new IndexListEntry<T>(value, temp.next, offs);
}
}
indexListLength++;
} else {
IndexListEntry<T> currentIndex = head.next;
int intervalWidth = baseListLength / indexMaxLength;
int intervalAdj = baseListLength % indexMaxLength;
int indexPosition = 0;
for (int i = 1; i < indexMaxLength; i++) {
int rip= 0;
if (intervalAdj - i >= 0)
rip= 1;
indexPosition = indexPosition + intervalWidth + rip;
BaseListEntry<T> newIndexTarget = baseList.getBaseListEntry(indexPosition);
currentIndex.pointer = newIndexTarget;
currentIndex.value = newIndexTarget.value;
currentIndex = currentIndex.next;
}
}
return true;
}
Are there any other methods to accomplish that goal? is my code somewhat correct. I am doubting everything I code right now and I kinda need confirmation from someone who knows more than me about this.
This is of course not everything i got. there are more classes to it but these are not the problem at hand so i dont thnk i need to upload that code as well.

Comparison method violates its general contract and method compareTo

I have a class Contact with fields firstName, lastName and emails. I need to sort them using Collection.sort(...), but I got an exception:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
My compareTo method:
#Override
public int compareTo(Contact another) {
int compareFirstName = 0;
if (this.getFirstName() != null && another.getFirstName() != null) {
compareFirstName = this.getFirstName().compareToIgnoreCase(
another.getFirstName());
if (compareFirstName == 0) {
int compareLastName = 0;
if (this.getLastName() != null && another.getLastName() != null) {
compareLastName = this.getLastName().compareToIgnoreCase(
another.getLastName());
if (compareLastName == 0) {
int compareEmail = 0;
if (this.getEmails() != null
&& another.getEmails() != null) {
compareEmail = this.getEmails()
.compareToIgnoreCase(another.getEmails());
return compareEmail;
} else {
return 0;
}
} else {
return compareLastName;
}
} else {
int compareEmail = 0;
if (this.getEmails() != null && another.getEmails() != null) {
compareEmail = this.getEmails().compareToIgnoreCase(
another.getEmails());
return compareEmail;
} else {
return 0;
}
}
} else {
return compareFirstName;
}
} else {
int compareLastName = 0;
if (this.getLastName() != null && another.getLastName() != null) {
compareLastName = this.getLastName().compareToIgnoreCase(
another.getLastName());
if (compareLastName == 0) {
int compareEmail = 0;
if (this.getEmails() != null && another.getEmails() != null) {
compareEmail = this.getEmails().compareToIgnoreCase(
another.getEmails());
return compareEmail;
} else {
return 0;
}
} else {
return compareLastName;
}
} else {
int compareEmail = 0;
if (this.getEmails() != null && another.getEmails() != null) {
compareEmail = this.getEmails().compareToIgnoreCase(
another.getEmails());
return compareEmail;
} else {
return 0;
}
}
}
}
Please help me to find error in my compareTo method. Thanks.
Your implementation does violate the contract.
Suppose you have 3 Contacts :
contact1 : First Name = "John", Last Name = "Doe", Email = "x#gmail.com"
contact2 : First Name = "John", Last Name = "Doe", Email = null
contact3 : First Name = "John", Last Name = null, Email = "y#gmail.com"
Based on your logic :
contact1.compareTo(contact2) returns 0 (since they have the same first and last name).
contact2.compareTo(contact3) also returns 0 (since you only compare by first name).
But contact1.compareTo(contact3) doesn't return 0 (since they have different emails).
compareTo must be transitive.
The way to fix this is not to ignore a property that is null only in one of the contacts you are comparing. For example, if this.getLastName()==null && another.getLastName() != null, return 1 (assuming you want to order the null last names after the non-null last names).

Is there any method to store conditional statement in java?

I wanted to know if there is any method to store if else condition in java? What I mean is like having a variable to represent the condition. This is my original code
private OnClickListener click2 = new OnClickListener() {
#Override
public void onClick(View v) {
tv1.setText("");
List<Integer> mClickedButtonIds = new ArrayList<Integer>();
int[] mDesiredOrder = new int[] { ans1.getId(), ans2.getId(), ans3.getId(),
ans4.getId(), ans5.getId() };
mClickedButtonIds.add(v.getId());
if (mClickedButtonIds.size() >= mDesiredOrder.length )
{
if (mClickedButtonIds.get(0) == mDesiredOrder[0]
&& mClickedButtonIds.get(1) == mDesiredOrder[1]
&& mClickedButtonIds.get(2) == mDesiredOrder[2]
&& mClickedButtonIds.get(3) == mDesiredOrder[3]
&& mClickedButtonIds.get(4) == mDesiredOrder[4]
)
{
tv1.setText("Correct!");
}
else
{
tv1.setText("Try Again!");
}
mClickedButtonIds.clear();
}
}
};
I plan to change it to something like this
private OnClickListener click2 = new OnClickListener() {
#Override
public void onClick(View v) {
tv1.setText("");
List<Integer> mClickedButtonIds = new ArrayList<Integer>();
int[] mDesiredOrder = new int[] { ans1.getId(), ans2.getId(), ans3.getId(),
ans4.getId(), ans5.getId(), ans6.getId() };
switch (main)
{
case 4 : Variable x = mClickedButtonIds.get(0) == mDesiredOrder[0]
&& mClickedButtonIds.get(1) == mDesiredOrder[1]
&& mClickedButtonIds.get(2) == mDesiredOrder[2]
&& mClickedButtonIds.get(3) == mDesiredOrder[3];
case 5 : Variable x = mClickedButtonIds.get(0) == mDesiredOrder[0]
&& mClickedButtonIds.get(1) == mDesiredOrder[1]
&& mClickedButtonIds.get(2) == mDesiredOrder[2]
&& mClickedButtonIds.get(3) == mDesiredOrder[3]
&& mClickedButtonIds.get(4) == mDesiredOrder[4];
case 6: Variable x = mClickedButtonIds.get(0) == mDesiredOrder[0]
&& mClickedButtonIds.get(1) == mDesiredOrder[1]
&& mClickedButtonIds.get(2) == mDesiredOrder[2]
&& mClickedButtonIds.get(3) == mDesiredOrder[3]
&& mClickedButtonIds.get(4) == mDesiredOrder[4]
&& mClickedButtonIds.get(5) == mDesiredOrder[5];
}
mClickedButtonIds.add(v.getId());
if (mClickedButtonIds.size() >= mDesiredOrder.length )
{
if (x)
{
tv1.setText("Correct!");
}
else
{
tv1.setText("Try Again!");
}
mClickedButtonIds.clear();
}
}
};
The Variable x is something which I would like to ask. Is there any method to do so or is there any variable that can store if else condition. Cause the original code, it is fixed to 5 clicks. Now I want the number of required clicks to change according to how many clicks the user want.
Based on the code snippet, consider a loop:
boolean result = true;
for (int i = 0; i < main; ++i) {
result = result && mClickedButtonIds.get(i) == mDesiredOrder[i];
if (!result)
break; // short-circuit out from loop if false
}
// now you can use "result" to test whether the condition matched all "main" ids
if (result) {
// correct
} else {
// bzzt, try again
}
If I understand correctly, that you want x to be a condition that you may change programatically (but which conforms to some structure) then you can do this using an interface Question and classes which implement that interface
public interface Question {
boolean getResponse(String condition1, int condition2);
}
public class StringIsLongCondition implements Question{
public boolean getResponse(String condition1, int condition2) {
return condition1.length()>condition2;
}
}
public class StringIsShortCondition implements Question{
public boolean getResponse(String condition1, int condition2) {
return condition1.length()<condition2;
}
}
Then use like
Question x;
//some code that selects the question
x= new StringIsShortCondition();
if(x.getResponse(someString, someInt){
//do something
}

JDOM SAXBuilder - assume CDATA for specific tags

I'm using org.jdom.input.SAXBuilder to parse an input stream (XML file) into a JDOM document.
SAXBuilder builder = new SAXBuilder(JavaScriptParser.class.getName());
org.jdom.Document document = builder.build(stream);
There are specific tags in my XML stream whose content within the tag must be treated as CDATA.
Example:
<text><![CDATA[ Any text... ]]></text>
<javascript><![CDATA[ function doSomething(){} ]]></javascript>
Currently the above examples will parse. What I have been trying to do for two days is try and extend the org.apache.xerces.impl.XMLScanner so the following examples will parse the same as above.
Example:
<text>Any text...</text>
<javascript>function doSomething(){}</javascript>
Below is what I currently have. scanCDATASection() is copied from the parent implementation with only the fEntityScanner.scanData("</javascript>", fStringBuffer) line changed to look for my end tag instead of the double closing brace. It's hard for me to identify what the issue is, but I believe EntityScanner.scanData("</javascript>") isn't working correctly because I never get into the "if" statement. Or the way I'm going about injecting a call to scanCDATASection() inside of scanContent() is causing issues. I have to imagine there is a cleaner and straight forward approach to accomplish this task. I have no experience customizing an XML Parser and every use of SAXParser in our application uses the default setup. Any suggestions/hints would be greatly appreciated.
public class JavaScriptScanner extends org.apache.xerces.impl.XMLNSDocumentScannerImpl
{
private final XMLStringBuffer fStringBuffer = new XMLStringBuffer();
public JavaScriptScanner()
{
super();
}
#Override
protected int scanContent() throws IOException, XNIException
{
if ("javascript".equals(fCurrentElement.rawname))
{
scanCDATASection();
setScannerState(SCANNER_STATE_CONTENT);
}
return super.scanContent();
}
protected boolean scanCDATASection() throws IOException, XNIException
{
// call handler
if (fDocumentHandler != null) {
fDocumentHandler.startCDATA(null);
}
while (true) {
fStringBuffer.clear();
if (!fEntityScanner.scanData("</javascript>", fStringBuffer) ||
fStringBuffer.toString().contains("</javascript")) {
if (fDocumentHandler != null && fStringBuffer.length > 0) {
fDocumentHandler.characters(fStringBuffer, null);
}
int brackets = 0;
while (fEntityScanner.skipChar(']')) {
brackets++;
}
if (fDocumentHandler != null && brackets > 0) {
fStringBuffer.clear();
if (brackets > XMLEntityManager.DEFAULT_BUFFER_SIZE) {
// Handle large sequences of ']'
int chunks = brackets / XMLEntityManager.DEFAULT_BUFFER_SIZE;
int remainder = brackets % XMLEntityManager.DEFAULT_BUFFER_SIZE;
for (int i = 0; i < XMLEntityManager.DEFAULT_BUFFER_SIZE; i++) {
fStringBuffer.append(']');
}
for (int i = 0; i < chunks; i++) {
fDocumentHandler.characters(fStringBuffer, null);
}
if (remainder != 0) {
fStringBuffer.length = remainder;
fDocumentHandler.characters(fStringBuffer, null);
}
}
else {
for (int i = 0; i < brackets; i++) {
fStringBuffer.append(']');
}
fDocumentHandler.characters(fStringBuffer, null);
}
}
if (fEntityScanner.skipChar('>')) {
break;
}
if (fDocumentHandler != null) {
fStringBuffer.clear();
fStringBuffer.append("]]");
fDocumentHandler.characters(fStringBuffer, null);
}
}
else {
if (fDocumentHandler != null) {
fDocumentHandler.characters(fStringBuffer, null);
}
int c = fEntityScanner.peekChar();
if (c != -1 && isInvalidLiteral(c)) {
if (XMLChar.isHighSurrogate(c)) {
fStringBuffer.clear();
scanSurrogates(fStringBuffer);
if (fDocumentHandler != null) {
fDocumentHandler.characters(fStringBuffer, null);
}
}
else {
reportFatalError("InvalidCharInCDSect",
new Object[]{Integer.toString(c,16)});
fEntityScanner.scanChar();
}
}
}
}
fMarkupDepth--;
// call handler
if (fDocumentHandler != null) {
fDocumentHandler.endCDATA(null);
}
return true;
}
}

Categories

Resources