How can I use Optional to return empty if there is any exception in the code in it? - java-8

Pretty new to Optional/Java8 usage and I had a doubt regarding its usage.
I have a function in my API which returns a String which can be null or empty. Its similar to finding the id in email like: abc#gmail.com -> abc is o/p.
Now one way of doing this was:
public Optional<String> getUser(final String emailId) {
if (TextUtils.isEmpty(emailId)) {
return Optional.empty();
}
String userIDSeparator = "#";
int userNameEndIndex = emailId.indexOf(userIDSeparator);
if (userNameEndIndex == -1) {
return Optional.empty();
}
return Optional.of(emailId.substring(0, userNameEndIndex));
}
I was wondering if there is any neater way of doing this to return an Optional?
Also, Optional was introduced in Java8 so is there anyway the code can be java7 compatible? I am aware of preprocessors in C not sure if something similar is available.
Note:
I have not compiled this code, so there might be some errors. I wanted the input on Optional.
Thanks!

Well, the code can certainly be reduced. i.e.
public Optional<String> getUser(final String emailId) {
return Optional.of(emailId)
.filter(email -> email.contains("#"))
.map(email -> email.substring(0, email.indexOf("#")));
}
if this method can ever receive a null value then you'd need to change Optional.of(emailId) to Optional.ofNullable(emailId).
As for:
Also, Optional was introduced in Java8 so is there any way the code can
be java7 compatible?
Not that I know of. There may be other libraries that have similar functionality to Java's Optional type, so a little bit of research online may get you to the right place.

Maybe you mean something like this :
public Optional<String> getUser(final String emailId) {
return Optional.ofNullable(emailId)
.filter(email -> email.contains("#"))
.map(email -> Optional.of(email.replaceAll("(.*?)#.*", "$1")))
.orElseGet(Optional::empty);
}
Example
null -> Optional.empty
"" -> Optional.empty
"abc#gmail.com" -> abd
As #Aominè mention, there are some unnecessary parts in my solution, you can use this version instead :
public Optional<String> getUser(final String emailId) {
return Optional.ofNullable(emailId)
.filter(email -> email.contains("#"))
.map(email -> email.replaceAll("(.*?)#.*", "$1"));
}

Related

Project Reactor: Obtain Size of List Contained Within a Mono

