检查电子邮件域是否在域列表中的最快方法

Quickest way to check if an email domain is within a list of domains

提问人:Lh74vBQrjMJtrYKDUdzK 提问时间:10/25/2023 最后编辑:Lh74vBQrjMJtrYKDUdzK 更新时间:10/27/2023 访问量:110

问:

我想确保客户输入的电子邮件地址是企业帐户电子邮件,因为我们只与拥有自己域的大公司合作。

我有一个来自这个网站的最常见的电子邮件域列表:https://email-verify.my-addr.com/list-of-most-popular-email-domains.php

我想要最快的方法来检查电子邮件是否没有 Java 中的这些域之一。

List<String> domains = ...
String email = "[email protected]";

Boolean domainsMatch = false;

//Some code to check the domains against the email

return !domainMatches;

我尝试了显而易见的

for (String domain: domains)
{
  if (email.contains(domain)) domainsMatch = true;
}

我想知道是否有更快、更有效的方法

Java 数组 匹配

评论

2赞 Andy Turner 10/26/2023
你不应该使用 ,因为这可能匹配,例如 跟。contains[email protected]gmail.com
2赞 Iłya Bursov 10/26/2023
您可以尝试使用哈希集,它们应该为您提供摊销的 0(1) 而不是 for 的 O(N)
1赞 Old Dog Programmer 10/26/2023
您是否考虑过使用哈希查找?HashSet 就是这样做的。
0赞 mandy8055 10/26/2023
@I łyaBursov 使用 HashSet 更有意义。感谢您的见解
0赞 MC Emperor 10/26/2023
如果你想“确保客户输入的电子邮件地址是企业帐户电子邮件”,为什么不维护这些域的白名单,而不是热门域的黑名单呢?

答:

1赞 mandy8055 10/25/2023 #1

我能想到的一种有效方法(前提是您正在使用或以后)是使用 streams api,它专门设计用于对大型数据集的操作更有效。Java 8

List<String> domains = ...
String email = "[email protected]";

boolean domainMatches = domains.stream()
    .anyMatch(email::contains);

return !domainMatches;

此外,正如 @AndyTurner 所指出的,您不应该使用,因为它可以匹配一些无效的地址(例如)。因此,如果您正在寻找另一种方式,则可以使用等式:containsbob@gmailcom

List<String> domains = ...
String email = "[email protected]";

String domain = email.split("@")[1];

boolean domainMatches = domains.stream()
    .anyMatch(domain::equals);

return !domainMatches;

编辑:(推荐方法)

根据评论和头脑风暴,我想出了另一种更有效的方法,那就是使用 .像这样:streamsHashSet

List<String> domains = ...
String email = "[email protected]";

Set<String> domainSet = new HashSet<>(domains);
String domain = email.split("@")[1]; // You can also use indexOf and substring.

boolean domainMatches = domainSet.contains(domain);

return !domainMatches;

评论

1赞 Andy Turner 10/25/2023
请提供关于您声称的效率的更多细节。
1赞 MC Emperor 10/26/2023
您也可以使用 和 代替 .indexOfsubstringsplit
2赞 Luatic 10/26/2023
只需对域使用 HashSet,然后就可以直接使用 .没有理由使用列表。contains
1赞 Reilas 10/27/2023
@Luatic,我不跟着。值“bob@gmailcom”不应返回[email protected]true,无论是 HashSet 还是 String
1赞 Luatic 10/27/2023
@Reilas 啊,确实,安迪的观点是,在被默默接受的域名之后,可以有一个域名的前缀。你是对的,这个例子应该被修复为类似或。@bob@<...>gmail.com<...>gmail.com<...>@<...>
-2赞 Reilas 10/26/2023 #2

"...我想要最快的方法来检查电子邮件是否没有 Java 中的这些域之一。..."

最快的解决方案是循环

List<String> domains = ...
String email = "[email protected]".toLowerCase(),
       s = email.substring(email.indexOf('@') + 1);

Boolean domainsMatch = false;

//Some code to check the domains against the email

for (String domain: domains)
{
    if (domain.endsWith(s)) {
        domainsMatch = true;
        break;
    }
}

return domainsMatch;

或者,使用

List<String> domains = ...
String email = "[email protected]".toLowerCase(),
       s = email.substring(email.indexOf('@') + 1);

//Some code to check the domains against the email

Boolean noMatch
    = domains.stream()
             .noneMatch(x -> x.toLowerCase().endsWith(s));
1赞 tbatch 10/27/2023 #3

jmail 库可以为您做到这一点。它不是使用正则表达式来验证电子邮件,而是将电子邮件解析为一个对象,然后对各个部分进行验证。它还允许自定义验证。

in 的字段之一是 。这包含按句点拆分的域的所有部分(假设它已正确解析,否则它将无法通过其他验证)。您可以按如下方式添加自定义验证程序:Email.javaList<String> domainPartsEmailValidator

public class MyEmailValidator {
  public boolean validateEmail(String email) {
    List<String> invalidDomains = List.of("gmail", "yahoo");
    EmailValidator validator = JMail.strictValidator().withRule(validationEmail -> Collections.disjoint(validationEmail.domainParts(), invalidDomains));
    return validator.isValid(email);
    }
}

你可以很容易地测试这一点。

@Test
void validateEmail() {
  MyEmailValidator validator = new MyEmailValidator();
  assertTrue(validator.validateEmail("[email protected]"));
  assertFalse(validator.validateEmail("[email protected]"));
}