7 Haziran 2021 Pazartesi

Poly Expression

Giriş
Bir expression'ın sonucu ya void ya da belirli bir tip olmalıdır. Bazen bu tip bir anlamda esnetilir ve derleyicinin karar vermesi istenebilir. Poly Expression sanırım sadece generic kodlarda devreye girer.

Örnek
Elimizde şöyle bir kod olsun.
var intSet1 = Set.of(123, 1234, 101);
var strValue = "123";
isValid(strValue, intSet1);// Compilation error (Expected behaviour)

static <T> boolean isValid(T value, Set<T> range) {
  return range.contains(value);
}
Bu kod derleme hatası verir çünkü String ve Integer farklı tiplerdir. isValid() metoduna birlikte geçilemezler.
Bu kod şöyle olsun.
var strValue = "123";
isValid(strValue, Set.of(123, 1234, 101));// No Compilation error**

static <T> boolean isValid(T value, Set<T> range) {
  return range.contains(value);
}
Bu sefer derleme hatası almayız. Açıklaması şöyle. Çünkü isValid() metoduna geçilen her iki parametrenin de ortak arası olan Serializble kullanılır. 
With isValid(strValue, intSet1);, you're calling isValid(String, Set<Integer>), and the compiler does not resolve T to the same type for the two arguments. This is why it's failing. The compiler simply can't change your declared types.

With isValid(strValue, Set.of(123, 1234, 101)), though, Set.of(123, 1234, 101) is a poly expression, whose type is established in the invocation context. So the compiler works at inferring T that is applicable in context. 
Yani kod şu hale gelirr
static boolean isValid(Serializable value, Set<Serializable> range)

4 Haziran 2021 Cuma

RxJava Observable.create metodu - Vertx İle Birlikte Kullanılabilir

Giriş
ObservableOnSubscribe nesnesi alır. Bu bir emitter'dır. İş bitince emitter nesnesinin onNext() veya onError() metodu çağrılır. İşin bittiğini belirtmek için de onComplete() çağrılır.

Örnek
Şöyle yaparız.
Observable.create(new ObservableOnSubscribe<Integer>() {
  @Override
  public void subscribe(ObservableEmitter<Integer> observableEmitter) throws Exception {
    if (!observableEmitter.isDisposed())
      observableEmitter.onComplete();
  }
}).subscribe (...);
Örnek
Şöyle yaparız
Vertx vertx = Vertx.vertx();
WebClient webClient = WebClient.create(vertx);

Observable<Object> google = hitURL("www.google.com", webClient);
Observable<Object> yahoo = hitURL("www.yahoo.com", webClient);

for (int i = 0; i < 100; i++) {
  google.repeat(100).subscribe(timeTaken -> {
    if ((Long) timeTaken > 10000) {
      System.out.println(timeTaken);
    }
  }, error -> {System.out.println(error.getMessage());});
  yahoo.repeat(100).subscribe(timeTaken -> {
    if ((Long) timeTaken > 10000) {
      System.out.println(timeTaken);
    }
  }, error -> {System.out.println(error.getMessage());});
  }
}

public static Observable<Object> hitURL(String url, WebClient webClient) {
  return Observable.create(emitter -> {
    Long l1 = System.currentTimeMillis();
    webClient.get(80, url, "").send(ar -> {
      if (ar.succeeded()) {
        Long elapsedTime = (System.currentTimeMillis() - l1);
        emitter.onNext(elapsedTime);
      } else {
        emitter.onError(ar.cause());
      }
      emitter.onComplete();
    });
  });
}

3 Haziran 2021 Perşembe

CompletableFuture.thenAcceptBoth metodu - Her İki CompletableFuture Bitince Bir BiConsumer Çalıştırır

Giriş
Not :thenAcceptBothAsync ile kardeştir.

Açıklaması şöyle.
executes a Runnable triggers upon completion of both of two stages. 
Bazı CompletableFuture metodları iki tane işin bitiminde yeni bir iş çalıştırmak içindir. Bunlara "Two to One" denilebilir.

