Covariance in Java - java

Why does the following not work in Java? It would work in C#:
public static final List<String> Split(String str, char delimiter)
{
if ((str == null) || "".equals(str))
{
return new CopyOnWriteArrayList<String>();
}
}
I get an error saying this method has to return List. CopyOnWriteArrayList implements the List interface. Why does covariance not apply on return values in Java?

It looks like you've forgotten to return a List<String> for the else branch.

You either have a else branch explicitly and return whatever you want to return (null maybe ?). Or have a return statement at the end of the method. You program will not compile if you do not have either.

Apart from the correct answers above:
use lower case method names in Java (split instead of Split)
why return such a heavy object as CopyOnWriteArrayList when your string is empty? That's the kind of situation where you want to return Collections.emptyList(), where no new object is created unnecessarily (assuming you are not going to add values to the list afterwards)
Actually, I'd use apache commons lang and do it like this:
return Arrays.asList(
StringUtils.stripToEmpty(myString) // converts null into ""
// and strips extra whitespace
.split(
Pattern.quote(Character.toString(delimiter))
)
)
No if / else needed.

Related

How iterate over a List and check it against the Enum values with a Stream

I have a list and I want to find out if it contains any other elements than what I have in the enum.
I have this working:
boolean containsMyEnumCode(List<String> processCodes) {
if (null != processCodes) {
for (final String process : processCodes) {
if (!(Arrays.stream(MyEnumCode.values()).anyMatch((p) -> p.name().equals(process)))) {
return true;
}
}
}
return false;
}
This works, but how could I replace for loops with a stream, and have it in fewer lines?
Instead of null check, you can use Stream.ofNullable() (available from Java 9 onwards) which will create a stream with a single element (list of processors) or empty stream. Apply flatMap() to turn it to a stream of strings. And then apply anyMatch() as a terminal operation which will determine whether at least one process in the stream matches with the given predicate.
Note: that condition !Arrays.stream().anyMatch() means that none of elements in the stream should match the predicate passed to the anyMatch(). And that is the meaning of the operation noneMath(). A change of the terminal operation will make the condition more readable by eliminating the need in logical not in front of it Arrays.stream().noneMath().
Another improvement that is made to this code was inspired by suggestions from Holger and k314159.
Stream of enum constants Arrays.stream(MyEnumCode.values())... from the original code that is used in the condition discussed above has a performance overhead. Method values() creates an array of enum constants at every call. And it will be invoked for every element in the list. Therefore it makes sense to introduce a local variable that will store a Set of enum-names and check every element in the stream against this set.
Also as Holger pointed out null-friendly solution will disguise the problem. anyMatch() will return false in case of an empty stream and this result will be accepted as valid instead of raising NPE, and then this list can be stored somewhere and will cause problems in the future.
Since I'm providing two solutions here I've implemented one in such a way that it will raise an exception with a custom message, and another as being null-friendly by using Stream.ofNullable().
public static boolean containsNonEnumCode(List<String> processCodes) {
Set<String> names = getEnumNames(MyEnumCode.class);
return Stream.ofNullable(processCodes)
.flatMap(List::stream)
.anyMatch(process -> !names.contains(process));
}
Solution for Java 8 (requested by PO in the comment) implemented as null-hostile by using Objects.requireNonNull().
public static boolean containsNonEnumCode(List<String> processCodes) {
Set<String> names = getEnumNames(MyEnumCode.class);
return Objects.requireNonNull(processCodes, "processCodes list in null")
.stream()
.anyMatch(process -> !names.contains(process));
}
The method below expects the Class of an enum as a parameter and generates a Set of enum names.
public static <T extends Enum<T>> Set<String> getEnumNames(Class<T> enumClass) {
return EnumSet.allOf(enumClass).stream()
.map(T::name)
.collect(Collectors.toSet());
}
Starting with Optional.ofNullable on the collection passed through as a parameter you could do something like this:
Optional.ofNullable(processCodes).stream()
.flatMap(Collection::stream)
.anyMatch(code -> Arrays.stream(MyEnumCode.values()).anyMatch(v -> v.name().equals(code)));

