30 Nisan 2021 Cuma

Netty ByteBuf ReaderIndex Kullanımı

Giriş
ReaderIndex  sanırım sadece Heap Buffer kullanırken anlamlı.

Örnek
ReaderIndex konumunu değiştirmeden okumak için şöyle yaparız
ByteBuf buf = ...
byte[] bytes = new byte[buf.readableBytes()];
int readerIndex = buf.readerIndex();
buf.getBytes(readerIndex, bytes);
Örnek
Şöyle yaparız. Heap buffer ise bytes değişkenini alırız ve offset değişkeni arrayOffset() ile doldurulur.
Direct buffer ise veriyi kopyalamak gerekir. readableBytes() ile okunabilecek veri büyüklüğü alınır ve getBytes() ile ReaderIndex ilerletilmeden veri kopyalanır
ByteBuf buf = ...
byte[] bytes;
int offset;
int length = buf.readableBytes();

if (buf.hasArray()) { //Heap Buffer
    bytes = buf.array();
    offset = buf.arrayOffset();
} else { //Direct Buffer
    bytes = new byte[length];
    buf.getBytes(buf.readerIndex(), bytes);
    offset = 0;
}

27 Nisan 2021 Salı

CompletableFuture.thenAccept metodu - Bir Future Nesnesinin Sonucunu Sadece Tüketir Yani void Döner

Giriş
 thenAccept X() metodları bir future nesnesinin sonucunu sdece consume eder. Yani void döner. 
- thenRun() aslında thenAccept() gibidir yani void döner. Farklı olarak Runnable alır
- thenApply() ise thenAccept() ve thenRun()'dan farklıdır yani bir sonuç döner. 

thenAccept metodu
Eğer thenAccept() çağrısı yapıldığında CompletableFuture zaten bitmişse, çağıran thread içinde çalışır. Bitmemişse ForkJoinPool içinde çalışır. Bir önceki safhanın sonucunu girdi olarak alır ancak thenApply'dan() farklı olarak void döner. Yani Consumer gibi çalışır.

Örnek
Şöyle yaparız
CompletableFuture<Integer> a = CompletableFuture.supplyAsync(() -> task.compute(1));
CompletableFuture<Integer> b = CompletableFuture.supplyAsync(() -> task.compute(2));
CompletableFuture<Integer> c = CompletableFuture.supplyAsync(() -> task.compute(3));
CompletableFuture.allOf(a, b, c).thenAccept(v->System.out.println(List.of(a,b,c)));
thenAcceptAsync metodu
Executor veya ForkJoinPool içinde çalışır. Bir önceki safhanın sonucunu girdi olarak alır ancak thenApply'dan() farklı olarak void döner. Yani Consumer gibi çalışır.

ThreadPoolExecutor Kullanımı

Giriş
ThreadPoolExecutor kullanırken, Java'nın sunduğu şekilde değil de bazı değişiklikler yaparak kullanmak daha iyi.

afterExecute metodu Override Edilmeli
ThreadPoolExecutor verilen işlerin fırlattığı exceptionları yutar. Yani loglamaz. Yani elimizde şöyle bir kod olsun. Eğer Runnable exception fırlatırsa haberimiz olmaz.
service.execute(new Runnable(){...});
Elimizde şöyle bir kod olsun. Bu çağrı bir Future döndürür ve eğer Runnable exception fırlattıysa, Future sayesinde anlayabiliriz. Ancak bu durumda her submit() çağrısına kod yazmak gerekir. 
service.submit(new Runnable(){...});
Tüm exceptionları merkezi bir yerden loglamak için afterExecute() metodu override edilir. Açıklaması şöyle.

Hook methods

This class provides protected overridable beforeExecute(...) and afterExecute(...) methods that are called before and after execution of each task. These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals, gathering statistics, or adding log entries. Additionally, method terminated(...) can be overridden to perform any special processing that needs to be done once the Executor has fully terminated. If hook or callback methods throw exceptions, internal worker threads may in turn fail and abruptly terminate.
Söyle yaparız.
protected void afterExecute(Runnable r, Throwable t) {
  super.afterExecute(r, t);
  if (t == null && r instanceof Future<?>) {
    try {
      Future<?> future = (Future<?>) r;
      if (future.isDone()) {
        future.get();
      }
    } catch (CancellationException ce) {
        t = ce;
    } catch (ExecutionException ee) {
      t = ee.getCause();
    } catch (InterruptedException ie) {
      Thread.currentThread().interrupt();
    }
  }
  if (t != null) {
    System.out.println(t);
  }
}

Optional.or metodu

Giriş
Java 9 ile geliyor. Optional empty olmadığı müddetçe or() ile bağlanan metodları çağırır. Açıklaması şöyle
The usage of or() method is similar to what orElse() and orElseGet() method does. However, or() method let us return an Optional instance that is produced by a Supplier.
Örnek
Şöyle yaparız.
Optional<Integer> a, b, c, d; // initialized
Optional<Integer> opOr = a.or(() -> b).or(() -> c).or(() -> d);
Örnek
Şöyle yaparız
@Test
public void whenUseOrThenOk(){
  Person person = null;
  Person optionalPerson = Optional.ofNullable(person)
    .or(() -> Optional.of(new Person("default", "9898")))
.get();
  assertThat(optionalPerson.getContactNo(), is("9898"));
}
Örnek
Şöyle yaparız.
String getFooFromService() {
    return this.function_1()
      .or(this::function_2) // Requires Java 9
      .or(this::function_3) // Requires Java 9
      .orElse("DEFAULT_VALUE");
  }

  Optional<String> function_1() {
    System.out.println("function_1 called");
    return Optional.empty();
  }

  Optional<String> function_2() {
    System.out.println("function_2 called");
    return Optional.of("b");
  }

  Optional<String> function_3() {
    System.out.println("function_3 called");
    return Optional.of("c");
  }