Should the toString() method be added? - java

This is the piece of code.
List<BDDObject> childlist = savingObject.getChildren("TherapyAreaReference");
if (childlist.size() > 1) {
for (int i = 0; i < childlist.size() - 1; i++) {
String newMedcondRefChild = ((String) childlist
.get(i)
.getValue( IDDConstants.IDD_THERAPY_AREA_REF_VALUE))
.toLowerCase()
.trim()
.concat(((String) childlist
.get(i)
.getValue(IDDConstants.IDD_THERAPY_AREA_REF_TYPE_NAME))
.toLowerCase().trim());
}
}
IDDConstants has public static final strings defined in it. As StringBuffer is more effective, how can it be incorporated for the concat operations?

I'm guessing that the intention is to generate a list of 'reports', one for each BDDObject record found. Based on that idea, your code should look more like this:
public List<String> getReport(List<BDDObject> records) {
List<String> reports = new ArrayList<String>(record.size());
for (BDDObject record:records) {
String newMedcondRefChild = String.valueOf(record.getValue( IDDConstants.IDD_THERAPY_AREA_REF_VALUE))
.toLowerCase()
.trim() + String.valueOf(record.getValue(IDDConstants.IDD_THERAPY_AREA_REF_TYPE_NAME)))
.toLowerCase().trim());
reports.add(newMedcondRefChild);
}
return reports;
}
Regarding the question on whether toString() would be helpful, the only place where I see it fitting, would be on the BDDObject itself. It would look something like this:
class BDDObject {
...
#Override
public String toString() {
return String.valueOf(getValue(IDDConstants.IDD_THERAPY_AREA_REF_VALUE)).toLowerCase().trim() +
String.valueOf(getValue(IDDConstants.IDD_THERAPY_AREA_REF_TYPE_NAME)).toLowerCase().trim());
}
In which case, the function to create the report becomes trivial:
public List<String> getReport(List<BDDObject> records) {
List<String> reports = new ArrayList<String>(record.size());
for (BDDObject record:records) {
reports.add(record.toString());
}
return reports;
}
In case that what you want is a looooong string with all the values concatenated to it, you can use StringBuilder, like this:
public String getReport(List<BDDObject> records) {
StringBuilder sb = new StringBuilder();
for (BDDObject record:records) {
sb.append(String.valueOf(record.getValue( IDDConstants.IDD_THERAPY_AREA_REF_VALUE))
.toLowerCase()
.trim());
sb.append(String.valueOf(record.getValue(IDDConstants.IDD_THERAPY_AREA_REF_TYPE_NAME))
.toLowerCase().trim()));
}
return sb.toString();
}
This will return all the records appended after each other. I doubt its readability, but you I hope you get the idea. StringBuilder is helpful when you need to build a string iteratively (like in the previous example). StringBuilder should not be used to replace single String operations like : String a = b.get() + c.get(); given that the compiler implicitly creates a StringBuilder in these cases and therefore there's no actual performance improvement to be achieved.

In the code in your question, StringBuffer/StringBuilder will not give you any performance gains, because you concatenate only two strings. However, the question does not state what you are doing with the string in newMedconfRefChild. If your actual goal is to concatenate the strings of each loop iteration, then you should use a StringBuilder (use StringBuffer only when it is really necessary, prefer StringBuilder).

Related

String concatenation - Boolean hard-coded Vs Boolean Concatenation with String

I need a advice (both in java & .net) for the following piece of code.
public void method(bool value)
{
String someString;
//some code
if (value)
{
//some code
...
someString = "one" + value;
}
else
{
//some code
...
someString = "two" + value;
}
}
Which one is advisable and why? either code like above or code like
someString = "onetrue";
someString = "twofalse";
After compilation and optimization by JDK, method will look like:
public static String method(boolean value) {
String someString;
if (value) {
StringBuilder sb = new StringBuilder();
sb.append("one");
sb.append(value);
someString = sb.toString();
} else {
StringBuilder sb = new StringBuilder();
sb.append("two");
sb.append(value);
someString = sb.toString();
}
return someString;
}
If this code is invoked very frequently, it could bring a performance impact, compared to the second version. In each case a new StringBuilder is constructed and three methods are invoked on it. And boolean should be converted to an object before calling append. While in the second version we just return constant. Everything depends on how often this code is called.
Neither will make any difference it's purely style.
Since you have // some other code I'd just stick with the first. If you only had one line in each branch then either is ok.
At a high level they both are the same but if you look down at lower levels, I would advise to using the method:
someString = "onetrue";
someString = "twofalse";
This is because when you do "one" + value, the value is actually a bool and the toString() method of the bool object will be called to add to the string. Basically just adding another step opposed to just specifying what to add to the string.

