https://github.com/Cydeo-Alumni/JavaProgrammingFastTrack7.git
Day 01:
How is your java experience?How do you rate your java skill? Do you have experience with java? etc
I have 5 years of java programming experience. I used java for building automation frameworks and test automation development. I am comfortable with core java, flow control, string manipulation, collections, Object oriented programming, exception handling, debugging using java.
Why did you choose java for automation?
Java is high level object oriented language. It is platform independent It has many open source libraries for test automation. JUnit, TestNG, Selenium , JDBC, RestAssured etc It is a popular language for web backend , mobile development, so using java for automation is makes it in sync with developer environment.
Which java version? I used java 8 mostly in my automation projects. Switched to java 11 in current project.
Jdk, jre, jvm?
Jdk - Java dev kit -> is needed for java development. It contains compiler and JRE, JVM.
JRE -> Java runtime environment -> used to run compiled java code(bytecode), uses JVM to run
JVM -> java virtual machine -> used to run java compiled bytecode
================ Explain main method: public static void main(String[] args)
Main method, is called by Jvm to start execution of java program.
public -> access modifier, can be accessed from anywhere static -> method can be called without creating object void -> does not return any value main -> method name String[] args -> String array parameter where we can pass values to main method
============== Explain: System.out.println("Hello World");
System is a class in java.lang package out -> static variable of PrintStream type: public static final PrintStream out println -> is a void method in PrintStream class "Hello World" -> is a input to be printed out
println is overloaded method, so we can pass all kinds of inputs. Ex: System.out.println("Hello World"); System.out.println(333);
Data types: primitives and non-primitives byte, short, int, long float, double char boolean
var type automatically detects data type for local variables. And need to initialize in same statement
var v = 10;
non-primitives -> are object types that comes from a class String, Scanner, ChromeDriver etc
Object class is root/parent class for all classes in java. public class Object {} can also be used as data type.
Object obj = new String("abc");
Sometimes, when we write a class, we want to be able to use for all types. In that case we can use Generic type.
What are Wrapper classes: Each primitive has a matching Wrapper class. Primitives are just values without any behaviour. Wrapper classes add behaviour to primitives also ability to become an object. We can use wrapper types with java collections. Java collections does not work with primitives. Only array can work with both
byte -> Byte short -> Short int -> Integer long -> Long float -> Float double -> Double char -> Character boolean -> Boolean
=======================
//compare 2 numbers System.out.println("larger int = " + Integer.max(10, 5)); System.out.println("sum of double = " + Double.sum(4343.2, 12.4));
//convert from String to wrapper type: String strAge= "44"; int age = Integer.parseInt(strAge); Integer age = Integer.valueOf(strAge);
=======================
Autoboxing vs Unboxing?
Autoboxing -> converting from primitive to wrapper object Integer i = 11;
What do you do if you have a really large number that is not fitting LONG?
BigInteger, BigDecimal types can be used for really large numbers that we cannot predict.
Casting primitives.
converting from one type to another:
from byte to int from int to short byte n1 = 11; int n2 = n1; //cast from small to large automatically
Variables: local vs instance?
local variable declared inside the method or a block. and scope is limited to that block.
instance variable declared inside the class, outside the methods.
scope is whole class
=======================
DAY 02:
Operators: -arithmethmetic/math(+,-,/,%,*) -shorthand, unary (+=, -=, ++, --) -> pre , post increment/decrement pre -> ++n; post -> n++;
-comparison -> >, <, !=, == etc -logical -> &, &&, |, ||, !, ^
XOR operator ^ -> returns true only when conditions are different.
if both conditions are same, it will return false.
boolean a = true; boolean b = false; a ^ b => true
Conditional statements:
-
if statements
-
switch
-
ternary ----=
-
if(conditionA) { //code to run when A is true } else if(conditionB) { //code to run when B is true } else if(conditionC) { //code to run when C is true } else { //code to run when all above are false }
if(conditionA) { if(conditionB){ //code B }else { //Code C } //code D } else { Code E }
switch(variable) { //String, int, Enums case 1: //code to run when case 1 is match break; case 2: //code to run when case 2 is match break; default: //when all cases mismatch }
=======================
var myVar = (conditionA) ? value when true : value when false
String str; if(conditionA) { str = value when true } else { str = value when false }
=======================
When to use: if statements are most flexible, and can be used with all kind of conditions. paired with logical operator. ||, && etc, >, <
if(a > b || a < c) {
}
we can use switch when we are comparing if variable EQUALS certain values. cannot handle other types of comparisons
switch(a) {
case "ABC":
//code
break;
case "RRT12":
//code
break;
}
ternary can be used to replace basic simple if else statement.
===============================
LOOPS in java:
while, do while, for loop, for each loop
we can have nested loops
forEach method can also be used with collections
while(conditions is true) { //keep running this code }
do { //Do this once, then keep doing while condition is true }while(conditions is true);
while vs do while?
while loop checks condition first and runs loop block code if true.
do while runs loop block code once, then checks if conditions is true.
for loop with iterator, can be used when we know number of iterations beforehand.
for(int i = 0; i <= 100; i++) { //loop code }
for each loop is used with arrays, collections. it will start from first element until the last element.
int[] nums = {43, 123, 53};
for(int n : nums) { println(n); }
String[] strs = {"43", "123", "53"};
String: String is a class in java lang package. String can store "value" in double quotes, and uses final char[] array internally.
String pool is an area in Heap memory where string objects are stored and can be reused.
String a = "java"; String b = "java"; "java" is created in String pool, since we are using double quotes to create a String. One object is created and reused
if(a == b) ==> true. both are pointing to same object in string pool
String a = new String("java"); String b = new String("java");
We are using NEW keyword, 2 objects are created outside String pool.
a == b ==> false because a and b are referring to different objects.
================
DAY 04:
Methods: -> when I am assigned automation task during sprint planning. -> analyze -> make sure steps, and acceptance criteria is CLEAR. Ask from BA, Dev, other team member if not clear -> in progress: -> test manually, if any bugs, report them. Most bugs can be caught here -> testing manually: make it more clear about functionality, test data requirements, steps etc deeper. -> start automation: -> look at framework and see if any similar scenario was automated before -> look at any steps in this scenario are common to other tests that were automated before -> if yes, look at what REUSABLE methods, utilities, page object elements/methods can be reused. -> When writing doing automation development, please focus on reusability.
COMMAND/CTRL+SHIFT+F -> global search in IntelliJ
Methods:
Help create reusable code Void -> performs actions, does not return value. -> Ex: setter method
Method that with or without parameters.
Void + no params: public static void m1() {}
Void + with params: public static void m2(String str, int num){}
Return + no params: public static int m3(){ return 2024; }
To make our code more Reusable => methods: -> general reusable methods(reverseString )/utility methods: configReader etc -> application specific reusable methods(page object methods)
Naming of methods: -> code readability. -> make sure method, and variable names are in alignment of naming conventions in your project
Method overloading:
2 or more methods with SAME NAME, DIFFERENT PARAMETERS.
DIFFERENT: data types of params, number of params, or order of params different
public void m1(){} public void m1(String str){} public boolean m1(boolean bl){} public boolean m1(int n1, int n2){} public boolean m1(double n1, int n2){} public boolean m1(int n2, double n1){}
Once we overload, return type can be different.
public void m1(){} public int m1(String str){}
Error below, because we cannot just change the param without properly overloading. public void m1(){} public int m1(){}
Error, we look at variable parameter types and count. Variable names does not matter. public void m1(int n1, int n2){} public void m1(int n2, int n1){}
IQ: Is java pass by value or pass by reference?
Java is pass by value, it copies the value to method parameter.
Ex: main { int n = 55; add5(n);//int num = n; println(n); //55 }
public static void add5(int num) { num = num+5; //60 }
================
Array/Object example:
Array is an object with multiple value stored.
When we pass the array, we copy the reference to that object.
So inside the method:
- reassign new array object. -> it does not affect to original array
- change existing values of array -> it effects original as well because they are both pointing to same object
int[] nums = {3,2,6}; addExtraNum(nums); println(Arrays.toString(nums)); // no change 3,2,6
increaseNum(nums); println(Arrays.toString(nums));//changes 13,2,6
//reassign new array object. public static void addExtraNum(int[] nums) { nums = new int[]{3,2,6,9}; }
Java review Day 05:
• Can you run a program without the main method? We can use test frameworks like JUnit, TestNG and @Test annotation. So it will help run the test and we do not need to add a main method. In Cucumber framework, CucumberRunner can be used to initialize execution. Internally they invoke main method.
-Can you overload the main method? Yes, we can by changing the parameters. however it is no longer a runner method that Jvm will invoke
public static void main(int[] args) {
}
-Why is the main method static? So that method can be called without creating an object of the class.
-Why is there a String[] parameter? This is to be able to pass runtime arguments. Usually from command line or IDE run configurations.
================
DAY 06: For each loop: Useful while iterating over arrays and other collections.
for(dataType var: collection) {
}
=================
Multi-Dimensional array:
An element of an array is another array. Normally we could use 2D array in dataProvider method in TestNG
String[][] users = { {"user4433", "abc442"}, {"user1133", "ade442"}, {"userdd33", "a12442"} };
We could also copy webtable data from webpage to 2D array using Selenium and xpath.
============
Var-Args:
It is used as parameter to a method, and adds ability to pass multiple values seperated by comma. Inside the method, Var-args parameter will be treated as regular array.
public static void m1(int... nums) { //nums is used as an array }
m1(32,1,2) m1() m1(23,34,34,545,134,66,56,57)
================================
Array vs ArrayList?
Array is fixed size, we cannot resize once we create the object
ArrayList is dynamic size, we can add or remove elements
Array can contain Primitives and objects(non-primitives) ArrayList is part of collections framework and can contain only objects(non-primitives)
ArrayList uses arrays internally.
Recursion:
When a method calls itself, it is a recursive method.
Normally in test automation development, we do not use this approach, instead we use loops.
m1(4); 4 3 2 1 0 -1 public static void m1(int num) { System.out.println(num); m1(num-1); }
We always need to add breaking/stopping condition to prevent infinite loop.
public static void m1(int num) { System.out.println(num); if(num > 0) m1(num-1); }
==================
Class and Object
Class is a blueprint for an object We define data and behaviour of object in a class
We can create instance or object from a class using new keyword.
public class Car { String make; public void drive(){...} } Create object/instantiate: Car car = new Car(); car.make = "Honda"; car.drive();
Instance vs static variables
instance variables belong to objects and each object will have its own copy of variables.
static variables belong to class directly and the value is shared by all objects. it has single copy. We can access static variables without creating an object.
Constructor: Is a method in a class that automatically runs when we create object of the class. It has same name as classname, no return type. We can add parameters to constructors. We can overload constructors
Constructor chaining: we can call one constructor from another constructor using THIS keyword.
public class A{ public A() { this("hi"); }
public A(String str) {
println(str);
}
this vs this():
this. is used to refer to instance of the object and instance variables and methods Usually used to differentiate between local and instance variables: this.name = name;
this() -> is used for chaining constructors. calling one constructor from another one.
======================
static block vs instance init block?
static block runs once before anything else when the class is loaded(whenever we use the class)
Inheritance:
Sub/child class inherits variables and methods from super/parent class.
It helps with reusability and design
IS-A relationship is inheritance Child class IS-A Parent class
Student IS-A Person
public class Person {//var, methods}
Has-A relationship -> it is when a class has instance variable of type of different class. Also called Composition
public class House { Address address; }
What is inherited ?
Depends on access modifiers:
Public,Protected -> always inherited Default -> inherited if in same package private -> is not inherited Constructors are not inherited Final classes cannot be inherited.
Access modifier: Public -> visible to everyone protected -> visible to everyone in same package and sub classes in other packages default -> package private. visible to everyone in same package private -> visible to same class only
==========================
Inheritance and constructors:
Super class - Sub class
When we create object of Sub class, Super class constructor runs first.
public class A { public A() { System.out.println("A"); } }
public class B extends A { public B() { super(); //compiler adds super class constructor call System.out.println("B"); } }
A a = new A();==> "A"
B b = new B();==> "A" "B"
public class A { public A(String str) { System.out.println("A => " + str); } }
public class B extends A { public B() { //super();//not compile because no-args constructor is not present super("hi"); System.out.println("B"); } }
super vs this:
super keyword is used to reference parent class object and call parent class members.
this keyword is used to reference currunt class object and used to call current class members.
public class A {
public String name = "A name";
public A(String str) {
System.out.println("A => " + str);
}
}
public class B extends A {
public String name = "B name";
public void printName() {
System.out.println(name);//"B name"
System.out.println(super.name);//"A name"
}
public B() {
//super();//not compile because no-args constructor is not present
super("hi");
System.out.println("B");
}
this() vs super()
this() -> is used to call another constructor in same class
super() -> is used to call parent class constructor from child class constructor.
both statements need to be first in the constructor.
public class A { public A(String str) { this(); //optionally I can add this keyword System.out.println("A => " + str); }
public A() {
System.out.println("A");
}
}
public class B extends A { public B() { super(); System.out.println("B"); }
public B(String str) {
super(str);
//this(); will not compile as it needs to be first statement
System.out.println("B => " + str);
}
Are static members(variables and methods) inherited or no?
If access modifier allows, static members are inherited.
public class A { public static String name = "John"; }
public class B extends A {
}
Method overriding:
When a method is inherited to a sub class, we can change the implementation to customize for sub class. This process is called method overriding.
method overriding -> changing the implementation of inherited method in a sub class
We can only override inherited method. Method name and paramethers MUST be same.
public class A { public void m1() { println("A class m1") } }
public class B extends A { @Override public void m1() { println("B class m1") } }
final methods that are inherited cannot be overridden. final methods are used to prevent overrriding
Overriding rules: -> Method name and parameters must be same -> access modifier can be same or most visible: -> public -> public -> protected -> protected,public -> default -> default,protected,public -> private -> not inherited.cannot override
-> return type:
-> same or covariant(sub class)
-> void -> void
-> String -> String
-> Person -> Person, Student, Teacher, Sdet
public class Student extends Person {
} public class Teacher extends Person {
} public class Sdet extends Person {
}
public class A { public Person m1() { Person p1 = new Person("Mike"); return p1; } }
public class B extends A { @Override public Student m1() { Student st = new Student(); return st; } }
Method overriding vs method overloading?
overriding -> method name must be same overloading -> method name must be same
overriding -> method parameters must be same overloading -> method parameters must be different
overriding -> access modifier can be same or more visible overloading -> access modifier can be different
overriding -> return type must be same or sub type(covariant) overloading -> return type can be different
Method overriding -> 2 methods with SAME name and SAME parameters. Used in inherited method
In Automation: Method overloading can used in page object classes. public class LoginPage { //weblements public void login(String role) { //switch (role){ case "admin" : case "guest" : } }
public void login(String userName, String password) {
//switch (role){
case "admin" :
case "guest" :
}
}
}
In Util methods DbUtil. read value from column name or column index number.
===============================
Overriding: can also be used in page objects.
public class BasePage { //common elements and methods here public void closePopUp() { //close sign up for news popup } }
public class InstructorsPage extends BasePage { public void closePopUp() { //close sign up for jobs notification popup //this one can be different, close button locator is different etc } }
public class TestBase { @Before public void setUp(){ //general set up. goto homepage }
public void verifyText(String exp, String act){}
}
public class SearchTests extends TestBase { @Before public void setUp(){ super.setUp(); //specific set up for page, novigation etc } @Override public void verifyText(String exp, String act){ //some extra string manipulation steps then compare } } public class SearchApiTests extends TestBase { @Before public void setUp(){ //specific set up for page, novigation etc } }
Method hiding: -> static methods are hidden, not overridden. -> based on where we can the method, it will refer to closest one
public class A { public static void m1() { println("A - m1"); }
public void m2() {
m1();
}
} public class B extends A { public static void m1() { println("B - m1"); } public void m3() { m1(); } }
Variable hiding: We cannot override inherited variables, we can only hide them.
public class A { int num = 10; public void m2() { println(num); } } public class B extends A { int num = 30; public void m3() { println(num); println(super.num) } }
Exceptions in java:
In Java exceptions are objects. They have certain hierarchy. Throwable is parent of all exceptions and errors. Exception is parent of all checked exceptions RuntimeException is parent of all un-checked exceptions
checked vs unchecked?
checked also called compile time exception, need to be handled or declared for code to compile.
Ex: SQLException, IOException, FileNotFoundException etc
unchecked also called Runtime exceptions, happen during runtime of code, they are optional to handle, normally we need to prevent them.
Ex: NullpointerException, Outofbounds, NoSuchElement, StaleElementException,
=======================
CheckedExceptions
Thread.sleep(3000);
It throws a checked InterruptedException. So we have two options:
- handle using try catch
try { Thread.sleep(3000); }catch (InterruptedException e) { e.printStackTrace(); }
- Unchecked : StringIndexOutOfBounds Exception
String str = "exception"; System.out.println(str.charAt(55));
Above lines will compile and throw exception during runtime.
in below example, even though api call does not have CHECKED exception, I am using try catch to prevent RuntimeException. Because I am not in control of API service in this case.
class SMSVerificationService { public static String getSmsCode(int accountId) { try{ Api call to endpoint adn extract sms code and return }catch(RuntimeException e) { return ""; } } }
Day 08:
Handling exceptions:
try{ //code }catch(Exception e) { e.printStackTrace(); e.getMessage() ==> print }
try{ //code }catch(Exception e) { e.printStackTrace(); e.getMessage() ==> print }finally { //code always runs, error or no error }
try{ //code that might throw exp, but we dont want to handle }finally{ //code always runs }
try{
}catch(NullpointerException e) {
}catch(RunTimeException e) {
throw vs throws: -> throw is used to create exception manually. if(age < 18) { throw new IllegalArgumentException("age is too low"); }
throws -> is used to declare exception in method signature
For checked exceptions, we either handle using try catch, or declare using throws.
=========================
final, finally, finalize()
final: final variable -> constant variable, cannot change value final method -> cannot override in sub class final class -> cannot extend to other classes
finally -> is block in exception handling, that contains code that always runs, exception happens or no. -> System.exit(0) or some memory error etc
Encapsulation: data hiding, making variables/data private and providing public getter and setters.
==========================
Abstraction -> is focusing on what todo instead of How todo.
In java: -> abstract class -> interface
Abstract class : -> abstract keyword is used -> cannot create object -> methods -> can have abstract, non abstract methods, constructors , blocks -> variables -> all types: instance , static, final etc -> class can extend only one abstract class
Interface: -> interface keyword -> cannot create object -> methods: PUBLIC abstract, static , default methods -> variables -> Public static final variables only -> class can implement multiple interfaces
What is difference between abstract class and interface?
-Both are used to achieve Abstraction in java.and cannot create object -Class can extend one abstract class and can implement multiple interfaces. -methods: abstract class -> can have abstract, non abstract methods, constructors , blocks interface -> PUBLIC abstract, static , default methods -variables: abstract class ->all types: instance , static, final etc interface -> Public static final variables only
How to achieve multiple inheritance in java?
In java , a sub class can inherit/extend only one super class.
So java does not support multiple inheritance for classes. We can use multiple inheritance with interfaces, a sub class can implement multiple interfaces.
public abstract class A {
}
public interface B{
}
public interface C{
}
public interface E extends B, C{
}
public abstract class A implements B{ public abstract void mA1();
}
public interface B{ public abstract void mB1(); }
public interface C{
}
public interface E extends B, C{
}
First Non-abstract class/concrete class is responsible for implementing all inherited abstract methods from abstract classes or interfaces.
===========================================
polymorphism: ability of object to take many forms:
reference type for object can be parent class or parent interface.
Person p1=new Student();
object is student
reference is parent class
==================================
public class A {} public class B extends A {} public class C extends B {}
public class A { int num = 10; public void m1() { println("A-m1"); } } public class B extends A { int num = 20; String str = "java"; public void m2() { println("B-m2"); } @Override public void m1() { println("B-m1"); } }
A a = new B(); println(a.num); => 10 a.m1(); => "B-m1"
public interface WebDriver{ get,findElement, close, quit } public interface TakesScreenshot{ getScreenshotAs(..).. }
public class ChromeDriver implements WebDriver,TakesScreenshot
WebDriver driver = new ChromeDriver(); driver.get(url) Error: driver.getScreenshotAs()
So we need to downcast to TakesScreenshot.
((TakesScreenshot)driver).getScreenshotAs();
TakesScreenshot screenshotDriver = (TakesScreenshot)driver; screenshotDriver.getScreenshotAs(A); screenshotDriver.getScreenshotAs(B);
=======================================
IQ: how can you handle large of amounts of Data?
In my project, there are modules that generate large amount of data in different formats.
I normally analyze the data formats that i am working with, and choose the most efficient approach.
Pojo/model class with Java collections.
If I can implement POJO classes/Model to match the data I am working with, I add model/pojo classes and use java collections to manipulate large amount of data.
Data pipeline: JanusGraph --> Format using pojo and collections -> kafka -> Datascience team score -> kafka -> Format using pojo and collections -> elastic search database -> Client companies
Big data -> millions of records Big data ETL tools -> Hadoop, Spark, Informatica etc Data engineering
================================================
IQ:Common question different between Collection / Collections
Collection is an interface is parent interface for List, Set, Queue. It contains common methods for all collection types like add, remove, size etc
Collections is a utility class that has useful methods when working with collections like sort, binarySearch, reverse, max, min etc
List: -> preserves insertion order -> allows duplicates -> get read values using indexes -> allows null values
List has several implementations: ArrayList -> resizable array, most common we use, based on array internally. Vector -> is also resizable array but it is syncronized linkedList -> based on nodes connected to each other. node: its value , prev and next reference. if prev is null and next is not -> we are at beginning node(index 0) if prev is not null but next one is null -> we are at the end. index is length()-1
which one to use LinkedList or Arraylist?
ArrayList is more commonly used.
Reading: get(5) -> arraylist -> faster -> Time complexity O(1) -> linkedList -> slower -> Time complexity O(n): Unless first or last then O(1)
Adding: add(value) or add(index, value) ->arraylist -> O(1) if arrays does not need to be resized. O(n) if needs to be resized(common) ->linkedList -> O(1) addFirst, addLast. inserting to middle is O(n)
Remove: remove(Elem): -> arraylist -> O(n) -> needs to remove and resize array -> linkedList -> O(1) -> if first or last elements. O(n) -> all other elements
Big O notation describes time and space complexity time complexity how long it takes for code to run based on input
space complexity - how much memory it will take
O(1) -> regardless how much input we have , it takes same exact time O(n) -> depending on input, time it takes to complete also grows
SET -> collection of unique values
-> does not allow duplicate data
-> does not preserve insertion order
-> allow null value
-> no indexes
Implementations: Hashset -> most common implementation. ex: Selenium window handles
LinkedHashSet -> preserves insertion order
TreeSet -> implements SortedSet-> sorts values