Java check multiple string inside a list - java

My Java code look as below;
public List<Lookup> findAll(List<String> types, String lang) {
Query query = entityManager.createNamedQuery("Lookup.myQuery");
List<Lookup> result = new ArrayList<Lookup>();
for (String type : types) {
// check if isValidLookupTypeOrCode(type) && isValidLang(lang))
// if yes, do query.setParameter("lookupTypes", types) & query.setParameter("lang", lang);
// result = query.getResultList();
}
return result;
}
private boolean isValidLookupTypeOrCode(String s) {
String pattern = "^[a-zA-Z0-9\\_]*$";
if (s.matches(pattern)) {
return true;
}
return false;
}
private boolean isValidLang(String s) {
String pattern= "[a-zA-Z]{1,3}$";
if (s.matches(pattern)) {
return true;
}
return false;
}
Now how do I update the code inside my findAll() method, as I need to check if each of the string inside List types passes the regex (isValidLookupTypeOrCode) and the single string lang also passes the regex (isValidLang)
What is the best way to check for the 2 conditions ? since isValidLang() needs to be actually checked just once, but isValidLookupTypeOrCode() needs to be run on each string of the list ?

You can do:
public List<Lookup> findAll(List<String> types, String lang) {
List<Lookup> result = new ArrayList<Lookup>();
// validate lang parameter
if (isValidLang(lang)) {
// validate each of the type parameters from list
for (String type : types) {
if ( !isValidLookupTypeOrCode(type) )
return result;
}
// we are here, all good so run the query
Query query = entityManager.createNamedQuery("Lookup.myQuery");
query.setParameter("lookupTypes", types);
query.setParameter("lang", lang);
result = query.getResultList();
}
return result;
}

If you are able to use Java 8 then this is a good use case for streams:
if (isValidLang(lang)
&& types.stream().allMatch(MyClass::isValidLookupTypeOrCode)) {
...
}

Related

Java 8 Filtering Custom Class Properties

I've been going through SO pages all morning trying to figure out the best way to attack my question:
What is the most efficient way to sort through an ArrayList, match on a name in the ArrayList with a name I'm pulling from a WebElement. I'm not experienced with Java, and wondering if this context it makes more sense to use HashTables, but I couldn't find an easily understandable answer on how to use them with multiple values per index:
My custom class:
public class KnowledgePermission {
public String name;
public String htmlType;
public Boolean isAllowed;
public KnowledgePermission(String name, String htmlType, Boolean isAllowed) {
this.name = name;
this.htmlType = htmlType;
this.isAllowed = isAllowed;
}
public String getName() {
return name;
}
public String getHtmlType() {
return htmlType;
}
public Boolean getIsAllowed() {
return isAllowed;
}
#Override
public boolean equals(Object obj) {
boolean result = false;
if(obj instanceof KnowledgePermission) {
KnowledgePermission otherPermission = (KnowledgePermission) obj;
result = (this.name == otherPermission.name);
}
return result;
}
#Override
public int hashCode() {
int result = 17;
result = 31 * result + name.hashCode();
result = 31 * result + htmlType.hashCode();
result = 31 * result + isAllowed.hashCode();
return result;
}
}
I'm able to use Java 8, so I've looked at filters, haven't been successful yet.
Here's the snippet after I've created a list using my class type.
What I'm trying to do is get the XPath of some browser page items, get its name via Selenium's WebDriver API, and for the one item I know should match in my permission list, access one of the other two properties - htmlType or isAllowed - and continue logic based off of that.
List<KnowledgePermission> permissionList = new ArrayList<KnowledgePermission>();
permissionList.add(new KnowledgePermission("checkbox1sName", "checkbox", true ));
permissionList.add(new KnowledgePermission("checkbox2sName", "checkbox", true ));
List<WebElement> checkboxes = driver.findElements(By.xpath("//*someXpathinfoHere//input[#type='checkbox']"));
// check the value of each checkbox and display
for(WebElement item : checkboxes) {
String elname = item.getAttribute("name");
Boolean hasBeenSelected = item.isSelected();
// find the permission in the list
System.out.println("filtering permissions list");
List<KnowledgePermission> currentPermission = permissionList.stream().filter(permission -> elname.equals(permission)).collect(Collectors.toList());
System.out.println(currentPermission);
}
All that prints out for each iteration of the loop is:
filtering permissions list
[]
So I'm guessing I'm not understanding filtering correctly here.
Any help and I'd be grateful!!
.filter(permission -> elname.equals(permission.getName()))
... is all you have to change
If elname can be null, change the order to
.filter(permission -> permission.getName().equals(elname))
Since instance.equals(null) returns false, not NullPointerException