Option to ignore case with .contains method?

Is there an option to ignore case with .contains() method?
I have an ArrayList of DVD object. Each DVD object has a few elements, one of them is a title. And I have a method that searches for a specific title. It works, but I'd like it to be case insensitive.
If you're using Java 8
List<String> list = new ArrayList<>();
boolean containsSearchStr = list.stream().anyMatch("search_value"::equalsIgnoreCase);
I'm guessing you mean ignoring case when searching in a string?
I don't know any, but you could try to convert the string to search into either to lower or to upper case, then search.
// s is the String to search into, and seq the sequence you are searching for.
bool doesContain = s.toLowerCase().contains(seq);
Edit:
As Ryan Schipper suggested, you can also (and probably would be better off) do seq.toLowerCase(), depending on your situation.
private boolean containsIgnoreCase(List<String> list, String soughtFor) {
for (String current : list) {
if (current.equalsIgnoreCase(soughtFor)) {
return true;
}
}
return false;
}
In Java 8 you can use the Stream interface:
return dvdList.stream().anyMatch(d -> d.getTitle().equalsIgnoreCase("SomeTitle"));
I know I'm a little late to the party but in Kotlin you can easily use:
fun Collection<String>.containsIgnoreCase(item: String) = any {
it.equals(item, ignoreCase = true)
}
val list = listOf("Banana")
println(list.contains("banana"))
println(list.containsIgnoreCase("BaNaNa"))
You can replace contains() for equalsIgnoreCase using stream() as below
List<String> names = List.of("One","tWo", "ThrEe", "foUR", "five", "Six", "THREE");
boolean contains = names.stream().anyMatch(i -> i.equalsIgnoreCase("three"))
This probably isn't the best way for your particular problem, but you can use the String.matches(String regex) method or the matcher equivalent. We just need to construct a regular expression from your prospective title. Here it gets complex.
List<DVD> matchingDvds(String titleFragment) {
String escapedFragment = Pattern.quote(titleFragment);
// The pattern may have contained an asterisk, dollar sign, etc.
// For example, M*A*S*H, directed by Robert Altman.
Pattern pat = Pattern.compile(escapedFragment, Pattern.CASE_INSENSITIVE);
List<DVD> foundDvds = new ArrayList<>();
for (DVD dvd: catalog) {
Matcher m = pat.matcher(dvd.getTitle());
if (m.find()) {
foundDvds.add(dvd);
}
}
return foundDvds;
}
But this is inefficient, and it's being done purely in Java. You would do better to try one of these techniques:
Learn the Collator and CollationKey classes.
If you have no choice but to stay in the Java world, add a method to DVD, boolean matches(String fragment). Have the DVD tell you what it matches.
Use a database. If it supports case-insensitive collations, declare the title column of the DVD table that way. Use JDBC or Hibernate or JPA or Spring Data, whichever you choose.
If the database supports advanced text search, like Oracle, use that.
Back in the Java world, use Apache Lucene and possibly Apache Solr.
Use a language tuned for case-insensitive matches.
If you can wait until Java 8, use lambda expressions. You can avoid the Pattern and Matcher class that I used above by building the regex this way:
String escapedFragment = Pattern.quote(titleFragment);
String fragmentAnywhereInString = ".*" + escapedFragment + ".*";
String caseInsensitiveFragment = "(?i)" + fragmentAnywhereInString;
// and in the loop, use:
if(dvd.getTitle().matches(caseInsensitiveFragment)) {
foundDvds.add(dvd);
}
But this compiles the pattern too many times. What about lower-casing everything?
if (dvd.getTitle().toLowerCase().contains(titleFragment.toLowerCase()))
Congratulations; you've just discovered the Turkish problem. Unless you state the locale in toLowerCase, Java finds the current locale. And the lower-casing is slow because it has to take into account the Turkish dotless i and dotted I. At least you have no patterns and no matchers.
You can't guarantee that you're always going to get String objects back, or that the object you're working with in the List implements a way to ignore case.
If you do want to compare Strings in a collection to something independent of case, you'd want to iterate over the collection and compare them without case.
String word = "Some word";
List<String> aList = new ArrayList<>(); // presume that the list is populated
for(String item : aList) {
if(word.equalsIgnoreCase(item)) {
// operation upon successful match
}
}
Kotlin Devs, go with any / none
private fun compareCategory(
categories: List<String>?,
category: String
) = categories?.any { it.equals(category, true) } ?: false
The intuitive solution to transform both operands to lower case (or upper case) has the effect of instantiating an extra String object for each item which is not efficient for large collections. Also, regular expressions are an order of magnitude slower than simple characters comparison.
String.regionMatches() allows to compare two String regions in a case-insensitive way. Using it, it's possible to write an efficient version of a case-insensitive "contains" method. The following method is what I use; it's based on code from Apache commons-lang:
public static boolean containsIgnoreCase(final String str, final String searchStr) {
if (str == null || searchStr == null) {
return false;
}
final int len = searchStr.length();
final int max = str.length() - len;
for (int i = 0; i <= max; i++) {
if (str.regionMatches(true, i, searchStr, 0, len)) {
return true;
}
}
return false;
}
It's very simple using the power of Kotlin's extension function, this answer may help Java and Kotlin developers.
inline fun List<String>.contains(text: String, ignoreCase: Boolean = false) = this.any { it.equals(text, ignoreCase) }
// Usage
list.contains("text", ignoreCase = true)
With a null check on the dvdList and your searchString
if (!StringUtils.isEmpty(searchString)) {
return Optional.ofNullable(dvdList)
.map(Collection::stream)
.orElse(Stream.empty())
.anyMatch(dvd >searchString.equalsIgnoreCase(dvd.getTitle()));
}
private List<String> FindString(String stringToLookFor, List<String> arrayToSearchIn)
{
List<String> ReceptacleOfWordsFound = new ArrayList<String>();
if(!arrayToSearchIn.isEmpty())
{
for(String lCurrentString : arrayToSearchIn)
{
if(lCurrentString.toUpperCase().contains(stringToLookFor.toUpperCase())
ReceptacleOfWordsFound.add(lCurrentString);
}
}
return ReceptacleOfWordsFound;
}
For Java 8, You can have one more solution like below
List<String> list = new ArrayList<>();
String searchTerm = "dvd";
if(String.join(",", list).toLowerCase().contains(searchTerm)) {
System.out.println("Element Present!");
}
If you are looking for contains & not equals then i would propose below solution.
Only drawback is if your searchItem in below solution is "DE" then also it would match
List<String> list = new ArrayList<>();
public static final String[] LIST_OF_ELEMENTS = { "ABC", "DEF","GHI" };
String searchItem= "def";
if(String.join(",", LIST_OF_ELEMENTS).contains(searchItem.toUpperCase())) {
System.out.println("found element");
break;
}
For Java 8+, I recommend to use following library method.
org.apache.commons.lang3.StringUtils
list.stream()
.filter(text -> StringUtils.containsIgnoreCase(text, textToSearch))
public List<DdsSpreadCoreBean> filteredByGroupName(DdsSpreadCoreBean ddsSpreadFilterBean, List<DdsSpreadCoreBean> spreadHeaderList){
List<DdsSpreadCoreBean> filteredByGroupName = new ArrayList<>();
filteredByGroupName = spreadHeaderList.stream().
filter(s->s.getGroupName()
.toLowerCase
.contains(ddsSpreadFilterBean.getGroupName())).collect(Collectors.toList());
return filteredByGroupName;
}
Option to ignore case with .contains method?
Check the below example
boolean contains = employeeTypes.stream().anyMatch(i -> i.equalsIgnoreCase(employeeType));
I added Custom Annotation for validation in my project
#Target({ElementType.FIELD, ElementType.PARAMETER})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Constraint(validatedBy = EmployeeTypeValidator.class)
public #interface ValidateEmployeeType {
public String message() default "Invalid employeeType: It should be either Permanent or Vendor";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
Validation of EmployeeType
public class EmployeeTypeValidator implements ConstraintValidator<ValidateEmployeeType, String> {
#Override
public boolean isValid(String employeeType, ConstraintValidatorContext constraintValidatorContext) {
List<String> employeeTypes = Arrays.asList("Permanent", "vendor", "contractual");
boolean contains = employeeTypes.stream().anyMatch(i -> i.equalsIgnoreCase(employeeType));
return contains;
}
}
Entity of Employee
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Employee {
private int empId;
#NotBlank(message = "firstName shouldn't be null or empty")
private String firstName;
#NotBlank(message = "lastName shouldn't be null or empty")
private String lastName;
#Past(message = "start shouldn't be before current date")
#JsonFormat(pattern = "dd-MM-yyyy")
private Date doj;
#NotNull(message = "department shouldn't be null")
#NotEmpty(message = "department shouldn't be empty")
private String dept;
#Email(message = "invalid email id")
private String email;
#ValidateEmployeeType
private String employeeType;
}
For Validation, We need Dependency in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
Note: SNAPSHOT, M1, M2, M3, and M4 releases typically WORK IN PROGRESS. The Spring team is still working on them, Recommend NOT using them.
You can apply little trick over this.
Change all the string to same case: either upper or lower case
For C# Code:
List searchResults = sl.FindAll(s => s.ToUpper().Contains(seachKeyword.ToUpper()));
For Java Code:
import java.util.*;
class Test
{
public static void main(String[] args)
{
String itemCheck="check";
ArrayList<String> listItem =new ArrayList<String>();
listItem.add("Check");
listItem.add("check");
listItem.add("CHeck");
listItem.add("Make");
listItem.add("CHecK");
for(String item :listItem)
{
if(item.toUpperCase().equals(itemCheck.toUpperCase()))
{
System.out.println(item);
}
}
}
}

Is there a way to replace all occurrences of a string in a variable of a list?

I have a list as follows
List<Summary> summary;
Summary {
int key;
String value1;
String value2;
}
Is there a way in java (or any other utility library) to replace all occurrences of a String "String1" in the variable value1 without having to loop through the list?
Looping the list is inevitable so you or some third party library has to do the looping. Is it really that hard to do:
for (Summary s : summary)
if (s.value1.equals("String1"))
s.value1 = "...";
? :)
Maybe you could use a library that allow you use it without loops, the problem is that in the low level the compiler must use something like a loop for do it.
I think that direct or indirectly you will use a loop.
So, for this reason you havenĀ“t any problem if use a loop in your code.
Sorry for my English, I hope you can understand all.
You can add a method to find by the object part:
public class ListOfString {
public static void main(String[] args) {
List<Model> models = new ArrayList<>();
for(int i = 0 ; i < 5; i++) {
Model model = new Model();
model.setStr("String"+i);
models.add(model);
}
Model temp = new Model();
temp.setStr("String1");
System.out.println(containsObjectPart(temp, models));
}
// This method just a prototype, you can modify as you like...
private static boolean containsObjectPart(Model obj, List<Model> models) {
for(Model model : models) {
if(model.getStr().equals(obj.getStr()))
return true;
}
return false;
}
}
class Model {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
}
No you cannot, Loop is invetible.But you can optimize it many area like, selecting loop, how do you find the string and replacing it .etc....
You could avoid a bit of looping - at the expense of losing your list ordering - by using a TreeSet, with value1 values as keys and the Summary objects as values. Then you can do a binary chop search to find all matching entries. A collection which uses hashing would have similar trade-offs and gains.
Otherwise, as everyone else has said, looping is inevitable. The only optimisation you could make is counting the entries as they go into the list so you know when you've found them all so you can stop looping.
But remember, premature optimisation is the root of all evil. :)

