Java for SDET

47Java for SDET

What you will master here

  • OOP pillars with test-framework examples
  • Overloading vs overriding; abstract class vs interface
  • Access modifiers, final, static
  • Collections: List/Set/Map, ArrayList vs LinkedList, HashMap internals
  • Generics, exceptions (checked vs unchecked), try-with-resources
  • Streams + lambdas — filter/map/collect on test data
  • String immutability, equals/hashCode contract
  • Threading basics; ThreadLocal for parallel WebDriver

47.1 Why Java for SDET

Java is the lingua franca of enterprise test automation. Selenium, REST Assured, TestNG/JUnit, Cucumber-JVM, Allure — all assume a JVM. Understanding the language well separates someone who copies WebDriver snippets from someone who designs maintainable frameworks.

47.2 The four OOP pillars

Encapsulation

public class LoginPage {
  private final WebDriver driver;
  private final By userField = By.id("user");
  public LoginPage(WebDriver driver) { this.driver = driver; }
  public DashboardPage login(String u, String p) {
    driver.findElement(userField).sendKeys(u);
    /* ... */
    return new DashboardPage(driver);
  }
}

Inheritance

public abstract class BasePage {
  protected final WebDriver driver;
  protected BasePage(WebDriver driver) { this.driver = driver; }
  protected void waitVisible(By l) { /* shared */ }
}
public class LoginPage extends BasePage {
  public LoginPage(WebDriver d) { super(d); }
}

Polymorphism — overloading vs overriding

Overloading (compile-time)
void click(By l) { ... }
void click(WebElement el) { ... }
void click(By l, int t) { ... }
  • Same name, different parameters
  • Resolved at compile time
Overriding (run-time)
class BaseTest { void setup() {} }
class ApiTest extends BaseTest {
  @Override void setup() { /* replaces */ }
}
  • Same signature, subclass replaces parent
  • Resolved at run time (dynamic dispatch)

Abstraction — abstract class vs interface

AspectAbstract classInterface
Instantiable?NoNo
State (fields)YesConstants only
ConstructorsYesNo
Multiple inheritanceOne superclassImplement many
MethodsAbstract + concreteAbstract + default/static (Java 8+)

47.3 Access modifiers

ModifierSame classSame packageSubclassEverywhere
public
protected
default (package-private)
private

47.4 Collections

TypeBacked byOrderDuplicatesBest for
ArrayListresizable arrayinsertionYrandom access reads
LinkedListdoubly-linked nodesinsertionYO(1) head/tail ops
HashSetHashMap (keys)noneNfast membership
LinkedHashSetlinked HashMapinsertionNordered uniqueness
TreeSetRed-Black treesortedNsorted set
HashMapbuckets + chainingnoneN (keys)O(1) key lookup
LinkedHashMap+ linked listinsertionN (keys)LRU caches
TreeMapRed-Black treesortedN (keys)sorted map / range queries
ConcurrentHashMapstriped locknoneN (keys)thread-safe map

HashMap internals (must know)

47.5 Generics

public class Stack<T> {
  private final List<T> data = new ArrayList<>();
  public void push(T x) { data.add(x); }
  public T pop() { return data.remove(data.size() - 1); }
}

// Bounded
public <T extends Comparable<T>> T max(List<T> xs) {
  return xs.stream().max(Comparable::compareTo).orElseThrow();
}

// Wildcards
List<? extends Number> numbers;        // read-only (covariant)
List<? super Integer> integers;        // write-only (contravariant)

47.6 Exceptions

TypeWhenMust catch?
Checked (Exception, IOException, SQLException)Recoverable conditionsYes — declare or catch
Unchecked (RuntimeException, NullPointerException)Programming errorsNo — but should fix
Error (OutOfMemoryError, StackOverflowError)JVM-level fatalDon't catch
// try-with-resources — auto-closes
try (Connection c = DriverManager.getConnection(url);
     PreparedStatement ps = c.prepareStatement(sql)) {
  /* use */
} catch (SQLException e) {
  throw new RuntimeException("DB failed", e);
}

47.7 Streams + lambdas

List<User> admins = users.stream()
  .filter(u -> u.role().equals("admin"))
  .sorted(Comparator.comparing(User::createdAt))
  .collect(Collectors.toList());

// Group by
Map<String, List<User>> byRole = users.stream()
  .collect(Collectors.groupingBy(User::role));

