java comparison of two enums - java

Given the test code:
#Test
public void testEnumAreEqual() {
for (var someEnum : SomeEnum.values()) {
Assertions.assertTrue(EnumUtils.isValidEnum(OtherEnum.class, someEnum.name()));
}
for (var otherEnum : OtherEnum.values()) {
Assertions.assertTrue(EnumUtils.isValidEnum(SomeEnum.class, otherEnum.name()));
}
}
I want to check if two given enums are containing the same values.
Is there maybe a more elegant way to do this?

Build a set of the names:
Set<String> someEnumNames =
Arrays.stream(SomeEnum.values())
.map(Enum::name)
.collect(toSet());
Do the same for OtherEnum (consider extracting the above into a method).
Then:
assertEquals(someEnumNames, otherEnumNames);

Related

Assert two List have same subtypes in a certain order

I would like to check if two lists (let's say, ArrayLists) have exactly the same instance classes, based in an expected List.
To do so, I have built the next method, but I was wondering whether there is another fancy way using certain library, like assertJ.
private void assertConcreteTypes(List actual, List expected) {
for (int i = 0; i < actual.size(); i++){
assertThat(actual.get(i)).isExactlyInstanceOf(expected.get(i).getClass());
}
}
Any suggestion would be more than welcome. Thanks!
You can create a custom Assertj asserter and leverage it for asserting types.
class TypeAssert extends AbstractAssert<TypeAssert, List<?>> {
public TypeAssert(List<?> actual) {
super(actual, TypeAssert.class);
}
public TypeAssert hasElementsOfExactlyTheSameTypeAs(List<?> expected) {
isNotNull();
for (int i = 0; i < actual.size(); i++) {
if (!actual.get(i).getClass().equals(expected.get(i).getClass())) {
failWithMessage("Expected [%s]th element to be of type: %s but was of type: %s",
i, expected.get(i).getClass(), actual.get(i).getClass());
}
}
return this;
}
}
You'll need a static method that will expose the object of our Custom Exporter.
class Assertions {
// static factory method which exposes custom asserted
static TypeAssert assertThat(List<?> actual) {
return new TypeAssert(actual);
}
}
And then you can use the above method for asserting based on type.
List<Object> actual = List.of(new Employee());
List<Object> expected = List.of(new StringBuilder());
Assertions.assertThat(actual).hasElementsOfExactlyTheSameTypeAs(expected);
If you are asserting based on a type only at a very few places then I think the approach you have mentioned is much cleaner and readable. But if you need such assertion at several places then may be creating a custom assertion is a good choice.
You need to take into account lists of different sizes as well as null elements in the lists.
This seems quite readable and caters to these edge cases:
private void assertConcreteTypes(List actual, List expected) {
assertEquals(classes(expected), classes(actual));
}
private List<Class<?>> classes(List<Object> list) {
return list.stream().map(v -> v == null ? null : v.getClass()).collect(Collectors.toList());
}

assertThat field by field or compare object

I'm having an argument with my friend and I would like to know your opinion.
In a test do you think that is better to compare field by field or just create a expectedResultObject and compare it.
For instance:
Assert.That(obj.Foo).isEqualTo(FOO);
Assert.That(obj.Test).isEqualTo(TEST);
vs
Foo expected = new Foo(FOO, TEST);
assertThat(obj).usingRecursiveComparison().isEqualTo(expected);
In this example we only have two fields but we can have allot more.
Thanks
If you can have multiple fields, the expected method is better because you'll be adding the other fields inside the constructors' params. Imagine if you have 100 fields, adding them line by line as you suggested in your first example would be a headache, while adding in the params would be a bit simpler.
Between the two possibilities, I prefer the one without the usingRecursiveComparison().
I wanted to add a few thins :
An object is not a data toolbox, so it's not a good thing to add getter/setter to test your object's creation. It's better test a behaviour, a method where you can test the return.
Generally I'm not fond of writing more than one assertion in a test.
There is a technique which made assertions more lisibles (with AssertJ but I think you can make this kind of thing with Hamcrest).
The initial class :
public class Amount {
private int value;
public Integer add(int amountToAdd) {
value += amountToAdd;
return value;
}
}
Create an Asserter :
public class IntegerAsserter extends org.assertj.core.api.AbstractAssert<IntegerAsserter, Integer> {
IntegerAsserter(Integer actual) {
super(IntegerAsserter.class, actual);
}
public IntegerAsserter isBetweenOneOrTwo() {
Assert.assertTrue(actual < 2);
Assert.assertTrue(actual > 1);
return this;
}
}
Create a new Assertions :
public class Assertions extends org.fest.assertions.Assertions {
public static IntegerAsserter assertThat(Integer actual) {
return new IntegerAsserter(actual);
}
}
And then use it :
public void should_be_between_one_or_two {
Amount amount = new Amount(0);
Integer newAmount = amount.add(1);
Assertions.assertThat(obj).isBetweenOneOrTwo();
}

Private Sorting Rule in a Stream Java

Hey if anyone has an idea I would be really thankfull.
I'm in a Java stream and i would like to sort my list that i'll be returning.
I need to sort the list via TradPrefis ( MyObject::getTradPrefix ).
But this would be way too easy. Because i want to sort following the number at the end of TradPrefix exampleTradPrefix_[NUMBER TO SORT]
Exemple : hello_1
test_2
...
still_there_22
Here is a piece of code so you can imagine easier.
public LinkedHashSet<WsQuestion> get(String quizId, String companyId) {
LinkedHashSet<QuizQuestionWithQuestion> toReturn = quizQuestionRepository.findAllQuizQuestionWithQuestionByQuizId(quizId);
return (toReturn.stream()
.map(this::createWsQuestion)
.sorted(comparing(WsQuestion::getTradPrefix.toString().length()))
.collect(Collectors.toCollection(LinkedHashSet::new)));
}
One method would simply be to split getTradPrefix().toString() by _ and parse the rightmost value as an int, and use it to sort the Stream:
public LinkedHashSet<WsQuestion> get(String quizId, String companyId) {
LinkedHashSet<QuizQuestionWithQuestion> toReturn = quizQuestionRepository.findAllQuizQuestionWithQuestionByQuizId(quizId);
return toReturn.stream()
.map(this::createWsQuestion)
.sorted(Comparator.comparingInt(question -> {
String[] args = question.getTradPrefix().toString().split("_");
return Integer.parseInt(args[args.length - 1]);
}))
.collect(Collectors.toCollection(LinkedHashSet::new));
}
If I where you I would simply put a method on the WsQuestion class, let's call it sort order:
public int getSortOrder() {
return Integer.valueOf(tradPrefix.substring(tradPrefix.lastIndexOf("_") + 1));
}
The Integer parse is needed since comparing strings would give "11" < "2" (thanks Holger for pointing this out). The lastIndexOf() makes sure that any number of underscores are allowed in tradPrefix, as long as there is at least one.
Then simply create a comparotor by using Comparator.comparingInt()
public LinkedHashSet<WsQuestion> get(String quizId, String companyId) {
LinkedHashSet<QuizQuestionWithQuestion> toReturn = quizQuestionRepository.findAllQuizQuestionWithQuestionByQuizId(quizId);
return (toReturn.stream()
.map(this::createWsQuestion)
.sorted(comparingInt(WsQuestion::getSortOrder))
.collect(Collectors.toCollection(LinkedHashSet::new)));
}
You can make a small Comparator like this:
private static final Comparator<String> questionComparator = Comparator.comparingInt(s -> {
String[] pieces = s.split("_");
return Integer.parseInt(pieces[pieces.length-1]);
});
Then use it in your sorted().
Having a separate Comparator will make your code more readable too, since you will be separating concerns.
return toReturn.stream()
.map(this::createWsQuestion)
.sorted(questionComparator)
.collect(Collectors.toCollection(LinkedHashSet::new));

Concatenate two or more optional string in Java 8

I have a rather simple question for you guys. In Java 8 it was introduced the Optional type. I have two objects of type Optional<String> and I want to know which is the more elegant way to concatenate them.
Optional<String> first = Optional.ofNullable(/* Some string */);
Optional<String> second = Optional.ofNullable(/* Some other string */);
Optional<String> result = /* Some fancy function that concats first and second */;
In detail, if one of the two original Optional<String> objects was equal to Optional.empty(), I want the whole concatenation to be empty too.
Please, note that I am not asking how to concatenate the evaluation of two Optionals in Java, but how to concatenate two Strings that are inside some Optional.
Thanks in advance.
The solution I found is the following:
first.flatMap(s -> second.map(s1 -> s + s1));
which can be cleaned using a dedicated method, such the following:
first.flatMap(this::concat);
Optional<String> concat(String s) {
second.map(s1 -> s + s1);
}
However, I think that something better can be found.
If we want to generalize to a list or an array of Optional<String>, then we can use something similar to the following.
Optional<String> result =
Stream.of(Optional.of("value1"), Optional.<String>empty())
.reduce(Optional.of(""), this::concat);
// Where the following method id used
Optional<String> concat(Optional<String> first, Optional<String> second) {
return first.flatMap(s -> second.map(s1 -> s + s1));
}
Note that in order to compile the above code, we have to manually bind the type variable of Optional.empty() to String.
You can stream the Optionals and reduce them with a concat.
Optional<String> first = Optional.of("foo");
Optional<String> second = Optional.of("bar");
Optional<String> result = Stream.of(first, second).flatMap(Optional::stream).reduce(String::concat);
If you are using Java 8 replace the flatMap operator with filter(Optional::isPresent).map(Optional::get).
Consider also to use the joining collectors: this will return String, not an Optional<String>.
You can use something like :
Optional<String> result;
result = first.isPresent() && second.isPresent() ? Optional.of(first.get() + second.get()) : Optional.empty();
Any solution that requires a flexible number of optional strings must explicitly use a StringBuilder, rather than rely on the compiler to generate one for you.
String concatThem(Stream<String> stringsin) {
StringBuilder sb = new StringBuilder();
stringsin.forEach(s -> sb.append(s));
return sb.toString();
}
If you have a Stream<Optional<String>> then it becomes:
String concatThem(Stream<Optional<String>> stringsin) {
StringBuilder sb = new StringBuilder();
stringsin.filter(Optional::isPresent).forEach(s -> sb.append(s.get()));
return sb.toString();
}
Otherwise if you have N optional strings you end-up with a heavy cycle of creation and destruction of N-1 single-use StringBuilder objects (generated at compile time) and N-1 strings.
Edit: I had misread, so here's how to do it if any of them is missing to clear it all:
String concatThem(Stream<Optional<String>> stringsin) {
StringBuilder sb = new StringBuilder();
try {
stringsin.forEach(s -> {
if (!s.isPresent()) throw new IllegalArgumentException();
sb.append(s.get())
});
}
catch(IllegalArgumentException ex) {
sb.setLength(0);
}
return sb.toString();
}
This is of course if you insist on using the new API that's light on the syntax and heavy on the execution.
#SafeVarargs
public final Optional<String> concat(Optional<String>... inputs)
{
return Arrays.stream(inputs)
.reduce((left, right) -> left.flatMap(leftValue -> right.map(rightValue -> leftValue + rightValue)))
.get();
}
#Test
public void shouldReturnEmptyIfFirstItemIsEmpty()
{
assertThat(concat(Optional.empty(), Optional.of("B")), is(Optional.empty()));
}
#Test
public void shouldReturnEmptyIfSecondItemIsEmpty()
{
assertThat(concat(Optional.of("A"), Optional.empty()), is(Optional.empty()));
}
#Test
public void shouldConcatIfNoItemIsEmpty()
{
assertThat(concat(Optional.of("A"), Optional.of("B")), is(Optional.of("AB")));
}
Here's an implementation using the reduce method on Stream.
Here's another pretty way:
#Value.Immutable
public abstract class Person {
public Optional<String> firstName() {
return Optional.of("John");
}
public Optional<String> lastName() {
return Optional.of("Smith");
}
public Optional<String> location() {
return Optional.of("Paris");
}
#Value.Lazy
public String concat() {
return Stream.of(firstName(), lastName(), location())
.filter(Optional::isPresent)
.map(Optional::get)
.filter(StringUtils::isNotBlank)
.reduce((first, second) -> first + '.' + second)
.orElse("");
}
}
Note that, as mentioned in other comments, the concat() method performs string concatenations without using a StringBuilder (which might not be performant if you call the method a lot of times). To fix this, in the above example we're using Immutables' [1] #Value.Lazy, which makes sure the concat() method is called once and the result is cached for further calls. Works great!
[1] https://immutables.github.io

Java String contain method and enum

I have enum defined in class as
public enum EnumSample {
SPACE,
NASA,
SPUTNIK;
}
In class Test, I have a method with following code snippet
if (str.contains(<>)) {
Is it possible to search all enum values in contain method of String?
You can iterate over the .values() of the enum and apply .contains() for each of them.
For example:
for (EnumSample value : EnumSample.values()) {
if (str.contains(value.name()) {
//do your thing
}
}
One problem with contains is that it finds parts of words - for example, it would find "NASA" in "NASAL DECONGESTANTS". If you would like your comparison to be fast, and look for specific words, not parts of words, use regex search instead.
The regex for your example would look like this:
\b(SPACE|NASA|SPUTNIK)\b
You can construct and use it like this:
static Pattern allEnumVals;
static {
StringBuilder b = new StringBuilder("\\b(");
boolean first = true;
for (EnumSample e : EnumSample.values()) {
if (!first) {
b.append("|");
} else {
first = false;
}
b.append(e.name());
}
b.append(")\\b");
allEnumVals = Pattern.compile(b.toString());
}
static boolean check(String str) {
return allEnumVals.matcher(str).find();
}

Categories