如何避免泛型方法clickSubMenuItem返回null?求最优解决方案
I don't want my function to return null, what's the optimal solution? Here's my code:
public <T extends BasePage> T clickSubMenuItem(MenuBar menuBar) { int hoveredMenuItemIndex = mouseOverToMenuItemByTitle(menuBar.menuOptionTitle); if (hoveredMenuItemIndex > -1) { allSubMenuItem = getWebElements(By.cssSelector("#topnav > .rootmenu > li:nth-child(" + hoveredMenuItemIndex + ") > ul > li > a")); for (WebElement subMenuItem : allSubMenuItem) { if (subMenuItem.getAttribute("title").contains(menuBar.subMenuTitle)) { subMenuItem.click(); return instantiatePageClass(...); } } } }
Option 1: Throw a specific exception (Fail-Fast approach)
This is usually the best choice when failing to find/click the submenu is an unexpected error condition (i.e., the submenu should always exist if the input is valid). By throwing an exception, you make the failure explicit instead of silently returning null, which helps catch bugs early.
Modify your code like this:
import org.openqa.selenium.NoSuchElementException; public <T extends BasePage> T clickSubMenuItem(MenuBar menuBar) { int hoveredMenuItemIndex = mouseOverToMenuItemByTitle(menuBar.menuOptionTitle); if (hoveredMenuItemIndex == -1) { throw new NoSuchElementException("Could not find menu item with title: " + menuBar.menuOptionTitle); } allSubMenuItem = getWebElements(By.cssSelector("#topnav > .rootmenu > li:nth-child(" + hoveredMenuItemIndex + ") > ul > li > a")); for (WebElement subMenuItem : allSubMenuItem) { if (subMenuItem.getAttribute("title").contains(menuBar.subMenuTitle)) { subMenuItem.click(); return instantiatePageClass(...); } } // If we reach here, no matching submenu was found throw new NoSuchElementException("Could not find submenu item with title containing: " + menuBar.subMenuTitle); }
Note: You can either use Selenium's built-in NoSuchElementException or create your own custom exception (e.g., SubMenuItemNotFoundException) for better error clarity.
Option 2: Return Optional<T> (Explicit null handling)
If it's a valid scenario that the submenu might not exist (and you don't want to throw an exception), returning Optional<T> makes it clear to the caller that the result could be absent. This forces the caller to handle the empty case explicitly, avoiding null pointer exceptions downstream.
import java.util.Optional; public Optional<T> clickSubMenuItem(MenuBar menuBar) { int hoveredMenuItemIndex = mouseOverToMenuItemByTitle(menuBar.menuOptionTitle); if (hoveredMenuItemIndex > -1) { allSubMenuItem = getWebElements(By.cssSelector("#topnav > .rootmenu > li:nth-child(" + hoveredMenuItemIndex + ") > ul > li > a")); for (WebElement subMenuItem : allSubMenuItem) { if (subMenuItem.getAttribute("title").contains(menuBar.subMenuTitle)) { subMenuItem.click(); return Optional.of(instantiatePageClass(...)); } } } return Optional.empty(); }
Callers would then use it like:
// Handle the present case clickSubMenuItem(menuBar).ifPresent(page -> { // Do something with the page instance }); // Or get a default value if empty BasePage fallbackPage = clickSubMenuItem(menuBar).orElseGet(DefaultPage::new);
Option 3: Return a default page instance (Only if business logic allows)
If there's a meaningful default page to return when the submenu isn't found, you can return that instead of null. However, this is only recommended if the default behavior is clear and expected—avoid this if returning a default could mask real errors.
public <T extends BasePage> T clickSubMenuItem(MenuBar menuBar) { int hoveredMenuItemIndex = mouseOverToMenuItemByTitle(menuBar.menuOptionTitle); if (hoveredMenuItemIndex > -1) { allSubMenuItem = getWebElements(By.cssSelector("#topnav > .rootmenu > li:nth-child(" + hoveredMenuItemIndex + ") > ul > li > a")); for (WebElement subMenuItem : allSubMenuItem) { if (subMenuItem.getAttribute("title").contains(menuBar.subMenuTitle)) { subMenuItem.click(); return instantiatePageClass(...); } } } // Return a default page instance (cast if needed) return (T) new DefaultPage(); }
Which one to choose?
- Go with Option 1 if missing the submenu is an error that should halt execution and be fixed.
- Go with Option 2 if missing the submenu is a normal, expected scenario that callers need to handle.
- Use Option 3 sparingly, only when a default page makes sense for your application's flow.
内容的提问来源于stack exchange,提问作者Monika