Cannot resolve method startsWith by using anyMatch

Can some one tell me please what is wrong here. My code is fine until I added this portion of code if (!tmp.isEmpty()) { return e.isEmpty(); }
The error is: Cannot resolve method startsWith(java.lang.String)
#Test
public void TestData() {
ArrayList<String> rootOpts = new ArrayList<String>();
rootOpts.add("aa");
rootOpts.add("bb");
rootOpts.add("ac");
ArrayList<String> allSiblings = new ArrayList<String>();
allSiblings.add("aa");
allSiblings.add("ac");
allSiblings.add("abc");
System.out.println("allMatch " + rootOpts.stream()
.map((e) -> {
System.out.println("e = " + e);
List<String> tmp = new ArrayList<String>();
tmp.addAll(allSiblings);
String[] CHs = {"ab","aa","ac"};
for (String chh : CHs) {
tmp.remove(chh);
}
if (!tmp.isEmpty()) {
return e.isEmpty();
}
return e;
})
.anyMatch(v -> v.startsWith("a")));
}
I am trying to rewrite the following code below(this code is contained in a method that is supposed to return a boolean value true or false):
for (Option e : rootOpts) {
List<String> tmp = new ArrayList<String>();
tmp.addAll(allSiblings);
if (e.getData() != null && !e.getData().getString().isEmpty()) {
String[] chs = {"ab","aa","ac"};
for (String ch : chs) {
tmp.remove(ch);
}
} else {
return false;
}
if (!tmp.isEmpty()) {
return false;
}
}
return true;
Thank you for your help guys
e.isEmpty() returns a boolean. In the following method anyMatch you want to invoke the method startsWith on this boolean but this method does not exist on boolean. So change your code to:
if (!tmp.isEmpty()) {
return ""; //or whatever string makes sense
}
e is of type String while e.isEmpty() is of type Boolean.
Therefore the return type of your function is Object.
Finally, Object does not have a startsWith function, contrary to the original String type that was returned which is why the compiler is complaining.
Look at the return type of isEmpty() - it's boolean. How are you planning to do startsWith on a boolean true/false? :) Stream predicts that it's possible to get boolean, and thus it cannot let you do startsWith on it.
if (!tmp.isEmpty()) {
return e.isEmpty();
}

Using 'contains' method in a class array

