-3

I got this Optional String (non-null) for which I want to extract only the first word (in this case – username, out of an email address). What is the best way to do it with Optional, given the fact I can disregard everything after the delimiter ('@', in this case). I do not want a stream as a result, just a single string.

@NonNull private final Optional<String> email;

email.ifPresent(s -> myBuilder.set(UserName, s));

So an input for example: hello@domain.com

Desired results: hello

Tried in many ways but theres always some sort of limitation with this Optional string & streams. I am new to it so I'm sure there's something I don't understand properly.

Optional<String> userName = Stream.of(email)
    .filter(Optional::isPresent)
    .map(Optional::get)
    .<What's next?>

Or

if (email.isPresent()) {
    Optional <String> userName = Pattern.compile("@").splitAsStream(email).toString();
}

Doesn't compile but I know it is wrong.

edit:

I looked up trim @domain.xxx from email leaving just username but it doesn't help me because this is not a regular string but Optional & streams. Also, I do not want to get an array of results but a single result

edit2:

if (email.isPresent()) {
    Optional<String> newAccountName = Arrays.stream(email.get().split("@")).findFirst();
}

Is this the right way to go?

MC Emperor
  • 22,334
  • 15
  • 80
  • 130
Sonya gold
  • 87
  • 1
  • 6
  • 1
    Does this answer your question? [trim @domain.xxx from email leaving just username](https://stackoverflow.com/questions/10386025/trim-domain-xxx-from-email-leaving-just-username) – Joe Nov 28 '22 at 11:45
  • 1
    "Tried in many ways" - how? Plese include your attempt. A simple `split` should do the trick. – f1sh Nov 28 '22 at 11:46
  • @joe No because I know how to do it with a regular string, but not with Optional strings and streams, but thanks – Sonya gold Nov 28 '22 at 11:50
  • 1
    @Sonyagold you are overcomplicating things. Just call `.get()` on the Optional, then work on the `String`. Use `split` on the `String`. – f1sh Nov 28 '22 at 11:54
  • @f1sh Thanks, see edit2. Does it make sense to use Arrays.Stream? It does not compile otherwise – Sonya gold Nov 28 '22 at 11:57
  • @Sonyagold you could just use `email.get().split("@")[0]`, but your approach with `Arrays.stream` and `findFirst` is cleaner because if the input does not contain a `@`, it gives you an empty `Optional` instead of throwing an `Exception`. – f1sh Nov 28 '22 at 12:00
  • Since you never have more than one element, using Streams is pointless. Streams are designed to handle *sequences of elements*, not cases where it is guaranteed to have at most a single element. – MC Emperor Nov 28 '22 at 12:16
  • 2
    @f1sh `.split("@")[0]` doesn’t throw an exception. – Holger Nov 28 '22 at 13:44

1 Answers1

0

You don't need to generate a Stream.

Instead, you can make use of the String.replaceFirst(), which expects a regular expression and a replacing String, like that replaceFirst("@.*", ""), which will remove everything after an at sign @ (including @ itself).

email.ifPresent(
    s -> myBuilder.set(
        UserName,
        s.replaceFirst("@.*", ""))
    );

By the way, since you've specified email variable with private access modifier, obviously it's a field. Hence, it is worth to point out that having field of Optional type isn't very beneficial. The common practice is to unpack the optional before instantiating the object, rather than storing a potentially empty optional (for instance, in some cases it might make no sense to create a new domain object if the optional doesn't contain data, e.g. : user without email can not exist).

You might be interested in reading these Questions:

Alexander Ivanchenko
  • 25,667
  • 5
  • 22
  • 46