I'm trying to do something again here in project reactor that I'm sure is reeeeeal simple for any of you project reactor gurus out there!
I've been searching and scratching around with this one for a while now, and feel I'm once again hitting a wall with this stuff.
All I'm trying to do is determine if a List of objects contained within a Mono is empty or not.
This is what I have so far:
private Mono<Boolean> isLastCardForAccount(String accountId) {
return cardService.getAccountCards(accountId)
.hasElement();
}
I'm thinking the above might work, but I'm having difficulty figuring out how to extract/access the 'Boolean' contained within the returned Mono. I think I have to use 'subscribe' somehow right?
I've mucked around with this stuff for a while now, but still no luck.
Here is how 'getAccountCards' is defined:
public Mono<List<Card>> getAccountCards(final String accountId) {
return cardCrudRepository.getCardsByAccountId(accountId)
.collectList();
}
From CardCrudRepository:
// #Query("SELECT * FROM card WHERE account_id = :accountId") <-Not sure if I need this
Flux<Card> getCardsByAccountId(String accountId);
And lastly, how I'm using 'isLastCardForAccount':
public Mono<Void> updateCardStatus(String accountId, String cardId, String cardStatus) {
return accountService.getAccount(accountId)
.map(Account::getClientId)
.map(clientId -> createUpdateCardStatusServiceRequestData(clientId, cardId, cardStatus))
.flatMap(requestData -> cartaClient.updateCardStatus(requestData)
.then(Mono.defer(() -> isCardBeingCancelled(cardStatus) ? allCardsCancelledForAccount(accountId) ? removeAccount(accountId) :
(isLostOrStolen(cardStatus) ? replaceCard(cardId, cardStatus).flatMap(this::updateCardNumber) : Mono.empty()) : Mono.empty())));
}
As always, any and all help and insight is tremendously appreciated!
I am not sure if this would resolve the issue but this way you can try to write your logic
return accountService.getAccount(accountId)
.map(Account::getClientId)
.map(clientId -> createUpdateCardStatusServiceRequestData(clientId, cardId, cardStatus))
.flatMap(requestData -> cartaClient.updateCardStatus(requestData)
.then(Mono.defer(() ->
Mono.zip(
Mono.just(isCardBeingCancelled(cardStatus)),
isLastCardForAccount(accountId),
Mono.just( isLostOrStolen(cardStatus) )
)
.map(tuple -> {
WRITE YOUR IF ELSE LOGIC
})
The idea is to use zip and then use the tuple for writing logic. The Tuple would be of type Tuple3 of <Boolean, Boolean ,Boolean>. I made the assumption that isLostOrStolen(cardStatus) returns Boolean.
One way of doing that is by using filterWhen operator like this:
.then(Mono.defer(() -> {
if (isCardBeingCancelled(cardStatus)) {
return Mono.just(accountId)
.filterWhen(this::allCardsCancelledForAccount)
.flatMap(this::removeAccount);
} else if (isLostOrStolen(cardStatus)) {
return replaceCard(cardId, cardStatus).flatMap(this::updateCardNumber);
}
return Mono.empty();
}))
You can use filterWhen in the case of asynchronous filtering. Check this section of Which operator do I need? reference and this How to filter Flux asynchronously.
As a side note, this is not going to work as you expect:
private Mono<Boolean> isLastCardForAccount(String accountId) {
return cardService.getAccountCards(accountId)
.hasElement();
}
public Mono<List<Card>> getAccountCards(final String accountId) {
return cardCrudRepository.getCardsByAccountId(accountId)
.collectList();
}
The collectList() will emit an empty List if there is no card. I'd use exists query instead:
public Mono<Boolean> isLastCardForAccount(final String accountId) {
return cardCrudRepository.existsByAccountId(accountId);
}

Is there a way to print out the chain of all operations in a Flux?

Given a Flux or a Mono from project reactor is a there a way to get the Flux or Mono to print out what the operator chain looks like. For example given the code below.
Fulx flux = Flux.just("a","b","c")
.map( v -> v.toUpperCase())
.log();
Is there some way to get the flux to print out a list of all the operators that are chained inside in the processing pipeline? Some nice ascii formatted text or a marble diagram?
printTheFlux(flux) should make a nice printout that show the structure of all the operators from the example above. I am not expecting to produce the code in the lambda's just a way to see what operators are chained together.
There is partial building blocks for doing this with the Scannable interface:
public String textRepresentation(Flux<?> flux) {
Scannable sc = Scannable.from(flux);
//scan the last operator in the chain and ask if it knows its parents
List<String> names = sc.parents().map(Scannable::operatorName)
.collect(Collectors.toList());
//as it traverses the chain from bottom to top, we need to reverse the order
Collections.reverse(names);
//need to also add the last operator
names.add(sc.operatorName());
return names.toString();
}
#Test
public void textRepresentationTest() {
Flux flux = Flux.just("a","b","c")
.map( v -> v.toUpperCase())
.log();
System.out.println(textRepresentation(flux));
}
Prints
[map, log]
Not all operators fully support it though (as you can see, the just source doesn't for instance).
Nice suggestion!
However, waiting for it, we can just have something like :
Disposable flux = Flux.just("a", "b", "c")
.map(String::toUpperCase)
.doOnNext(FluxUtil::print)
.subscribe();
Where FluxUtil::print is just a static method that you can write with different ways.
Here is the complete code works for me:
public class FluxUtil {
private static String s = "";
public static void main(String[] args) {
Disposable flux = Flux.just("a", "b", "c")
.map(String::toUpperCase)
.doOnNext(FluxUtil::print)
.subscribe();
}
private static Object print(Object o) {
s = !s.isEmpty() ? s.concat("->") : s;
s = s.concat(o.toString());
System.out.println(s);
return o;
}
}

Functional programming in java: Cloning Vs Mutating. Good or bad?

Mutating:
"transformEmployeeNameToUpperCase" function to transform employee name to uppercase.
List<Employee> employeesStartsWithDInUppercase1 = employees.stream()
.filter(employee -> employee.getName().startsWith("D"))
.map(Main::transformEmployeeNameToUpperCase)
.collect(Collectors.toList());
public static Employee transformEmployeeNameToUpperCase(Employee employee){
employee.setName(employee.getName().toUpperCase());
return employee;
}
Cloning:
"createEmployeeWithUpperCaseName" function to new employee with name in uppercase.
List<Employee> employeesStartsWithDInUppercase2 = employees.stream()
.filter(employee -> employee.getName().startsWith("D"))
.map(Main::createEmployeeWithUpperCaseName)
.collect(Collectors.toList());
public static Employee createEmployeeWithUpperCaseName(Employee e){
return new Employee( e.getId(), e.getName().toUpperCase(), e.getDesignation(), e.getAge());
}
Does "createEmployeeWithUpperCaseName" follow rule 1(above) as they say
yes: the employee is not being modified
In case of "transformEmployeeNameToUpperCase", does it follow rule 2(above)?
yes, although the rule uses an incorrect terminology. It creates an object, not a variable. You can't create a variable.
Is it good practice to use transformEmployeeNameToUpperCase way?
No, at least not the way you're doing it. There's nothing bad per se in modifying mutable objects: they're mutable for a reason. But a map() operation shouldn't modify its input and return it. You're perverting its purpose. A future reader of your code wouldn't expect a map operation to mutate its input, and you're thus making your code do unexpected things, leading to bugs and/or misunderstandings. It would be better to do it this way:
employees.stream()
.filter(employee -> employee.getName().startsWith("D"))
.forEach(e -> e.setName(e.getName().toUpperCase()));
That way, it makes it clear that the point of the pipeline is to have a side effect on the elements of the list. And it doesn't create a (probably) useless copy of the list, too.
Agree with #JB Nizet, but still if you don't want to change the original object but want to change the name of employee to Uppercase. use object cloning.
pseudo code:
List<Employee> employeeWithUpperCaseName = employees.parallelStream()
.filter(e -> e.getName().startsWith("D"))
.map(x -> {
Employee s = null;
try {
s = (Employee) x.clone();
s.setName(x.getName().toUpperCase());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
} finally {
return s;
}
})
.collect(Collectors.toList());
you can write it in better way.

java 8 method reference to: either `equals` or `equalsIgnoreCase`

I tried to convert the body of a method boolean exists(String value, boolean isCaseSensitive) :
for(String str : existingNames){
if(isCaseSensitive ? str.equals(name) : str.equalsIgnoreCase(name)){
return true;
}
}
return false;
to a solution that utilises java8 method references:
Predicate<String> equalityPred = isCaseSensitive ?
name::equals :
name::equalsIgnoreCase;
return existingNames.stream().anyMatch(equalityPred);
Then I saw that this way the equality is performed in the opposite direction (e.g. value.equals(str) ).
Is there a way to fix this and still use method references, and if no what would be the java8 way.
There is no “opposite direction” for equality. The only issue might be the behavior for null values. Your loop might fail, if the collection contains null, your method references will fail, if name is null.
You may achieve the original behavior using lambda expressions:
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
Predicate<String> equalityPred = isCaseSensitive?
s -> s.equals(name):
s -> s.equalsIgnoreCase(name);
return existingNames.stream().anyMatch(equalityPred);
}
but it makes little sense to consider null for the name parameter, when it will never be equal, as the code will fail with a NullPointerException, if the collection contains null.
To get a sensible behavior for null, you may use
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
Predicate<String> equalityPred = name==null? Objects::isNull:
isCaseSensitive? name::equals: name::equalsIgnoreCase;
return existingNames.stream().anyMatch(equalityPred);
}
or just
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
return name==null || isCaseSensitive?
existingNames.contains(name):
existingNames.stream().anyMatch(name::equalsIgnoreCase);
}
If you know that the Collection will never contain null, but want to support null for the name parameter, you could also use
boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
return name!=null && existingNames.stream()
.anyMatch(isCaseSensitive? name::equals: name::equalsIgnoreCase);
}
Well don't use a method reference then and write your lambda directly:
static boolean existsJDK8(List<String> existingNames, String value, boolean isCaseSensitive) {
Predicate<String> equalityPred = isCaseSensitive ? s -> value.equals(s) : s -> value.equalsIgnoreCase(s);
Predicate<String> equalityPredReversed = isCaseSensitive ? s -> s.equals(value) : s -> s.equalsIgnoreCase(value);
// return existingNames.stream().anyMatch(equalityPredReversed);
return existingNames.stream().anyMatch(equalityPred);
}

