- Source Code: .java file -> Compiled to .class file (bytecode) using
javac
- This .class file can only be run by a JVM unlike the
./a.out
files in C/C++
- Each .java file is only allowed to have a single class that matches the name of the file
- Only one public class allowed per file and the name of this public class is the name of the file
- The
main()
method of this class is the entry point of the execution
- Java needs to have packages because you can't import from "path" (e.g,
import libA from "./myLib"
) like you do in JS - The folders are literally packages, without any extra setup
- Folder structure:
"folderA/folderB/myFile.java"
- How to import:
import folderA.folderB.myFile
- Made up of snippets, ( each statement is a snippet )
- Can execute code directly without making classes for everything
- A snippet is a: statement, class declaration, method declaration , etc
- Each snippet has an identified
$12
,$13
, etc - Any snippet written in past can be edited by either re-declaring the method / class contents or by using the
/edit id
command whereid
is the$id
identifier
- Fields are class properties, two types of fields
- Non Static Fields ( instance variables )
- Static Fields ( Class Variables )
- Variables are:
- **Local Variables ( the variables used inside methods ) **
- Method Parameters
- byte (8 bits)
- short ( 16 bits )
- int ( 32 bits )
- long (64 bits)
- float ( IEEE 754 , 32 bits )
- double ( IEEE 754, 64 Bits )
- boolean
- char (16 bit Unicode)
Primitive Data types cannot be set to NULL
Literals for int, long, float, double: I, L, F, D
Declaring hex and binary variables: 0xFD126, 0b10111
Numbers can be seperated by _
int[] array
int[]
is the array data type
array = new int[10];
int[] arr = {1,2,3,4};
Use the java.util.Arrays
class extensively for methods to manipulate arrays
- java.util.Arrays.binarySearch(int[] a, int key) -> returns index otherwise
(-(insertion point) - 1)
where insertion point is the index of the element where the element WOULD have been present if it was existing
-
if
a = -b - 1
thenb = -a - 1
-
java.util.Arrays.sort()
-
java.util.Arrays.fill()
-
java.util.Arrays.toString(): prints array as a string
-
java.util.Arrays.asList() to convert array to list
- Checks if a given object is an instance of a class, sub class or an extending interface
- Left Shift: Moves bits to left and fills empty places with 0
- Right Shift (>>): Moves bits to right and
- Fills empty spaces with 0 if it's a positive number
- FIlls empty spaces with 1 if it's a negative number
- Right Shift ( >>>): Fills empty spaces with 0 no matter what
mylabel: for(int i = 0....)
while breaking: break mylabel;
while continuing: continue mylabel;
`public void methodName(Object... params) {
params[0], params[1],.... are all Objects
}
`
- Primitives are passed by value
- References are also passed by value ( everything is an object/class in java so copying ka no chance)
this.new ClassName()
where this
is the context where the class ClassName
is defined
Eg, **Nested Class: **
class OuterClass {
class InnerClass {
}
}
To create an instance of the InnerClass
first, create an instance of the OuterClass
and using that context, create the InnerClass
instance
var o = new OuterClass();
var i = o.new InnerClass();
![[Pasted image 20230905183245.png]]
Here, Subclass refers to Subclass outside the package
Intuition: Just remember the order from the most lenient access to the most restriced one
These modifiers apply only to the Class Members and as far as class is considered, it only has either public
or no modifier
However, since nested classes are technically members of the parent class, they can have public
and protected
modifiers as well
- The intuition behind this is that anything
static
is something that the class executes Exactly Once and is not dependent on the instance - These
static {//code here}
blocks are executed in the order that they appear in the code
- There are three types of Classes
- Nested Class : Class Inside a Class ( Nested class can access outer class's members by using
OuterClass.this
) - Local Class : Class Inside a Method ( can access outer class in similar way, but the local variables of the method can only be accessed if they're
final
)
- Nested Class : Class Inside a Class ( Nested class can access outer class's members by using
- Each primitive type has a wrapper class with additional methods
byte byteValue()
short shortValue()
int intValue()
Intuition: since the method name has smallercase int, short, etc it must return the primitive
Integer.valueOf(int i)
Byte.valueOf(byte i)
Integer.valueOf(string i, int radix)
Integer a = Integer.valueOf(2);
a.toString()
Use the above four to convert from one to another
equals()
compareTo()
%d
for integer%f
for float%n
for newline- precision values are added before the letter
+
include the sign,
add commas- '10.3' total 10 letters and point has 3 digit precision
- Constants like
Math.E
andMath.PI
Math.abs()
,Math.ceil()
,Math.floor()
returndouble
and takedouble
Math.round()
returnsint
orlong
Math.min()
andMath.max()
Math.pow()
,Math.log()
,Math.exp()
,Math.sqrt()
Math.random()
double between 0 and 1
- Convert a character to a string ->
Character.toString(char c)
Character.isLetter()
Character.isDigit()
Character.isLetterOrDigit()
Character.toUpperCase()
Character.isLowerCase()
- The standard
String
class is immutable - length using
.length()
method - get character at index using
.charAt()
method - get substring by using the
subString(int begin, int end)
end is not included and if absent, substring is till end of the string - Other methods:
indexOf(string s)
,lastIndexOf(string s)
,contains(string s)
replace(String old, String new)
endsWith()
,startsWith()
,compareTo()
,equals()
Modifiable versions of Strings, instead of using the java string pool, they internally use a character array
1) StringBuilder sb = new StringBuilder(String s)
sb.toString();
append()
pushes any primitive type or object to the end of the stringdelete(int start, int end)
deletes these characters (start to end - 1)deleteCharAt(int index)
insert(int offset, data )
just like append but can insert anywhere in the SBreverse()
charAt()
-> same like the one inString
- For replacing and all, convert it to a standard string
Class A {}
class B extends A {}
// works
A ob = new B();
This only causes compile-time errors if the assigned type is not correct ( LHS type not matches RHS)
If the (className)
cast operator is used, then it tries casting the object at runtime and if it's not working, it just throws a RuntimeError
They can only have method signatures, too. If you want to implement a method in interface, you gotta use the default
keyword
If java could have inherited multiple classes, then all the fields of the classes would become mixed and the method would not know which field to take the value from
class A {
int a = 4;
void printA() {
println(a);
}
}
class B {
int a = 5;
void printB() {
println(a);
}
}
If some class C could inherit A and B, which field would it use of variable a?
Inheriting multiple interfaces is possible, cuz they only have static/final variables
- When inheriting from multiple interfaces how to know which
super
to use from? - ClassName.super.dfsf(), InterfaceName.super etc
- the
.equals()
method in objects compares only the references, i.e, if they're the same object
- Just because
Integer
is a sub-class ofNumber
doesn't mean thatArrayList<Integer>
is a sub-class ofArrayList<Numebr>
, they in-fact don't have any relation at all - two types of bounds
extends
andsuper
- Wildcard parameters are literally the same as using
T
instead of a?
but the only difference is :- the code is not polluted as
?
literally means, be any type idc - it's only possible to use the
super
bound while using a '?' wildcard'
- the code is not polluted as
- There is no such thing as a generic type during runtime, it's all converted into normal types and bounds are applied
- Can't create an array of parameterized types
- They're like quick and easy functions
- Java doesn't have the concept of functions, so lambdas are essentially a simpler way of writing a class that has only a single method, this acts as a function
- Such interface with a single method is known as
@FunctionalInterface
(Parameter1 p1, Parameter2 p2...) -> {
// block of code
}
The paranthesis are removable
Comparator<String> c = (s1, s2) -> Integer.compare(s1.length(), s2.length());
- Interface ( the functionality that you need in the collection) on the left side
- Class ( the way you need it be implemented ) on the right side
- All of the methods like subList, etc that return a new list, only return a view of it, and do not delete actual data from the collection
Interface on left, class on right
- List (Interface) -> ArrayList, LinkedList
- Set -> HashSet
- SortedSet,NavigableSet -> TreeSet
- Queue, Deque -> LinkedList
- Queue -> Priority Queue
- Map -> HashMap, LinkedHashmap
- NavigableMap/SortedMap -> TreeMap
add(element)
remove(element)
contains(element)
A.containsAll(B)
A.addAll(B)
A.removeAll(B)
A.retainAll(B)
.size()
isEmpty()
clear()
.removeIf(predicate)
Collections.min()
Collections.max()
Collections.reverse()
add(index, element)
get(index)
set(index, element)
remove(index)
indexOf(element)
lastIndexOf(element)
subList(start, end)
-> from start to end - 1
listObject.sort(comparator/null)
- prolly don't need to use Set, since sorted set is almost always better
- best implementation is using a
TreeMap
and passing a comparator lambda to it
first()
andlast()
headSet(a)
andtailSet(b)
-> think logically, [HHH------TTT] , the front part (lower elements) is head, and the rearer end (larger) elements is the tail, headSet returns from first element toa
but not includinga
- tailSet returns from
b
(including b) till the last element subSet(a, b)
returns a combination of a and bceiling(element)
-> something that is greater than or equal to elefloor(element)
-> something that is less than or equal to elehigher(element)
andlower(element)
are the same but without the or equal todescendingIterator()
- check hasNext() to see if an element is present, and use
next()
to get the current pointing element and move to the next pointer
- the only thing added is
hasPrevious()
andprevious()
- set(element) update the last element returned by
next()
. i.e, update the element that the iterator is currently pointing to
- probably don't need it since you can use the
removeIf()
lambda
Note : Queue
and Deque
are just interfaces, the classes are LinkedList
PriorityQueue
etc.
Should just use a deque for everything
Don't use stack bc it's old ( was released along with Vector
and other classes before java 5)
addFirst()
addLast()
getFirst()
getLast()
removeFirst()
removeLast()
The only time you need to use Queue is when you're using a PriorityQueue
Queue Methods: add()
element()
remove()
In some questions, Stack
might still be asked so remember that the methods are
push()
pop()
peek()
empty()
.put(key, value)
putIfAbsent(key, value)
.values()
returns aCollection<E>
.get(key)
.remove(key)
containsKey(key)
andcontainsValue(val)
keySet()
-> set of keys.entrySet()
-> set ofMap.Entry
- Modifying either keySet or entrySet is reflected in the original map
.forEach((key, value) -> {lambda code})
replace(key, value)
compute()
andcomputeIfAbsent()
andcomputeIfPresent()
it takes in a lambda of the form(key, value) -> {}
, and the return value of this lamdba is the new value, the methodsIfAbsent()
andIfPresent()
are there to take care of calling/not calling the function if the current value is null
You can put any object as a key in a map, it'll just use it's memory address as key, note: it'll only match the key if the object requested and object in hashmap are EXACTLY same
headMap(a)
andtailMap(b)
-> same rules as NavigableSetsubMap(a, b)
ceilingKey()
,ceilingEntry()
,higherKey(key)
,higherEntry()
,floorKey()
,floorEntry()
,lowerKey()
andlowerEntry()
all of them have similar rules as NavigableSetnavigableKeySet()
,descendingMap()
- Step 1 : Compile your regex using p = Pattern.compile(regex)
- Step 2: generate matcher for this pattern, p.matcher(string)
- use the following methods to find patterns
matcher.find()
returns true/false depending on whether a match was found (sorta likeiterator.next()
)match.start()
andmatch.end()
return the starting and ending + 1 character of the matched string
Pattern p = Pattern.compile('fhi');
Matcher m = p.matcher('fhi how are you');
m.find()/m.start()/m.end() etc etc
[abc]
character class, : One character class matches only one character in the actual string
[^abc]
anything except abc
[a-zA-Z]
.
any character
\d
digit
\D
non digit
\s
any whitespace character ( tab, space, endline, crlf, etc)
\S
not whitespace
\w
word character (a-zA-Z0-9)
\W
not word
- it's written in the NAME, quantifiers means they help you count how many times you want a character class, character or a capturing group repeated
*
-> 0 or more
+
-> one or more
{n}
-> exactly n times
{n, m}
-> n to m times, m (exclusive)
()
wrap these around characters that you want to group
each capturing group is given a default number based on the order of opening brackets
In the expression ((A)(B(C)))
, for example, there are four such groups:
((A)(B(C)))
(A)
(B(C))
(C)
(they are ordered in above example)
group 0 is the entire string
you can back reference groups
\d\d\d\d
-> match 4 digit number
(\d\d)\1
-> first 2 digit same as last 2 digit, 1 is the number of capturing group
- this too, written in the name as well
- It allows us to add conditions for the characters surrounding the pattern that we want to match
- These boundaries are only conditions that filter out matches, they are NOT included in the match
^
-> beginning of a line
$
-> end of a line
\b
-> word boundary ( basically a non word character but it's not included in match)
\B
-> non word boundary ( basically a word character but not included in match)
Long.bitCount()
- number of 1's
Long.highestOneBit()
- returns (1<<i) where i
is the position of the left most bit
Long.lowestOneBit()
returns (1<<i)
where i
is the position of the right most bit
Long.numberOfLeadingZeros()
number of zeros before the highest one bit
Long.numberOfTrailingZeros()
number of zeros after the lowest one bit
- You can use it for subsets and all (2 power something)