Ordering a string alphabetically - did I miss something obvious?

public class Anagram {
public static void main(String[] args) {
String a = "Despera tion-".toLowerCase();
String b = "A Rope Ends It".toLowerCase();
String aSorted = sortStringAlphabetically(a);
String bSorted = sortStringAlphabetically(b);
if(aSorted.equals(bSorted)){
System.out.println("Anagram Found!");
}else{
System.out.println("No anagram was found");
}
}
public static String sortStringAlphabetically(String s) {
char[] ca = s.toCharArray();
int cnt = 0;
ArrayList al = new ArrayList();
for (int i = 0; i < ca.length; i++) {
if (Character.isLetter(ca[cnt]))
al.add(ca[cnt]);
cnt++;
}
Collections.sort(al);
return al.toString();
}
}
As a learner, I hacked up this boolean Anagram checker. My chosen solution was to create a sortStringAlphabetically method seems to do just too much type-juggling String -> chars[] -> ArrayList ->String - given that I do just want to compare 2 strings to test whether one phrase is an anagram of another - could I have done it with less type-juggling?
ps The tutors solution was a mile away from my attempt, and probably much better for a lot of reasons - but I am really trying to get a handle on all the different Collection types.
http://www.home.hs-karlsruhe.de/~pach0003/informatik_1/aufgaben/en/doc/src-html/de/hska/java/exercises/arrays/Anagram.html#line.18
EDIT
FTW here is the original challenge, I realise I wandered away from the solution.
http://www.home.hs-karlsruhe.de/~pach0003/informatik_1/aufgaben/en/arrays.html
My initial kneejerk reaction was to simply work though array a, knocking out those chars which matched with array b - but that seemingly required me to rebuild the array at every iteration - Many thanks for all your efforts to educate me.
There are different ways to improve this, if you go with this algorithm.
First, you don't necessarily need to create a character array. You can use String.charAt() to access a specific character of your string.
Second, you don't need a list. If you used a SortedMultiSet or a SortedBag, you could just add things in sorted order. If you write a function that creates the SortedMultiSet from your string, you could just compare the sets without rebuilding the string.
Note: I don't know what libraries you're allowed to use (Google and Apache have these types), but you can always 'brew your own'.
Also, make sure to use generics for your types. Just defining ArrayLists is pretty risky, IMHO.
You could just sort the string without using a list:
public static String sortStringAlphabetically(String s) {
String lettersOnly = s.replaceAll("\\W", "");
char[] chars = lettersOnly.toCharArray();
Arrays.sort(chars);
return new String(chars);
}
N.B. I haven't actually tried running the code.
Your algorithm, but shorter (and yet, slower). The "type-juggling" is done "implicitly" in Java's various library classes:
public static boolean isAnagram(String a, String b) {
List<String> listA = new ArrayList<String>(Arrays.asList(
a.toLowerCase().replaceAll("\\W", "").split("")));
List<String> listB = new ArrayList<String>(Arrays.asList(
b.toLowerCase().replaceAll("\\W", "").split("")));
Collections.sort(listA);
Collections.sort(listB);
return listA.equals(listB);
}
Optionally, replace the \W regular expression to exclude those letters that you don't want to consider for the anagram
public class Anagram {
public static void main(String[] args) throws Exception {
String s1 = "Despera tion-";
String s2 = "A Rope Ends It";
anagramCheck(s1, s2);
}
private static void anagramCheck(String s1, String s2) {
if (isAnagram(s1, s2)) {
System.out.println("Anagram Found!");
} else {
System.out.println("No anagram was found");
}
}
private static boolean isAnagram(String s1, String s2) {
return sort(s1).equals(sort(s2));
}
private static String sort(String s) {
char[] array = s.replaceAll("\\W", "").toLowerCase().toCharArray();
Arrays.sort(array);
return new String(array);
}
}