Apache Mahout - Read preference value from String

I'm in a situation where I have a dataset that consists of the classical UserID, ItemID and preference values, however they are all strings.
I have managed to read the UserID and ItemID strings by Overriding the readItemIDFromString() and readUserIDFromString() methods in the FileDataModel class (which is a part of the Mahout library) however, there doesnt seem to be any support for the conversion of preference values if I am not mistaken.
If anyone has some input to what an approach to this problem could be I would greatly appreciate it.
To illustrate what I mean, here is an example of my UserID string "Conversion":
#Override
protected long readUserIDFromString(String value) {
if (memIdMigtr == null) {
memIdMigtr = new ItemMemIDMigrator();
}
long retValue = memIdMigtr.toLongID(value);
if (null == memIdMigtr.toStringID(retValue)) {
try {
memIdMigtr.singleInit(value);
} catch (TasteException e) {
e.printStackTrace();
}
}
return retValue;
}
String getUserIDAsString(long userId) {
return memIdMigtr.toStringID(userId);
}
And the implementation of the AbstractIDMigrator:
public class ItemMemIDMigrator extends AbstractIDMigrator {
private FastByIDMap<String> longToString;
public ItemMemIDMigrator() {
this.longToString = new FastByIDMap<String>(10000);
}
public void storeMapping(long longID, String stringID) {
longToString.put(longID, stringID);
}
public void singleInit(String stringID) throws TasteException {
storeMapping(toLongID(stringID), stringID);
}
public String toStringID(long longID) {
return longToString.get(longID);
}
}
Mahout is deprecating the old recommenders based on Hadoop. We have a much more modern offering based on a new algorithm called Correlated Cross-Occurrence (CCO). Its is built using Spark for 10x greater speed and gives real-time query results when combined with a query server.
This method ingests strings for user-id and item-id and produces results with the same ids so you don't need to manage those anymore. You really should have look at the new system, not sure how long the old one will be supported.
Mahout docs here: http://mahout.apache.org/users/algorithms/recommender-overview.html and here: http://mahout.apache.org/users/recommender/intro-cooccurrence-spark.html
The entire system described, with SDK, input storage, training of model and real-time queries is part of the Apache PredictionIO project and docs for the PIO and "Universal Recommender" and here: http://predictionio.incubator.apache.org/ and here: http://actionml.com/docs/ur

Resources