I have a class like this:
public static class TiposDeHistorial
{
String CODIGO, TIPO;
public TiposDeHistorial()
{
}
public String getCODIGO()
{
return CODIGO;
}
public void setCODIGO(String CODIGO)
{
this.CODIGO = CODIGO;
}
public String getTIPO()
{
return TIPO;
}
public void setTIPO(String TIPO)
{
this.TIPO = TIPO;
}
}
and a list of it:
ArrayList<TiposDeHistorial> tiposHistorial;
So my question is: can I use tiposHistorial.contains(...) to search in a specific array field, CODIGO or TIPO, for example?
First of, you do not have an array but an ArrayList.
The contains method on a List operates with the equals method of it's stored elements (TiposDeHistorial in your case). Therefore the answer to your question is no.
Trying something like tiposHistorial.contains("a") will not work as there is a type mismatch: your list is of type TiposDeHistorial while you try to check for an element of String.
If you are using Java 8 you can use following code:
tiposHistorial.stream()
.filter(x -> "specific value for CODIGO".equals(x.getCODIGO()))
.findFirst()
.orElse(null);
It will return TiposDeHistorial object in the list containing specific CODIGO value or null otherwise.
As for your question: "contains" method just returns "true" or "false", not an object. Moreover it uses "equals" method of your object, so it will not help if you want to search using fields.
Contains method will return true only if your object equals with ur list elements objects.
You can try extending equals method and have your own criteria which can work for either CODIGO or TIPO.
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
test other = (test) obj;
if (CODIGO == null) {
if (other.CODIGO != null)
return false;
} else if (!CODIGO.equals(other.CODIGO))
return false;
return true;
}
The answers already given here are all correct, just if You don't know java streams, and would like to check if the list contains both some CODIGO and TIPO fields, for me the simplest solution would be:
ArrayList<TiposDeHistorial> tiposHistorial = new ArrayList<>();
//add elements to the list
String tipo = "TIPO"; // the TIPO value You are looking for in the list
String codigo = "CODIGO"; // the CODIGO value You are looking for in the list
boolean containsTipo = false;
boolean containsCodigo = false;
for (TiposDeHistorial element: tiposHistorial) {
if (!containsTipo && element.getTIPO().equals(tipo)) {
containsTipo = true;
}
if (!containsCodigo && element.getCODIGO().equals(codigo) ){
containsCodigo = true;
}
if (containsTipo && containsCodigo)
break;
}
By editing it just a bit, You may also find which elements of the array contain the values You are looking for, if that will be Your intention

convert List<String> to Set in CASE INSENSITIVE Manner-Java 6