My question is about addition of an array of different wrapper classes through java generics

public static void doProcess(){
Integer [] intArray = {2,5,3,8,9};
returnArray(intArray);
//Expected output: 27 (sum of all number)
String[] strArray = {"Jack", "Daniel", "Richel"};
returnArray(strArray);
//Expected output: Jack Daniel Richel
Character[] charArray = {'A', 'X', 'E'};
returnArray(charArray);
//Expected output: AXE
}
I have the above code and the method below which need to complete.
private static <E> *** returnArray(E[] value) {
for(E ele : value) {
//code for expected output
}
//return Expected output
}
I need to fill above method as well as fill the return type which is here shown as ***.
I can't use separate method or introduce any new method.
Just adding to #Lino's answer to suggest a more generic approach: I will assume you want to sum up numbers (be it integers, floats or whatever) and concat anything else (strings, chars, even random objects like Duration or Instant). It's just that characters will be squashed together, while strings (or anything else, for that matter) will be joined with a space separator.
You can return Object or something a bit narrower that fits both numbers and strings (like Serializable or Comparable<?>); this is hardly useful, but keeps you from returning really random stuff.
Alternatively, you can decide to always return String and just return the sum as a string as well (for numbers).
The actual implementation can look pretty neat if you use Java8 streams:
// the `E` generic type brings you nothing, as you can't make use of it at compile time,
// so you can simply drop it and go with a mere `Object[]` array, as per #Lino
public static <E> Serializable returnArray(E[] values) {
// exclude null values if any (note that `E` proves itself useless already):
final Stream<?> stream = Stream.of(values).filter(Objects::nonNull);
if (values instanceof Number[]) {
// you can use mapToDouble and doubleValue, for a more accurate sum
return stream.map(Number.class::cast).mapToInt(Number::intValue).sum();
} else {
// squash characters, but use a space separator for anything else
final String separator = (values instanceof Character[]) ? "" : " ";
return stream.map(Object::toString).collect(Collectors.joining(separator));
}
}
You may want to use the instanceof, e.g. you can have a construct like this:
public static <E> Object returnArray(E[] value) {
if(value instanceof String[]) {
String[] strings = (String[]) value;
// concat the strings with spaces
} else if(value instanceof Integer[]) {
Integer[] ints = (Integer[]) value;
// sum the integers
} else if(value instanceof Character[]) {
Character[] chars = (Character[]) value;
// concat the characters
} else {
// throw exception or handle more cases
}
}
I've deliberatly left out the real code for the different operations as this should just point you into the right direction, (and I won't do your work for you).
The only real tricky thing is the return type. As it can't be E. It works with Strings and Integers, but will break with Characters as 'ABC' is not a valid char and thus you can't return it.
Note: using generics and instanceof breaks the whole concept of generics. You can aswell just remove it and have a method like this:
public static Object returnArray(Object[] value) {

Java List.contains(Object with field value equal to x)

I want to check whether a List contains an object that has a field with a certain value. Now, I could use a loop to go through and check, but I was curious if there was anything more code efficient.
Something like;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
I know the above code doesn't do anything, it's just to demonstrate roughly what I am trying to achieve.
Also, just to clarify, the reason I don't want to use a simple loop is because this code will currently go inside a loop that is inside a loop which is inside a loop. For readability I don't want to keep adding loops to these loops. So I wondered if there were any simple(ish) alternatives.
Streams
If you are using Java 8, perhaps you could try something like this:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().filter(o -> o.getName().equals(name)).findFirst().isPresent();
}
Or alternatively, you could try something like this:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().map(MyObject::getName).filter(name::equals).findFirst().isPresent();
}
This method will return true if the List<MyObject> contains a MyObject with the name name. If you want to perform an operation on each of the MyObjects that getName().equals(name), then you could try something like this:
public void perform(final List<MyObject> list, final String name){
list.stream().filter(o -> o.getName().equals(name)).forEach(
o -> {
//...
}
);
}
Where o represents a MyObject instance.
Alternatively, as the comments suggest (Thanks MK10), you could use the Stream#anyMatch method:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().anyMatch(o -> name.equals(o.getName()));
}
You have two choices.
1. The first choice, which is preferable, is to override the `equals()` method in your Object class.
Let's say, for example, you have this Object class:
public class MyObject {
private String name;
private String location;
//getters and setters
}
Now let's say you only care about the MyObject's name, that it should be unique so if two `MyObject`s have the same name they should be considered equal. In that case, you would want to override the `equals()` method (and also the `hashcode()` method) so that it compares the names to determine equality.
Once you've done this, you can check to see if a Collection contains a MyObject with the name "foo" by like so:
MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);
However, this might not be an option for you if:
You are using both the name and location to check for equality, but you only want to check if a Collection has any `MyObject`s with a certain location. In this case, you've already overridden `equals()`.
`MyObject` is part of an API that you don't have liberty to change.
If either of these are the case, you'll want option 2:
2. Write your own utility method:
public static boolean containsLocation(Collection<MyObject> c, String location) {
for(MyObject o : c) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Alternatively, you could extend ArrayList (or some other collection) and then add your own method to it:
public boolean containsLocation(String location) {
for(MyObject o : this) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Unfortunately there's not a better way around it.
This is how to do it using Java 8+ :
boolean isJohnAlive = list.stream().anyMatch(o -> "John".equals(o.getName());
Google Guava
If you're using Guava, you can take a functional approach and do the following
FluentIterable.from(list).find(new Predicate<MyObject>() {
public boolean apply(MyObject input) {
return "John".equals(input.getName());
}
}).Any();
which looks a little verbose. However the predicate is an object and you can provide different variants for different searches. Note how the library itself separates the iteration of the collection and the function you wish to apply. You don't have to override equals() for a particular behaviour.
As noted below, the java.util.Stream framework built into Java 8 and later provides something similar.
Collection.contains() is implemented by calling equals() on each object until one returns true.
So one way to implement this is to override equals() but of course, you can only have one equals.
Frameworks like Guava therefore use predicates for this. With Iterables.find(list, predicate), you can search for arbitrary fields by putting the test into the predicate.
Other languages built on top of the VM have this built in. In Groovy, for example, you simply write:
def result = list.find{ it.name == 'John' }
Java 8 made all our lives easier, too:
List<Foo> result = list.stream()
.filter(it -> "John".equals(it.getName())
.collect(Collectors.toList());
If you care about things like this, I suggest the book "Beyond Java". It contains many examples for the numerous shortcomings of Java and how other languages do better.
Binary Search
You can use Collections.binarySearch to search an element in your list (assuming the list is sorted):
Collections.binarySearch(list, new YourObject("a1", "b",
"c"), new Comparator<YourObject>() {
#Override
public int compare(YourObject o1, YourObject o2) {
return o1.getName().compareTo(o2.getName());
}
});
which will return a negative number if the object is not present in the collection or else it will return the index of the object. With this you can search for objects with different searching strategies.
Map
You could create a Hashmap<String, Object> using one of the values as a key, and then seeing if yourHashMap.keySet().contains(yourValue) returns true.
Eclipse Collections
If you're using Eclipse Collections, you can use the anySatisfy() method. Either adapt your List in a ListAdapter or change your List into a ListIterable if possible.
ListIterable<MyObject> list = ...;
boolean result =
list.anySatisfy(myObject -> myObject.getName().equals("John"));
If you'll do operations like this frequently, it's better to extract a method which answers whether the type has the attribute.
public class MyObject
{
private final String name;
public MyObject(String name)
{
this.name = name;
}
public boolean named(String name)
{
return Objects.equals(this.name, name);
}
}
You can use the alternate form anySatisfyWith() together with a method reference.
boolean result = list.anySatisfyWith(MyObject::named, "John");
If you cannot change your List into a ListIterable, here's how you'd use ListAdapter.
boolean result =
ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");
Note: I am a committer for Eclipse ollections.
Predicate
If you dont use Java 8, or library which gives you more functionality for dealing with collections, you could implement something which can be more reusable than your solution.
interface Predicate<T>{
boolean contains(T item);
}
static class CollectionUtil{
public static <T> T find(final Collection<T> collection,final Predicate<T> predicate){
for (T item : collection){
if (predicate.contains(item)){
return item;
}
}
return null;
}
// and many more methods to deal with collection
}
i'm using something like that, i have predicate interface, and i'm passing it implementation to my util class.
What is advantage of doing this in my way? you have one method which deals with searching in any type collection. and you dont have to create separate methods if you want to search by different field. alll what you need to do is provide different predicate which can be destroyed as soon as it no longer usefull/
if you want to use it, all what you need to do is call method and define tyour predicate
CollectionUtil.find(list, new Predicate<MyObject>{
public boolean contains(T item){
return "John".equals(item.getName());
}
});
Here is a solution using Guava
private boolean checkUserListContainName(List<User> userList, final String targetName){
return FluentIterable.from(userList).anyMatch(new Predicate<User>() {
#Override
public boolean apply(#Nullable User input) {
return input.getName().equals(targetName);
}
});
}
contains method uses equals internally. So you need to override the equals method for your class as per your need.
Btw this does not look syntatically correct:
new Object().setName("John")
If you need to perform this List.contains(Object with field value equal to x) repeatedly, a simple and efficient workaround would be:
List<field obj type> fieldOfInterestValues = new ArrayList<field obj type>;
for(Object obj : List) {
fieldOfInterestValues.add(obj.getFieldOfInterest());
}
Then the List.contains(Object with field value equal to x) would be have the same result as fieldOfInterestValues.contains(x);
Despite JAVA 8 SDK there is a lot of collection tools libraries can help you to work with, for instance:
http://commons.apache.org/proper/commons-collections/
Predicate condition = new Predicate() {
boolean evaluate(Object obj) {
return ((Sample)obj).myField.equals("myVal");
}
};
List result = CollectionUtils.select( list, condition );

How to tell if an Array or List is also a set?

I have a char[]. I would like to be able to tell if it is a Set and if so create a new Set with the array values. I know I can use a try-catch block but is there any built in method for Java which I could use to test this without throwing an error. It is not imperative that I use a char[]. I could also use a List or something else.
I have a char[]. I would like to be able to tell if it is a Set
It won't be. It can't be. It may have distinct values, but it won't be a Set.
If you actually want to check whether the array contains distinct values, the simplest way would probably be to create a Set<Character> and check whether any add operation returns false:
public static boolean uniqueValues(char[] values) {
Set<Character> set = new HashSet<Character>();
for (char c : values) {
if (!set.add(c)) {
return false;
}
}
return true;
}
(That gives you an early out as soon as you find a duplicate, rather than continuing to construct the whole set.)
An alternative would be to create a boolean[] of size 65536 to see which characters you've got:
public static boolean uniqueValues(char[] values) {
boolean[] seen = new boolean[65536];
for (char c : values) {
int index = c;
if (seen[index]) {
return false;
}
seen[index] = true;
}
return true;
}
For small arrays, this will be hugely wasteful of memory - for larger arrays (of distinct elements, or where the duplicate occurs late) it's more space efficient than the HashSet approach.
You can test if a variable is from certain type using instanceof operator:
if (myVar instanceof Set) {
System.out.println("It's a Set.");
//do what you want/need
}
Still, the usage of instanceof operator seems to be a problem in your design. Even more, you must not use instanceof operator in an array to check if it is a Collection.
EDIT: Based on your last comment in your question, you want to seek if there's a duplicated element in your array. You can do this using the Set as explained in JonSkeet's answer (no need to rewrite the logic and explanation he already has provided).
If your thinking of using "generics" for types the system may have List for the type it can store to check for Set you can use "instanceof" test operator in a comparison.
List<Object[]> alist = new ArrayList<Object[]>();
//setup the list of arrays
if(alist.get(0) instanceof Set){
// do what you do with a set
}else{
// do what you require
}

Java using contains function to match string object ignore capital case?

I want that the contain function should return true even if the following are in capital letters
List<String> pformats= Arrays.asList("odt","ott","oth","odm","sxw","stw","sxg","doc","dot","xml","docx","docm","dotx","dotm","doc","wpd","wps","rtf","txt","csv","sdw","sgl","vor","uot","uof","jtd","jtt","hwp","602","pdb","psw","ods","ots","sxc","stc","xls","xlw","xlt","xlsx","xlsm","xltx","xltm","xlsb","wk1","wks","123","dif","sdc","vor","dbf","slk","uos","pxl","wb2","odp","odg","otp","sxi","sti","ppt","pps","pot","pptx","pptm","potx","potm","sda","sdd","sdp","vor","uop","cgm","bmp","dxf","emf","eps","met","pbm","pct","pcd","pcx","pgm","plt","ppm","psd","ras","sda","sdd","sgf","sgv","svm","tgs","tif","tiff","vor","wmf","xbm","xpm","jpg","jpeg","gif","png","pdf","log");
if(pformats.contains(extension)){
// do stuff
}
A Set is a better choice for a lookup.
private static final Set<String> P_FORMATS = new HashSet<String>(Arrays.asList(
"odt,ott,oth,odm,sxw,stw,sxg,doc,dot,xml,docx,docm,dotx,dotm,doc,wpd,wps,rtf,txt,csv,sdw,sgl,vor,uot,uof,jtd,jtt,hwp,602,pdb,psw,ods,ots,sxc,stc,xls,xlw,xlt,xlsx,xlsm,xltx,xltm,xlsb,wk1,wks,123,dif,sdc,vor,dbf,slk,uos,pxl,wb2,odp,odg,otp,sxi,sti,ppt,pps,pot,pptx,pptm,potx,potm,sda,sdd,sdp,vor,uop,cgm,bmp,dxf,emf,eps,met,pbm,pct,pcd,pcx,pgm,plt,ppm,psd,ras,sda,sdd,sgf,sgv,svm,tgs,tif,tiff,vor,wmf,xbm,xpm,jpg,jpeg,gif,png,pdf,log".split(","));
if(P_FORMATS.contains(extension.toLowerCase())){
// do stuff
}
Short answer: Will not work. You can't overwrite the contains, BUT: You can us the following code:
List<String> pformats= Arrays.asList("odt","ott","oth","odm","sxw","stw","sxg","doc","dot","xml","docx","docm","dotx","dotm","doc","wpd","wps","rtf","txt","csv","sdw","sgl","vor","uot","uof","jtd","jtt","hwp","602","pdb","psw","ods","ots","sxc","stc","xls","xlw","xlt","xlsx","xlsm","xltx","xltm","xlsb","wk1","wks","123","dif","sdc","vor","dbf","slk","uos","pxl","wb2","odp","odg","otp","sxi","sti","ppt","pps","pot","pptx","pptm","potx","potm","sda","sdd","sdp","vor","uop","cgm","bmp","dxf","emf","eps","met","pbm","pct","pcd","pcx","pgm","plt","ppm","psd","ras","sda","sdd","sgf","sgv","svm","tgs","tif","tiff","vor","wmf","xbm","xpm","jpg","jpeg","gif","png","pdf","log");
if(pformats.contains(extension.toLowerCase())){
}
This will make you extension to lowercase, and if within your Array are all extensions are already lowerCase, than it'll wokk.
Convert your List of extensions into a regular expression, compile it with the CASE_INSENSITVE flag, and use that.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class Foo {
public static void main(final String... args) {
final Pattern p = Pattern.compile("odt|ott|oth|odm|sxw|stw|sxg|doc|dot|xml|docx|docm|dotx|dotm|doc|wpd|wps|rtf|txt|csv|sdw|sgl|vor|uot|uof|jtd|jtt|hwp|602|pdb|psw|ods|ots|sxc|stc|xls|xlw|xlt|xlsx|xlsm|xltx|xltm|xlsb|wk1|wks|123|dif|sdc|vor|dbf|slk|uos|pxl|wb2|odp|odg|otp|sxi|sti|ppt|pps|pot|pptx|pptm|potx|potm|sda|sdd|sdp|vor|uop|cgm|bmp|dxf|emf|eps|met|pbm|pct|pcd|pcx|pgm|plt|ppm|psd|ras|sda|sdd|sgf|sgv|svm|tgs|tif|tiff|vor|wmf|xbm|xpm|jpg|jpeg|gif|png|pdf|log", Pattern.CASE_INSENSITIVE);
// Will be true
System.out.println(p.matcher("bmp").matches());
// Will be false
System.out.println(p.matcher("quasar").matches());
}
}
This would probably be easier to read/maintain if you build the regex programatically, but I've left that as an exercise to the reader.
How about:
extension.toLowerCase()
?
Although I'm not sure 100% sure what contains() method will do in this example. You might need to stick your extensions into a Set.
Edit: No it wont work as the contains method checks for the existence of a particular Object. Your string, even with the same value, is a different Object. So yes either a) override the contains method, e.g loop through the array and do a string comparison or b) simpler, use a Set.
Edit 2: Apparently it will work per comments below as ArrayList.contains() checks for equality (so you will get a string match), but this seems to disagree with the top voted answer that says it wont.
If all your formats are lower case, then toLowerCase combined with a HashSet is the preferred solution.
If your formats are in mixed case (and shall stay this way, as you are using them for other things, too) you need a real case-insensitive comparison.
Then a TreeSet (or other SortedSet) with a case insensitive collator as the comparator will do. (It is not as fast as a HashSet, but will still be faster then the ArrayList (except for really small lists).)
Alternatively a HashSet variant using a custom hashCode and equals (or simply a normal HashSet on wrapper objects with a case insensitive implementation of equals and hashCode) would do fine.
Add this extended List class:
private static class ListIgnoreCase<String> extends java.util.LinkedList {
public ListIgnoreCase(Collection<String> c) {
super();
addAll(c);
}
public boolean containsIgnoreCase(java.lang.String toSearch) {
for (Object element : this)
if (java.lang.String.valueOf(element).equalsIgnoreCase(toSearch))
return true;
return false;
}
}
Now you can call asList like this:
if(new ListIgnoreCase(Arrays.asList("odt","ott","oth","odm"))
.containtsIgnoreCase(extension)) {
...
You can use IteracleUtils and Predicate from collections4 (apache).
List<String> pformats= Arrays.asList("odt","ott","oth","odm","sxw","stw","sxg","doc","dot","xml","docx","docm","dotx","dotm","doc","wpd","wps","rtf","txt","csv","sdw","sgl","vor","uot","uof","jtd","jtt","hwp","602","pdb","psw","ods","ots","sxc","stc","xls","xlw","xlt","xlsx","xlsm","xltx","xltm","xlsb","wk1","wks","123","dif","sdc","vor","dbf","slk","uos","pxl","wb2","odp","odg","otp","sxi","sti","ppt","pps","pot","pptx","pptm","potx","potm","sda","sdd","sdp","vor","uop","cgm","bmp","dxf","emf","eps","met","pbm","pct","pcd","pcx","pgm","plt","ppm","psd","ras","sda","sdd","sgf","sgv","svm","tgs","tif","tiff","vor","wmf","xbm","xpm","jpg","jpeg","gif","png","pdf","log");
Predicate<String> predicate = (s) -> StringUtils.equalsIgnoreCase(s, "JPG");
if(IterableUtils.matchesAny(pformats, predicate))
// do stuff
}
org.apache.commons.collections4.IterableUtils

Categories

Resources