"Two to One"  için kullanılabilecek metodlar
- thenCombine()
- thenAcceptBoth()
olabilir

İmzası şöyle
public <U> CompletableFuture<Void> thenAcceptBoth(
  CompletionStage<? extends U> other,
  BiConsumer<? super T, ? super U> action)
thenCombine() vs - thenAcceptBoth()
Açıklaması şöyle
... when we want to do something with two Futures‘ results, but don't need to pass any resulting value down a Future chain. The thenAcceptBoth method is there to help:
thenCombine() ile şöyle yaparız. Burada CompletableFuture<Foo> şeklinde bir sonuç değeri dönülüyor.
CompletableFuture<String> completableFuture 
  = CompletableFuture.supplyAsync(() -> "Hello")
    .thenCombine(CompletableFuture.supplyAsync(
      () -> " World"), (s1, s2) -> s1 + s2));

assertEquals("Hello World", completableFuture.get());
Örnek
thenAcceptBoth() ile şöyle yaparız. Her iki supplyAsync() bitince, System ile bunları gösterir.
CompletableFuture future = CompletableFuture.supplyAsync(() -> "Hello")
  .thenAcceptBoth(CompletableFuture.supplyAsync(() -> " World"),
    (s1, s2) -> System.out.println(s1 + s2));
Örnek
Şöyle yaparız
var result = 
  CompletableFuture.supplyAsync(Weather::getWeatherFromServerA)
  .thenAcceptBoth( CompletableFuture.supplyAsync((Quotation::getQuotationFromServerA)),
  (weather, quotation) -> System.out.println(weather + ":" + quotation)) ;



2 Haziran 2021 Çarşamba

AsynchronousServerSocketChannel Sınıfı - NIO

Giriş
Şu satırı dahil ederiz
import java.nio.channels.AsynchronousServerSocketChannel;
accept metodu - CompletionHandler
Şöyle yaparız
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

public class TestServer {
  private AsynchronousServerSocketChannel channel;
  public TestServer(int port) {

    try {
      channel = AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(port));
    } catch (IOException e) {
...
    }

    channel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
      @Override
      public void completed(AsynchronousSocketChannel socket, Void attachment) {
        channel.accept(attachment, this);
        ByteBuffer byteBuffer = ByteBuffer.allocate(64);
        socket.read(byteBuffer);
        byteBuffer.flip();
        System.out.println(new String(byteBuffer.array()));
      }
      @Override
      public void failed(Throwable exc, Void attachment) {
        System.out.println("Failed to establish communication");
      }
    });
  }
}

1 Haziran 2021 Salı

FloatVector Sınıfı - Vector API - Java 16 İle Geliyor

Giriş
Vector API için IntVector, FloatVector gibi sınıflar var. Şu satırı dahil ederiz
import jdk.incubator.vector.FloatVector;
import jdk.incubator.vector.IntVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;
Vector API Nedir?
Açıklaması şöyle
Vector computation consists of a sequence of operations on vectors. The Vector API is used to express vector computations that can be reliably compiled at runtime to the optimal vector instructions on supported CPU architectures, resulting in better performance than equivalent scalar computations. The goal of the vector API is to provide users with concise, easy-to-use and platform-independent expression of a wide range of vector calculations.

Açıklaması şöyle
To explain how the Java Vector API abstraction works, we need to explore different CPU architectures and provide a basic understanding of data-parallel computation. However, the concept is not so new. It has existed in C# for a while and has proven to be a good approach to leveraging data-parallel computation on modern hardware architectures.

In contrast to a regular computing operation, as in 1+1, where two “pieces of data” are added in one operation, a data-parallel operation is executing a simple operation (e.g., +) on multiple “pieces of data” at the same time. This mode of operation is called SIMD (Single Instruction, Multiple Data), whereas the traditional way of execution is called SISD (Single Instruction, Single Data). The performance speed-up results from applying the same operation on more than one “piece of data” within one CPU cycle. As a simple example: Instead of adding each element of an array A with each element of an array B, we take chunks of array A and array B and operate simultaneously. The two modes are illustrated below and should provide evidence of why SIMD should increase computational performance.
Şeklen şöyle


