-
Notifications
You must be signed in to change notification settings - Fork 0
/
Common.txt
560 lines (450 loc) · 31.6 KB
/
Common.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
/******************** String, char, Integer conversion ***************/
[String to int]: Integer.parseInt(s); // return int primitive
[String to Integer]: Integer.valueOf(s); // return an Integer Object
[int to String]: String.valueOf(int)
[char[] to String]: String str = new String(chArray);
[list to array]: String[] arr = list.toArray(new String[list.size()]);
[array to list]: List<String> list = Arrays.asList(arr); // It can directly list elements of the array, for example: Arrays.asList("first", "second");
// Very suitable for converting a single element to a list.
// Note that the list-form array returned by Arrays.asList allows modification of certain elements but cannot add or remove elements.
/********************** String ***************************/
String s = “a*b*c”;
s.charAt(i);
s.length();
s.substring(0, 1); // [0, 1)
s.substring(1); //[1, s.length)
s.equals(“b”);
s.compareTo(“b*c*d”); // return -1 because s comes first in lexicographical order
s.trim(); // remove tailing and padding spaces
s.indexOf(“a”); // return first index of substring “a” indexOf(substring)
s.indexOf(‘a’, 2); // indexOf(int ch, fromIndex), indexOf(String str, fromIndex)
s.lastIndexOf(‘a’); // also we can use s.lastIndexOf(String str)
s.replaceAll(substr, target); // replace all substr to target in s
char[] arr = s.toCharArray();
String[] arr = s.split("\\*") // when delimiter is '*'
String[] arr = s.split("\\.") // when delimiter is '.'
String res = String.join(String delimiter, List<String> data); // use the delimiter to concatenate the string in data.
Objects.equals(Object a, Object b); // (1)if both parameters are null return true
// (2)if exactly one parameter is null return false
// (3)return the result of invoking the equals() method of the first parameter passing it the second parameter
// This behaviour means it is "null safe".
/********************** StringBuilder ***************************/
StringBuilder sb = new StringBuilder();
sb.append(“a”);
sb.insert(0, “a”); // sb.insert(int offset, char c) or sb.insert(offset, str)
sb.deleteCharAt(int index);
sb.reverse();
sb.toString();
sb.length(); // return the number of characters in sb, similar to str.length()
/********************** Array ***************************/
int[] arr = new int[10];
Arrays.sort(arr);
Arrays.fill(arr, -1); // initialize all array elements with value -1
public void helper(int[] nums);
helper(new int[]{1, 2}); // initialize array in method
/********************** HashMap (TreeMap), HashSet (TreeSet)***********************/
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
map.put('c', 1);
map.get('c');
map.getOrDefault(key, defaultValue); // if key exists return value, else return default value
map.remove(‘c’); // remove key and its value
map.computeIfAbsent(key, mappingFunction); // if key exists return value, else create a value by mappingFunction
map.computeIfAbsent(key, k -> new HashSet<>()).add(val);
map.computeIfAbsent(key, k -> new ArrayList<>()).add(val); // RECOMMENDED !!!
if (map.containsKey('c')) { // check if key exists
}
if (map.containsValue(1)) { // check if value exists
}
for (Character d : map.keySet()) { // traverse key set
}
for (Integer i : map.values()) { // traverse value set
}
for(Map.Entry<Character, Integer> entry : map.entrySet()){ // traverse key-value pair
entry.getKey();
entry.getValue();
}
map.forEach((k,v) -> System.out.println("key: "+k+" value:"+v)); // traverse key-value pair using lamda expression to print out info
map.isEmpty();
map.size();
HashSet<Integer> set = new HashSet<Integer>();
set.add(10);
set.remove(10);
if(set.contains(10)){
}
set.size();
set.isEmpty();
setA.retainAll(setB); // setA keeps the intersection of original setA and setB;
setB.removeAll(setC); // Removes from this set all of its elements that are contained in the specified collection (setB - setC)
setC.addAll(setD); // union two sets of setC and setD
setC.containsAll(setD); // Returns true if this set contains all of the elements of specified collection
Object[] arr = setA.toArray(); // Returns an array containing all of the elements in this set.
TreeMap<Integer, String> map = new TreeMap<>(); // key’s ascending order (default)
map.put(2, “b”);
map.put(1, “a”);
map.put(3, “c”);
for(String str : map.values()) // traverse in “a” “b” “c” order
for(Integer num : map.keySet()) // traverse in 1, 2, 3 order
TreeMap<String, Integer> treeMap = new TreeMap<>(); // sorted in lexicographical order
TreeMap<Integer, Integer> treeMap = new TreeMap<>(Collections.reverseOrder()); // descending order
treeMap.lowerKey(k); // return the max key that < k
treeMap.floorKey(k); // return the min key that >= k
treeMap.higherKey(k); // return the min key that > k
treeMap.ceilingKey(k); // return the max key that <= k
treeMap.firstKey(); // returns the first (lowest) key currently in this map.
SortedMap<K,V> portionOfTreeMap = treeMap.headMap(K toKey); // Returns a view of the portion of this map whose keys are strictly less than toKey.
NavigableMap<K,V> map = treeMap.headMap(toKey, true); // Returns a view of the portion of this map whose keys are less than or equal to toKey.
Set<Integer> treeSet = new TreeSet<>(); // sort in ascending order by default
treeSet.lower(Integer e); // return greatest element that is < e, or null if no such element
treeSet.floor(Integer e); // return greatest element that is <= e, or null if no such element
treeSet.ceiling(Integer e); // return smallest element that is >= e, or null if no such element
treeSet.higher(Integer e); // return smallest element that is > e, or null if no such element
treeSet.first(); // return the first element in the treeset (if min set, return minimum element)
treeSet.last(); // return the last element in the treeset
/********************** LinkedHashMap, LinkedHashSet *************/
Map<Integer,String> map = new LinkedHashMap<>();
map.put(1, "first");
map.put(2, "second");
map.put(3, "third");
for(Map.Entry<Integer,String> entry : map.entrySet())
System.out.println(entry.getKey(), entry.getValue()); // print order: 1, 2, 3
Set<Integer> set = new LinkedHashSet<>();
/********************** List, ArrayList, LinkedList *************/
List<Integer> list = new ArrayList<>();
list.add(14);
list.add(0, 10); // list.add(int index, int value);
list.get(int index);
list.remove(list.size() - 1);
list.set(int index, int val); // replaces element at index and returns original
list.indexOf(Object o); // return first index of occurrence of specified element in the list; -1 if not found
list.subList(int fromIndex, int toIndex); // return a sublist within range [fromIndex, toIndex)
Collections.sort(list); // ascending order by default
Collections.sort(list, Collections.reverseOrder()); // descending order
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) { // the Integer can be any Object instead
return o1 ‐ o2;// 0‐>1
// return o2‐o1; 1‐>0
}
});
list.forEach(num -> system.out.println(num)); // traverse the list and print out by using lamda function
/********************** Stack, Queue, PriorityQueue, Deque ***********************/
Stack<Integer> stack = new Stack<Integer>();
stack.push(10);
stack.pop();
stack.peek();
stack.isEmpty();
stack.size();
Queue<Integer> q = new LinkedList<Integer>();
q.offer(10); // q.add() is also acceptable
q.poll();
q.peek();
q.isEmpty();
q.size();
PriorityQueue<Integer> pq = new PriorityQueue<>(); // minimum Heap by default
PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder()); // change to maximum Heap
pq.add(10);
pq.poll();
pq.peek();
pq.isEmpty();
pq.size();
class Node implements Comparable<Node>{
int x;
int y;
public Node(int x, int y){
this.x = x;
this.y = y;
}
@Override
public int compareTo(Node that){
return this.x - that.x; // ascending order / minimum Heap
// return that.x - this.x; // descending order / maximum Heap
}
}
PriorityQueue<Node> pq = new PriorityQueue<>();
import java.util.Deque;
Deque<Integer> dq = new LinkedList<Integer>(); // Deque is usually used to implement monotone queue
dq.addFirst(); // dq.offerFirst();
dq.addLast(); // dq.offerLast();
dq.peekFirst(); //
dq.peekLast();
dq.pollFirst(); // dq.removeFirst();
dq.pollLast(); // dq.removeLast();
/********************** Enum ***************************/
set1 = EnumSet.of(Gfg.QUIZ, Gfg.CONTRIBUTE, Gfg.LEARN, Gfg.CODE);
set2 = EnumSet.complementOf(set1); // initially containing all the elements of this type that are not contained in the specified set
set3 = EnumSet.allOf(Gfg.class);
set4 = EnumSet.range(Gfg.CODE, Gfg.CONTRIBUTE); // contains all of the elements in the range defined by the two specified endpoints.
/************************** Random method *****************************/
Random rand =new Random(); // initialize Random object
int i = rand.nextInt(100); // generate random number in [0, 100)
float f = rand.nextFloat(); // generate float value in [0, 1)
double d = rand.nextDouble(); // generate double value in [0.0, 1.0)
/************************** Math *****************************/
Math.pow(double x, double y); // return x^y
Math.round(float a); // returns the closest int to the argument
Math.abs(int/float/doubld val);
Math.sqrt();
Math.sin(double rad); // input is rad not angle
Math.PI;
Math.E;
/************************** Collections/Object *****************************/
Collections.nCopies(100, new Object[]{true});// return an immutable list which contains n copies of given object
getClass() // Returns the runtime class of this {@code Object}
Collections.singletonList() // use it to replace Arrays.asList() when there is only one element
Collections.unmodifiableSet(new HashSet<>()) // returns an unmodifiable view of the specified set. Note that, changes in specified set will be reflected in unmodifieable set.
// Also, any modification on unmodifiableSet is not allowed, which triggers exception.
Collections.swap(List, int i, int j); // swap the ith and jth element in list
/************************** Lamda expression *****************************/
1. Functional interface: the interface contains exactly one abstract method
@FunctionalInterface
public interface Sprint {
public void sprint(Animal animal);
}
2. lamda expression
a -> a.canHop() Equivalent to (Animal a) -> { return a.canHop(); }
/********************* std input/output file read/write ************************/
import java.io.*;
import java.net.*;
Scanner in = new Scanner(System.in);
int n = in.nextInt();
while(in.hasNext()){
String str = in.nextLine();
}
String inputfile="in.txt";
String outputfile="out.txt";
try
{
BufferedReader in = new BufferedReader(new FileReader(inputfile));
line = in.readLine();
while (line!=null)
{
// do something with line
line=in.readLine();
}
in.close(); // close the file
} catch (IOException e)
{
e.printStackTrace();
}
try{
BufferedWriter out = new BufferedWriter(new FileWriter(outputfile));
for(String str : map.keySet()){
out.write(str + " " + map.get(str));
out.newLine();
}
out.close(); // close the file
}catch (IOException e)
{
e.printStackTrace();
}
URL wordlist = new URL("http://foo.com/wordlist.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(wordlist.OpenStream()));
String inputLine = null;
List<String> res = new ArrayList<>();
while((inputLine = in.readLine()) != null){
res.add(inputLine);
}
/********************* Atomic Class ******************************************/
//an atomic operation is supposed to be completed wholly or not at all. Based on CAS theory
AtomicInteger count = new AtomicInteger(0);
count.getAndSet();
count.incrementAndGet();
count.getAndIncrement();
count.decrementAndGet();
count.getAndDecrement();
AtomicBoolean enabled = new AtomicBoolean(initialValue: false);
boolean result = enabled.compareAndSet(expect:true, update:false); // if result = false, means actual value doesn't equal to expect one
AtomicReference<AmbryClientException> exceptionInCallback = new AtomicReference<>(null); // an atomic object allowing method to perform atomic operations
exceptionInCallback.get();
exceptionInCallback.set();
exceptionInCallback.compareAndSet(expected, update); // Atomically sets the value to the given updated value if the current value == the expected value.
AtomicStampedReference<Person> s = new AtomicStampedReference<Person>(new Person(20), stampVal);
s.compareAndSet(s.getReference(), new Person(s.getReference().age+10), stampVal, ++stampVal); // s.compareAndSet(expected_reference, update_reference, expected_stamp, update_stamp);
/********************* ExecutorService (create and manage threads)************************/
(1)Future: Think of a Future as an object that holds the result – it may not hold it right now,
but it will do so in the future (once the Callable returns). Thus, a Future is basically one way
the main thread can keep track of the progress and result from other threads.
(2)Callable: is similar to Runnable, in that it encapsulates a task that is meant to run on another thread.
(3)In the thread pool, instead of using execute(Runnable r), you use submit(Callable r), which returns a Future<V> object (declared in the ExecutorService interface).
When the result is required, you can use get() method on the Future object. If the result is ready, it is returned,
otherwise, the calling thread is blocked until the result is available.
ExecutorService service = new Executor.newSingleThreadExecutor(); // single thread executor
ExecutorService service = new Executor.newSingleThreadScheduledExecutor(); // single thread can run after delay or periodically
ExecutorService service = new Executor.newCachedThreadPool(); // if previous thread is available, reuse it. Otherwise, create new thread as needed
ExecutorService service = new Executor.newFixedThreadPool(int nThreads); // create a pool with fixed number of threads
ExecutorService service = new Executor.newScheduledThreadPool(int nThreads);// a pool with fixed number of threads and threads execute after delay or periodically
service.execute(Runnable Object); // or lamda expression; Executes a Runnable task at some point in the future
Future<?> future = service.submit(Runnable task); // Executes a Runnable task at some point in the future and returns a Future representing the task
service.shutdown(); // finish running tasks and then terminate
service.shutdownNow(); // stop all running tasks immediately
Future<?> result = service.schedule(Callable<V> callable, long delay, TimeUnit unit);
Future<?> result = service.schedule(Runnable command, long delay, TimeUnit unit);
Future<?> result = service.scheduleAtFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); // periodic execution. A fixed delay after completion of last execution
Future<?> result = service.submit(Callable<V> callableWorker);
future.isDone();
future.isCancelled();
future.cancel(); // Attempts to cancel execution of the task.
future.get(); // Retrieves the result of a task, waiting endlessly if it is not yet available.
future.get(long timeout, TimeUnit unit); // Retrieves the result of a task, waiting the specified amount of time.
/********************* Synchronize Block/Method ************************/
synchronized(object){} // synchronized block (used at code snippet closest to the operation)
private synchronized void update(){} // synchronized method
List<Integer> list = Collections.synchronizedList( new ArrayList<>(Arrays.asList(4,3,52))); // used to wrap non-concurrent class
/********************* Concurrent Collection ************************/
Map<String,Integer> map = new ConcurrentHashMap<>();
Queue<Integer> queue = new ConcurrentLinkedQueue<>();
Deque<Integer> deque = new ConcurrentLinkedDeque<>();
BlockingQueue<Integer> blockingQueue = new LinkedBlockingQueue<>();
blockingQueue.offer(E e, long timeout, TimeUnit unit); //Adds item to the queue waiting the specified time, returning false if time elapses before space is available
blockingQueue.poll(long timeout, TimeUnit unit); //Retrieves and removes an item from the queue, waiting the specified time, returning null if the time elapses before the item is available
BlockingDeque<Integer> blockingDeque = new LinkedBlockingDeque<>();
blockingDeque.offerFirst(E e, long timeout, TimeUnit unit);
blockingDeque.offerLast(E e, long timeout, TimeUnit unit);
blockingDeque.pollFirst(long timeout, TimeUnit unit);
blockingDeque.pollLast(long timeout, TimeUnit unit);
/* ----- Introduction on CopyOnWriteArrayList -------
* When we’re calling the iterator() method on the CopyOnWriteArrayList,
* we get back an Iterator backed up by the immutable snapshot of the content of the CopyOnWriteArrayList.
* Its content is an exact copy of data that is inside an ArrayList from the time when the Iterator was created.
* Even if in the meantime some other thread adds or removes an element from the list,
* that modification is making a fresh copy of the data that will be used in any further data lookup from that list.
* Because of the copying mechanism, the remove() operation on the returned Iterator is not permitted.
*/
List<Integer> list = new CopyOnWriteArrayList<>(Arrays.asList(4,3,52));// use case: when we are iterating over it more often than we are modifying it.
// If adding elements is a common operation in our scenario, then CopyOnWriteArrayList won’t be a good choice
// – because the additional copies will definitely lead to sub-par performance.
Set<Integer> set = new CopyOnWriteArraySet<>(); // copy all of their elements to a new underlying structure anytime an element is added, modified, or removed from the collection
// The most notable pros of the ConcurrentSkipListMap are the methods that
// can make an immutable snapshot of its data in a lock-free way.
Map<String, Integer> map = new ConcurrentSkipListMap<>(); // concurrent version for sorted map like treemap, ascending order by default
Set<String> set = new ConcurrentSkipListSet<>(); // concurrent version for sorted set like treeset, ascending order by default
concurrentNavigableMap<K,V>.descendingMap(); // Returns a reverse order view of the mappings contained in this map
/********************* Generics - Get and Put rule ************************/
Use an extends wildcard when you only get values out of a structure.
Use a super wildcard when you only put values into a structure.
And don't use a wildcard when you both want to get and put from/to a structure.
Collection<? extends Fruit> // what we know is that the collection is one type of Fruit. We can get but cannot add into it in case that added fruit violates the current type
Collection<? super Banana> // what we know is fruits in collection belong to parent class of banana. We can add fruit as long as we know the added fruit is parent class of banana.
But we can't get one from it because we don't know what is excatly the type is.
/********************* CountDownLatch ************************/
CountDownLatch is a synchronization utility class that allows one or more threads to wait until the operations of other threads are completed before proceeding.
Background: Other concurrent utility classes include CyclicBarrier, Semaphore, ConcurrentHashMap, and BlockingQueue, all of which exist in the java.util.concurrent package.
The CountDownLatch is implemented using a counter, initialized with the number of threads. Whenever a thread finishes its task, the counter decrements by 1. When the counter reaches 0,
it signifies that all threads have completed their tasks. Then, the threads waiting on the latch can resume executing their tasks.
CountDownLatch use cases:
1.Maximizing Parallelism: Sometimes, we want to start multiple threads simultaneously to achieve maximum parallelism. For instance, when testing a singleton class.
If we create a CountDownLatch with an initial count of 1 and make all threads wait on this latch, we can easily accomplish the testing.
We only need to call the countDown() method once to allow all waiting threads to resume execution simultaneously.
2.Wait for n threads to complete their individual tasks before starting execution: For example, an application startup class needs to ensure that before handling user requests,
all N external systems have started and are running.
3.Deadlock Detection: A very convenient use case is where you can use n threads to access shared resources, with a different number of threads in each testing phase,
attempting to create a deadlock.
/********************* review in OOP ************************/
In Java, members (methods, fields) marked with 'static' indicate that they belong to the class itself, rather than a specific instance of the class.
In Java, avoid using objects to call static member variables or methods; instead, use the class to invoke static members.
The 'static' block is used for initializing static variables, for example:
static int num;
static String mystr;
static{
num = 97;
mystr = "Static keyword in Java";
}
//Static Block is used for initializing the static variables.
//This block gets executed when the class is loaded in the memory.
//A class can have multiple Static blocks, which will execute in the same sequence in which they have been written into the program.
When 'final' modifier is used in Collection, such as List, Map it means reference can not be changed to another Collection (add/delet element, etc)
When 'final' is used to modify a class, it means that this class cannot be inherited (extended) by other classes.
/********************* Java NIO ************************/
Background: Java NIO enables non-blocking I/O operations. For instance, within a single thread, data can be read from a Channel into a buffer while concurrently performing other tasks. Once the data is read into the buffer,
the thread can then proceed to process the data. Writing data follows a similar pattern.
NIO includes the following core components:
Channels: All I/O operations start with a Channel. These channels are based on UDP and TCP network I/O, as well as file I/O. For example: FileChannel, ServerSocketChannel, DatagramChannel, and so on.
Buffers: Buffers cover the fundamental types that can be operated on through I/O operations. For example, ByteBuffer, IntBuffer, etc.
Selectors: Selectors allow a single thread to handle multiple channels. If your program involves numerous connections, especially with relatively low I/O bandwidth for each connection,
this feature can be very helpful. For instance, in a chat server scenario.
To use a Selector, we must register Channels with the Selector. Subsequently,
we can call the Selector's select() method. This method blocks until the state of one of the registered channels satisfies certain conditions.
Once the method returns, the thread can handle these events.
Characteristics of Channels:
Channels can perform both read and write operations, whereas streams are generally unidirectional (they can either be for reading or writing).
Channels support asynchronous reading and writing.
Channels always involve reading from or writing to buffer objects.
Implementation of Channels:
FileChannel Reading and writing data for files
DatagramChannel Reading and writing data for UDP
SocketChannel Reading and writing data for TCP
ServerSocketChannel Allows us to listen for TCP connection requests, where each request creates a SocketChannel.
Buffer: Essentially, it is a memory area that can be used to write data and later read it out.
This memory area is encapsulated by NIO Buffer, providing a series of convenient read and write interfaces for development.
Buffer reading and writing typically are as follows::
(1) Place data into the buffer; for example: int bytesRead = inChannel.read(buf); //read into buffer.
(2) Invoke flip(); Switch the Buffer from write mode to read mode.
(3) Extract data from the Buffer; for example: int bytesWritten = inChannel.write(buf); //read from buffer into channel.
(4) Call buffer.clear() or buffer.compact(); The clear method resets the position to 0, while compact clears only the read data, retaining unread data.
Buffer has three properties:
<1> Capacity Capacity: As a block of memory, a buffer has a fixed size. Once the buffer is filled, it needs to be cleared of read data to continue writing new data.
<2> Position Position: The current position for reading/writing in the buffer.
<3> Limit Limit: When switched to read mode, the limit represents the maximum amount of data that can be read. Its value equals the position in write mode.
<4> Mark Mark: A remembered position. Calling mark() sets mark = position. Calling reset() sets position = mark. The mark is undefined until set.
Relationship among these 4:
0 <= mark <= position <= limit <= capacity
The commonly used APIs of Buffer:
buffer.flip() // First, set limit = current position, then reset position = 0.
buffer.clear() // set the limit = capacity, reset position = 0;
buffer.rewind() // To reread the data, reset position = 0 while keeping the limit unchanged.
buffer.remaining() // The number of elements remaining in this buffer is actually limit - current position.
Scatter:
Scattering read refers to the operation of reading from a channel and writing the data into multiple buffers. In essence, 'scatters' represent the process of data transfer from one channel to multiple buffers.
Gather:
Gathering write, on the other hand, is the opposite, representing the process of writing data from multiple buffers into a single channel.
Scatter/gather can be very useful in certain scenarios, such as when dealing with separately transmitted data portions. For instance,
consider a message that includes a header and a body; we might store the header and body in separate independent buffers.
This approach of handling the header and body separately can make development more straightforward.
In Java NIO, if a channel is of type FileChannel, it can directly transfer data to another channel. This capability is due to the two methods, transferTo and transferFrom, included in FileChannel.
FileChannel.transferFrom(fromChannel, position, count): Pulls data from the source channel into the target channel.
FileChannel.transferTo(position, count, toChannel) method: Pushes data from the source channel to the target channel.
Selector: To check whether one or multiple NIO Channels are in a readable or writable state. This enables the management of multiple channels by a single thread, thereby managing multiple network connections.
The benefit is that I can use fewer threads to handle channels. In fact, you can even use a single thread to handle all channels.
From the perspective of the operating system, thread context switching is relatively expensive, and each thread requires system resources. Hence, the fewer threads occupied, the better.
Registering a Channel to a Selector:
channel.configureBlocking(false); //The Channel must be non-blocking. Therefore, FileChannel is not suitable for Selector because FileChannel cannot be switched to non-blocking mode.
SelectionKey key = channel.register(selector, SelectionKey.OP_READ); //The second parameter is a "interest set," representing the states of the channels that we are interested in.
Channel status:
(1)Connect: SelectionKey.OP_CONNECT
(2)Accept: SelectionKey.OP_ACCEPT
(3)Read: SelectionKey.OP_READ
(4)Write: SelectionKey.OP_WRITE
SelectionKey object contains the following properties:
The interest set;
The ready set;
The Channel;
The Selector;
An attached object (optional);
(1)interest set: is the set of events you are interested in "selecting".
(2)ready set: is the set of operations the channel is ready for. Generally, after calling the select method, the ready set will be needed.
(3)channel:
(4)selector: Accessing the channel + selector from the SelectionKey is trivial. Like this: Selector selector = selectionKey.selector();
(5)attached object: You can attach an object to a SelectionKey this is a handy way of recognizing a given channel,
or attaching further information to the channel.
Several functions of the Selector for channel selection
select(): blocks until at least one channel is ready for the events you registered for.
select(long timeout): does the same as select() except it blocks for a maximum of timeout milliseconds (the parameter).
selectNow(): doesn't block at all. It returns immediately with whatever channels are ready.
Note: The return value of the above functions is an int, The int returned by the select() methods tells how many channels are ready.
Accessing Channels that are Ready
You can access the ready channels via the "selected key set", by calling the selectors selectedKeys() method.
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Close() Function
When you are finished with the Selector you call its close() method.
This closes the Selector and invalidates all SelectionKey instances registered with this Selector.
The channels themselves are not closed.
Java NIO SocketChannel: a channel that is connected to a TCP network socket.
You can set a SocketChannel into non-blocking mode. When you do so, you can call connect(), read() and write() in asynchronous mode.
connect()
write()
read()
/********************* Java I/O ************************/
1. int read(byte[], int offset, int length)
The read(byte[], int offset, int length) method reads bytes into a byte array, but starts at offset bytes into the array,
and reads a maximum of length bytes into the array from that position. Again, the read(byte[], int offset, int length) method
returns an int telling how many bytes were actually read into array, remember to check this value before processing the read bytes.