// Reduce
int total = orders.stream().mapToInt(Order::total).sum();

// Parallel — be careful
long count = bigList.parallelStream().filter(predicate).count();

47.8 String immutability + equals/hashCode

String a = "hello";
String b = "hello";
a == b;          // true — string pool
a.equals(b);     // true — value comparison
new String("hello") == "hello";   // false — different object

// Always use .equals() for content comparison
"alice".equals(user.name());

// equals/hashCode contract for custom classes
@Override public boolean equals(Object o) {
  if (this == o) return true;
  if (!(o instanceof User u)) return false;
  return Objects.equals(email, u.email);
}
@Override public int hashCode() { return Objects.hash(email); }

47.9 Threading + ThreadLocal for WebDriver

// Each thread gets its own WebDriver instance — required for parallel TestNG
public class DriverFactory {
  private static final ThreadLocal<WebDriver> driver = new ThreadLocal<>();
  public static void set(WebDriver d) { driver.set(d); }
  public static WebDriver get() { return driver.get(); }
  public static void remove() {
    WebDriver d = driver.get();
    if (d != null) d.quit();
    driver.remove();
  }
}

Module 44 — Java Q&A

Difference between overloading and overriding?
Overloading: same method name, different parameters, resolved at compile time (static dispatch). Overriding: subclass replaces parent's method with same signature, resolved at run time (dynamic dispatch).
Abstract class vs interface?
Abstract class can have state (fields), constructors, and a mix of abstract + concrete methods; single inheritance. Interface defines a contract — constants + abstract methods (+ default/static since Java 8); a class can implement many. Use abstract for shared state, interface for capability contracts.
ArrayList vs LinkedList?
ArrayList — backed by resizable array; O(1) get by index, O(n) insert in middle. LinkedList — doubly-linked nodes; O(1) head/tail ops, O(n) get by index. For most SDET use cases ArrayList wins (better cache locality).
How does HashMap work?
Array of buckets; key's hashCode picks the bucket. Collisions chain as a list, converted to a tree if length > 8 (Java 8+). Load factor 0.75 triggers rehash. equals + hashCode contract: equal objects must have equal hash codes; unequal can have same hash (collision).
Checked vs unchecked exceptions?
Checked extend Exception (not RuntimeException) — compiler forces declaration or catch (IOException, SQLException). Unchecked extend RuntimeException — represent programming errors; no compiler check. Use checked for recoverable, unchecked for bugs/preconditions.
What is try-with-resources?
Syntax that auto-closes anything implementing AutoCloseable when the block exits (normally or via exception). Replaces verbose finally blocks for closing files, connections, streams.
Why is String immutable?
Thread-safety, hash-code caching, string interning (pool reuses identical literals), and security (can't change a String passed to a sensitive API after the check). Use StringBuilder for mutable strings.
equals/hashCode contract?
If a.equals(b) then a.hashCode() == b.hashCode() MUST be true. Reverse not required (collisions exist). Break the contract and HashMap/HashSet behave incorrectly for your type.
What's ThreadLocal and why does Selenium need it?
Storage that holds a value per thread — calls from thread A see only A's value. Selenium WebDriver is not thread-safe; for parallel TestNG runs, each thread must hold its own driver. ThreadLocal<WebDriver> is the canonical pattern.
What does final mean on a class/method/variable?
final class — can't be subclassed. final method — can't be overridden. final variable — can be assigned only once (reference; object contents may still mutate). Constants are public static final.
What's the difference between == and .equals() for objects?
== compares object references (same instance). .equals() compares logical equality if overridden. Always use .equals() for content. String literals share the pool so == may accidentally seem to work — don't rely on it.
What's a Stream and how is it different from a Collection?
A Collection holds data. A Stream is a pipeline of operations on data — lazy until a terminal operation runs. Streams support functional operations (filter, map, reduce) and can be parallel. Consumed once; not re-iterable.
When would you use ConcurrentHashMap over HashMap?
When multiple threads read/write the same map concurrently. ConcurrentHashMap uses lock striping for high throughput; HashMap is not thread-safe and corrupts on concurrent writes. Collections.synchronizedMap exists but is slower (single global lock).
What are generics for?
Type-safety at compile time without code duplication. List<User> guarantees only User can be added. Erasure means generics disappear at runtime — but the compiler catches type errors that would have been runtime ClassCastException.