Ancak bir problem var. Her CPU mimarisi kendi gerçekleştirimi ile geliyor. JVM'in işlemci mimarisine göre çalışması lazım. 

Açıklaması şöyle
Java supports auto vectorization for arithmetic algorithms , which means the JIT compiler transforms some scalar operations to vector operations , when It sees fit. But the developer has no control over this.
With the new Vector APIs , developers can perform vector operations explicitly and make better use of multiple core capabilities.
fromArray metodu
Örnek 
Şöyle yaparız
float[] a = {1f, 2f, 3f, 4f};
float[] b = {5f, 8f, 10f, 12f};

FloatVector first = FloatVector.fromArray(FloatVector.SPECIES_128, a, 0);
FloatVector second = FloatVector.fromArray(FloatVector.SPECIES_128, b, 0);

FloatVector result = first
  .add(second)
  .pow(2)
  .neg();

//result = [-36.0, -100.0, -169.0, -256.0]

float[] resultArray = new float[4];
result.intoArray(resultArray,0);
fma işlemi
Örnek
Normalde şöyle yaparız
// FMA: Fused Multiply Add: c = c + (a * b)
public static float scalarFMA(float[] a, float[] b){
  var c = 0.0f;

  for(var i=0; i < a.length; i++){
    c = Math.fma(a[i], b[i], c);
  }
  return c;
}
Vector API ile şöyle yaparız
private static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERgrey;

public static float vectorFMA(float[] a, float[] b){
  var upperBound = SPECIES.loopBound(a.length);
  var sum = FloatVector.zero(SPECIES);
  var i = 0;
  for (; i < upperBound; i += SPECIES.length()) {
    // FloatVector va, vb, vc
    var va = FloatVector.fromArray(SPECIES, a, i);
    var vb = FloatVector.fromArray(SPECIES, b, i);
    sum = va.fma(vb, sum);
  }
  var c = sum.reduceLanes(VectorOperators.ADD);
  for (; i < a.length; i++) { // Cleanup loop
    c += a[i] * b[i];
  }
  return c;
}


28 Mayıs 2021 Cuma

RxJava AsyncSubject Sınıfı

Giriş
Açıklaması şöyle
AsyncSubject emits only the last value of the Observable and this only happens after the Observable completes.
Örnek 
Elimizde şöyle bir kod olsun
AsyncSubject<Integer> pSubject = AsyncSubject.create();
pSubject.onNext(0);

pSubject.subscribe(it -> System.out.println("Observer 1 onNext: " + it),
                  (Throwable error) -> { }, () -> System.out.println("Observer 1 onComplete"),
                  on1 -> System.out.println("Observer 1 onSubscribe"));

pSubject.onNext(1);
pSubject.onNext(2);


pSubject.subscribe(it -> System.out.println("Observer 2 onNext: " + it),
                  (Throwable error) -> { }, () -> System.out.println("Observer 2 onComplete"),
                  on1 -> System.out.println("Observer 2 onSubscribe"));

pSubject.onNext(3);
pSubject.onNext(4);

/* This is very important in AsyncSubject  */
pSubject.onComplete();
Çıktı olarak şunu alırız
Observer 1 onSubscribe
Observer 2 onSubscribe
Observer 1 onNext: 4
Observer 1 onComplete
Observer 2 onNext: 4
Observer 2 onComplete

RxJava UnicastSubject Sınıfı

Giriş
Açıklaması şöyle
UnicastSubject allows only a single subscriber and it emits all the items regardless of the time of subscription.
Örnek
Şöyle yaparız
Observable<Integer> observable = Observable.range(1, 5)
                .subscribeOn(Schedulers.io());


UnicastSubject<Integer> pSubject = UnicastSubject.create();
observable.subscribe(pSubject);


pSubject.subscribe(it -> System.out.println("onNext: " + it));
Çıktı olarak şunu alırız
onNext: 1
onNext: 2
onNext: 3
onNext: 4
onNext: 5