I have a list which contains Strings ABC:123,abc:123 ;when I am converting it to Set its giving me 2 different elements.Is there a one liner way to convert this List to Set ignoring the case so that my Set contains ABC:123 only.` But if the input List contains ABC:123a4,abc:1234A4 it should give me 2 different elements in the Set : ABC:123a4,ABC:1234A4
I know this can be done spliting the list elements on ":" first and converting the abc to all uppercase and adding them to new list and then the rest.But just wanted to know if there a better way (small lines of code) to do that.Thanks for any brain storming ideas in advance.
List<String> memlist = new ArrayList<String>(Arrays.asList(memberList.split(",")));
Set<String> memberSet = new HashSet<String>(memlist );
memlist = new ArrayList<String>(memberSet);
You can use a TreeSet with the String.CASE_INSENSITIVE_ORDER flag set.
String startingString = "ABC:123,abc:123";
List<String> caseSensitiveList = Arrays.asList(startingString.split(","));
Set<String> caseInsensitiveSet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
caseInsensitiveSet.addAll(caseSensitiveList);
for(String caseInsensitiveString : caseInsensitiveSet){
System.out.println(caseInsensitiveString);
}
This code, when run, gives me the output:
ABC:123
replace
memberList.split(",")
with
memberList.toUpperCase().split(",")
The cleanest solution is the one suggested by #SQLHacks. But then you said ABC:123a4 must be different from abc:1234A4. I guess the only solution now is to create a wrapper for the String objects and override the equals() and hashCode() method to do what you want, as #PaulBoddington suggested in his comment.
This is what I came up with (edited and improved based on #nafas answer):
public class StringWrapper {
private String value;
private String beforeColon;
private String afterColon;
private int hash;
public StringWrapper(String value) {
this.value = value;
String[] splitted = value.split(":");
beforeColon = splitted[0];
afterColon = splitted[1];
hash = Objects.hash(beforeColon.toUpperCase(), afterColon);
}
public String getValue() {
return value;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof StringWrapper) {
StringWrapper other = (StringWrapper) obj;
return beforeColon.equalsIgnoreCase(other.beforeColon) && afterColon.equals(other.afterColon);
}
return false;
}
#Override
public int hashCode() {
return hash;
}
#Override
public String toString() {
return value;
}
}
And then:
// this method is just to help you building a List<StringWrapper> from your String (memberList variable)
public static List<StringWrapper> split(String string, String regex) {
List<StringWrapper> list = new ArrayList<>();
for (String element : string.split(regex)) {
list.add(new StringWrapper(element));
}
return list;
}
public static void main(String[] args) {
String memberList = "ABC:123,abc:123,ABC:123a4,ABC:123A4";
List<StringWrapper> memlist = new ArrayList<>(split(memberList, ","));
Set<StringWrapper> memberSet = new HashSet<>(memlist);
memlist = new ArrayList<StringWrapper>(memberSet);
for (StringWrapper element : memlist) {
System.out.println(element);
}
}
If you run this, you get as output the following:
ABC:123a4
ABC:123A4
ABC:123
abc:123 is out but ABC:123a4 and ABC:123A4 are both present.
You can make things even easier changing the static split method to create the Set for you. The reason I didn't do that was to make things look familiar to you.
what is wrong with actually creating a little Model class to take care of all possible cases?
final class Model{
final String firstPart;
final String secondPart;
final int hashCode;
Model(String s){
String[] splitted=s.split(":");
firstPart=splitted[0];
secondPart=splitted[1];
hashCode=Objects.hash(firstPart.toLowerCase(),secondPart);
}
#Override
public boolean equals(Object o){
String[] splitted=o.toString().split(":");
return firstPart.equalsIgnoreCase(splitted[0]) && secondPard.equals(splitted[1]);
}
#Override
public int hashCode(){
return hashCode;
}
#Override
public String toString(){
return firstPart+":"+secondPart;
}
}
now create a set and etc:
Set<Model> set =new HashSet<Model>();
You can try this Java 8 one liner
Set<String> memberSet = memlist.stream().map(s -> s.toUpperCase()).collect(Collectors.toSet());
It will go through all strings in memlist convert them to uppercase and put them to a set.
That means of course that if your list contains "abc:123" but not "ABC:123", you will still get "ABC:123" in the set.

Simplifying a method design in java

Lets assume that I have a class with multiple String fields.
public class Person {
private String address;
private String first_name;
//etc
Now lets say that I have a List of Persons:
List<Person>
I want to write a method that can parse this list for a specific string value, e.g. address=="California".
The problem is that I have multiple fields in this class and it would be a lot of code reuse if I make a method for each field.
I could also do:
public List<Person> filter(List<Person> plist, String fieldToParse, String value){
//simple loop that removes the Person.fieldToParse == Person.value values
}
But is there a simpler, less ugly way for me to do this?
You could take a look at the lambdaj library (https://code.google.com/p/lambdaj/) if your goal is to filter the Person objects by a property. See this question/answer, as well What is the best way to filter a Java Collection?
You can use any LAMBDA library or you can implement it by yourself. See my code:
public static List<Person> filter(List<Person> source, String fieldToParse, String value) {
// Field getter
Method fieldGetter = null;
try {
fieldGetter = Person.class.getMethod("get" + firstUpperCase(fieldToParse));
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("Invalid field name: " + fieldToParse);
}
// Filter
List<Person> list = new ArrayList<Person>();
for (Person person : source) {
try {
Object obj = fieldGetter.invoke(person);
//TODO: process NULL here
if (obj.equals(value)) {
list.add(person);
}
} catch (Exception e) {
}
}
return list;
}
public static String firstUpperCase(String str) {
if (str == null) {
return null;
}
if (str.isEmpty() == false) {
char[] chars = str.toCharArray();
chars[0] = Character.toUpperCase(chars[0]);
return new String(chars);
}
return str;
}
Sample uses:
filter ( source, "address", "abc");
filter ( source, "first_name", "july");
When you define a method like you suggested you lose the type safety (and some error detection in compile time).
This what will happen if someone will call this method with a filed string that does not exist?
To achieve this goal you can try to use Guava collections library.
There is a filter method in the Collection2 class that gets a predicate.
See http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Collections2.html.
You can provide a helper method that will create a predicate for a predefined set of fields if such filters will be common.

Categories

Resources