Java: StringBuffer & Concatenation

I'm using StringBuffer in Java to concat strings together, like so:
StringBuffer str = new StringBuffer();
str.append("string value");
I would like to know if there's a method (although I didn't find anything from a quick glance at the documentation) or some other way to add "padding".
Let me explain; every time I append something to the string, I want to add a space in the end, like so:
String foo = "string value";
str.append(foo + " ");
and I have several calls to append.. and every time, I want to add a space. Is there a way to set the object so that it will add a space automatically after each append?
EDIT --
String input
StringBuffer query = new StringBuffer();
Scanner scanner = new Scanner(System.in);
scanner.UseDelimiter("\n");
do {
System.out.println("sql> ");
input = scanner.next();
if (!empty(input)) query.append(input);
if (query.toString().trim().endsWith(";")) {
//run query
}
}
while (!input.equalsIgnoreCase("exit");
I'll use StringBuilder though as grom suggested, but that's how the code looks right now
I think this is handled easier either with a helper method (untested code):
public String myMethod() {
StringBuilder sb = new StringBuilder();
addToBuffer(sb, "Hello").addToBuffer("there,");
addToBuffer(sb, "it").addToBuffer(sb, "works");
}
private StringBuilder addToBuffer(StringBuilder sb, String what) {
return sb.append(what).append(' '); // char is even faster here! ;)
}
Or even using a Builder pattern with a fluent interface (also untested code):
public String myMethod() {
SBBuilder builder = new SBBuilder()
.add("Hello").add("there")
.add("it", "works", "just", "fine!");
for (int i = 0; i < 10; i++) {
builder.add("adding").add(String.valueOf(i));
}
System.out.println(builder.build());
}
public static class SBBuilder {
private StringBuilder sb = new StringBuilder();
public SBBuilder add(String... parts) {
for (String p : parts) {
sb.append(p).append(' '); // char is even faster here! ;)
}
return this;
}
public String build() {
return sb.toString();
}
}
Here's an article on the subject.
Hope it helps! :)
You should be using StringBuilder.
Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.
StringBuffer is final. You cannot derive from it.
The Best solution really is to add the padding for yourself. Write a method for it and use a PADDING-Constant so that you can easily change it, or better put it in a parameter.
Can you not create a new class which wraps around StringBuffer and add an appendWithTrailingSpace() method?
CustomStringBuffer str = new CustomStringBuffer();
str.appendWithTrailingSpace("string value");
(Although you may want to call your method something a little shorter.)
Just add the space yourself, it's easy enough, as per your own example.
Another possibility is that StringBuilder objects return themselves when you call append, meaning you can do:
str.append("string value").append(" ");
Not quite as slick, but it is probably an easier solution than the + " " method.
Another possibility is to build a wrapper class, like PaddedStringBuilder, that provides the same methods but applies the padding you want, since you can't inherit.

Categories

Resources