11 Ocak 2021 Pazartesi

Lombok Kullanımı

Giriş
IntelliJ'de File/Settings menüsü kullanılarak Builder,Execution,Deployment ayarlarına gelinir. Compiler/Annotation Processors seçeneği seçilir ve "Enable Annotation processing" etkinleştirilir.

Maven
Şöyle yaparız
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.18</version>
  <scope>provided</scope>
</dependency>
Açıklaması şöyle
... Lombok is needed only at compile time. Because of that reason, the maven scope can (and should) be set to compile/provided.
Normalde bu gerekli değil ancak annotation processor'lara sıra vermek istersek şöyle yaparız
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>3.8.1</version>
      <configuration>
        <source>1.8</source> <!-- depending on your project -->
        <target>1.8</target> <!-- depending on your project -->
        <annotationProcessorPaths>
          <path>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
          </path>
        </annotationProcessorPaths>
      </configuration>
    </plugin>
  </plugins>
</build>
Gradle
Örnek
Şöyle yaparız
compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.26'
Örnek
Şöyle yaparız
dependencies {
  compileOnly 'org.projectlombok:lombok:1.18.22'
  annotationProcessor 'org.projectlombok:lombok:1.18.22'
	
  testCompileOnly 'org.projectlombok:lombok:1.18.22'
  testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'
}
Delombok
Lombok tarafından üretilen kodu görmeyi sağlar. IDE'ler delombok için menü sağlıyorlar. Şeklen şöyle. Burada 
1. Tüm anotasyonlar veya 
2. Sadece class içindeki bazı anotasyonları kapatabiliriz.



Lombok Anotasyonları
Açıklaması şöyle
Val - Creates a local variable with val which will be initialized based on initialization expression. The local variable will also be made final.
Var - Works exactly like Val but the local variable is not declared final.
@Setter - Add setter for all variables.
@Getter -  Add getter for all the variables.
@RequiredArgsConstructor - Generates constructor for each field.
@NoArgsConstructor - Creates a non-parametrized constructor.
@AllArgsConstructor - Creates a parametrized constructor containing all fields.
@ToString - Creates toString method.
@EqualsAndHashCode - Creates Equals and Hashcode implementation for fields in the class.

@Data - It is a quick way of combining features of @ToString, @EqualsAndHashCode, @Getter@Setter and @RequiredArgsConstructor
@Builder - Makes instantiation of class easier and provides a way to statically initialize fields in a class.
@Cleanup yazısına bakabilirsiniz.
@Log yazısına bakabilirsiniz.
@NonNull yazısına bakabilirsiniz.
@Slf4j yazısına bakabilirsiniz.
@SneakyThrows yazısına bakabilirsiniz
@Synchronized yazısına bakabilirsiniz
@UtilityClass yazısına bakabilirsiniz.
@Value yazısına bakabilirsiniz
@With yazısına bakabilirsiniz

Generics ve Bounded Type

Giriş 
Eğer liste hem dolaşılacak hem de eklenecekse wildcard kullanılmaması gerekir. 

Örnek
Şöyle yaparız. count metodu listeye yeni eleman ekler, sum ise listeyi dolaşır. Dolayısıyla sadece Collection<Number> şeklinde kullanılır.
public static double sumCount(Collection<Number> nums, int n) {
  count(nums, n);
  return sum(nums);
}
Örnek - İçerideki Generic tip
Şöyle yaparız. Burada RandomizerEntry sınıfının kendisi de Generic tip. Dolayısıyla generic tipi de dışarından geçmek gerekiyor.
public class RandomizedWrapper<T>{

  final int upperBound = 100;
  final List<RandomizerEntry<T>> randomizeList;
  Map<Integer, RandomizerEntry<T>> randomizerMap;

    
  public RandomizedWrapper(final List<RandomizerEntry<T>> randomizeList) {

    this.randomizeList = randomizeList;
    this.randomizerMap = new HashMap<>();
  }


  public void create(){
    List<RandomizerEntry<Integer>> randomizerList = new ArrayList<>();
    //stuff here
    RandomizedWrapper wrapper = new RandomizedWrapper(randomizerList);//OK
  }
}

10 Ocak 2021 Pazar

Method.isBridge metodu

Giriş
Bridge metodlar derleyici tarafından üretilir.
- Generic kodlarda Object parametre alan metodlara erişim için üretirlir. Bunlar bridge denir.
- non-public class'ın public metoduna erişim içi üretilir. Bunlar bridge denir.
Açıklaması şöyle
- in case of non-public classes a bridge method will be created (so that reflection would work)

- in case of generics an erased bridge method will be created (so that erased calls would work)
Örnek - generics
Elimizde şöyle bir kodd olsun
interface WithGeneric<T> {
  public WithGeneric<T> self(T s);
}

public class Impl implements WithGeneric<String> {

  @Override
  public WithGeneric<String> self(String s) {
    return null;
  }
}
Impl sınıfında iki tane metod bulunurr
public WithGeneric<String> self(String) {...}

public WithGeneric self(Object) {...}
Örnek - non-public class'ın public metodu
Elimizde şöyle bir kod olsun
static class A {
    public String foo() { return null; }
}

public static class B extends A {}
Burada derleyici B sınıfında bir kod üretir. Açıklaması şöyle
... will generate a foo method with ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC. On the other hand if you make A public, such a method will not be generated, the reason should be obvious,

CompletableFuture.complete - İşin Belirtilen Değer İle Bitmesini Sağlar

Giriş 
Açıklaması şöyle. Bu metod herhangi bir thread içinden çağrılabilir.
it can be completed from any thread that wants it to complete.
Şöyle yaparız.
CompletableFuture<String> f = new CompletableFuture<>();
f.complete (...);
bu metod çalışmakta olan bir CompletableFuture işinin hemen bitmesine de sebep olabilir.
Örnek
Elimizde şöyle bir kod olsun
public static void main(String[] args) {
  CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
    System.out.println("started work");
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(5));
    System.out.println("done work");
    return "a";
  });

  LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
  cf.complete("b");
  System.out.println(cf.join());
}
Çıktı olarak şunu alırız. Burada çalışmakta olan CompletableFuture nesnesinin sonucunun - yani "a" değerinin" - gelmediği görülebilir.
started work
b
 

6 Ocak 2021 Çarşamba

Phaser Sınıfı

Giriş
Şu satırı dahil ederiz
import java.util.concurrent.Phaser;
Açıklaması şöyle. Phaser'ın CountDownLatch sınıfına göre farkı, kaç tane thread'ın buluşacağını constructor'da vermek yerine dinamik olarak ta verebilmemiz.
Phaser is also a flexible barrier that blocks multiple threads for execution. It executes a number of threads dynamically in separate phases. It is a better flexible approach when compared to the CyclicBarrier and CountDownLatch.
Açıklaması şöyle
The current phase is finished when all registered parties arrive (registered==arrived, unarrived==0). 
constuctor - int parties
Açıklaması şöyle
The Phaser(int parties) constructor creates a phaser with initial phase number 0 and the given number of registered parties (phase=0, registered=parties).
arrive metodu
Açıklaması şöyle
The int arrive() method marks a party arriving at the phaser, without waiting for other parties to arrive (arrived++, unarrived — ).
arriveAndAwaitAdvance metodu
Açıklaması şöyle. Tüm thread'lerin varmasını bekler
The int arriveAndAwaitAdvance() marks a party arriving at the phaser and awaits other parties to arrive (arrived++, unarrived — ).
Örnek
main'de şöyle yaparız. Phaser constructor'a 1 veriyoruz çünkü main thread'i de register() etmek istiyoruz
ExecutorService executorService = Executors.newCachedThreadPool();
Phaser ph = new Phaser(1);
assertEquals(0, ph.getPhase());

executorService.submit(new LongRunningAction("thread-1", ph));
executorService.submit(new LongRunningAction("thread-2", ph));
executorService.submit(new LongRunningAction("thread-3", ph));

ph.arriveAndAwaitAdvance();
 
assertEquals(1, ph.getPhase());
Thread'lerde şöyle yaparız. constructor içinde register() çağrısı ile Phaser sayacı artırılır. Daha sonra run() içinde arriveAndAwaitAdvance() içinde tüm register() olan thread'lerin aynı noktaya gelmesi beklenir.
class LongRunningAction implements Runnable {
  private String threadName;
  private Phaser ph;

  LongRunningAction(String threadName, Phaser ph) {
    this.threadName = threadName;
    this.ph = ph;
    ph.register(); //Thread registers to phaser
  }

  @Override
  public void run() {
    ph.arriveAndAwaitAdvance(); //Wait all parties to arrive
    try {
      Thread.sleep(20);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    ph.arriveAndDeregister(); //Thread deregisters from phaser
  }
}
arriveAndDerigster metodu
Örnek yukarıda

register metodu
Örnek yukarıda

5 Ocak 2021 Salı

Lombok @SneakyThrows Anotasyonu

Giriş
Checked exception'ları RuntimeException ile sarmalar. Açıklaması şöyle
A common critique of Java is the verbosity created by throwing checked exceptions. Lombok has an annotation to remove the need for those pesky throws keywords: @SneakyThrows. As you might expect, the implementation is quite sneaky. It does not swallow or even wrap exceptions into a RuntimeException. Instead, it relies on the fact that at runtime, the JVM does not check for the consistency of checked exceptions. Only javac does this. So Lombok uses bytecode transformations to opt out of this check at compile time.
Üretilen Kod
Şuna benzer
@SuppressWarnings("unchecked")
static <T extends Throwable> void sneakyThrow(Throwable t) throws T {
  throw (T) t;
}

static void testSneaky() {
  final Exception e = new Exception();
  sneakyThrow(e);    // No Errors
}
Neden Çalışıyor
Language specification section 18.4 için açıklama şöyle
… Otherwise, if the bound set contains throws αi, and the proper upper bounds of αi are, at most, Exception, Throwable, and Object, then Ti = RuntimeException
Bu şu anlama gelir. T tipi Throwable olarak tanımlandığı için RuntimeException olarak anlamlandırılıyor.
This exact case applies to sneakyThrows, It states that if the type’s only upper bound is almost Exception, Throwable, and Object, then T will be inferred to be a RuntimeException as per the specification, so it compiles.
Örnek
Şöyle yaparız. Burada checked exception olan Exception, RuntimeException ile sarmalanıyor
public class SneakyThrows {
@SneakyThrows public void sneakyThrow() { throw new Exception(); } }
Örnek
Şöyle yaparız. Burada  checked exception olan ParseException, RuntimeException ile sarmalanıyor
@SneakyThrows
public static Date parseDate(String dateStr) {
  SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
  return format.parse(dateStr);
}
Aslında kodu şu hale getiriyor
public static Date parseDate(String dateStr) {
  try {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    return format.parse(dateStr);
  } catch (ParseException e) {
    throw new RuntimeException(e); 
  }
}
value Alanı
Fırlatılmasını istediğimiz exception belirtilebilir.

Örnek
Şöyle yaparız. Burada kod IOException fırlatıyor. Biz de yine aynısı fırlatılsın istiyoruz ama metod imzasında bu exception kullanılsın istemiyoruz.
@SneakyThrows(IOException.class)
void throwException(String a) {
  ...
  throw new IOException();
}

4 Ocak 2021 Pazartesi

Blowfish

Örnek
Elimizde şöyle bir kod olsun
// random blowfish 256 key
byte[] key = new byte[32];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(key);


// random iv
byte[] iv = new byte[8]; // blowfish iv is 8 bytes long
secureRandom.nextBytes(iv);
Bir dosyayı okuyup başka dosyaya şifrelenmiş olarak yazmak için şöyle yaparız
public static boolean encryptCbcFileBufferedCipherOutputStream(String inputFilename,
String outputFilename, byte[] key, byte[] iv)
throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,
InvalidAlgorithmParameterException
{ Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding"); try (FileInputStream in = new FileInputStream(inputFilename); FileOutputStream out = new FileOutputStream(outputFilename); CipherOutputStream encryptedOutputStream = new CipherOutputStream(out, cipher);) { out.write(iv); SecretKeySpec secretKeySpec = new SecretKeySpec(key, "Blowfish"); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); byte[] buffer = new byte[8096]; int nread; while ((nread = in.read(buffer)) > 0) { encryptedOutputStream.write(buffer, 0, nread); } encryptedOutputStream.flush(); } }
Şifrelenmiş dosyayı okumak için şöyle yaparız
public static boolean decryptCbcFileBufferedCipherInputStream(String inputFilename,
String outputFilename, byte[] key)
throws IOException, NoSuchPaddingException, NoSuchAlgorithmException,
InvalidKeyException, InvalidAlgorithmParameterException
{ byte[] iv = new byte[8]; // blowfish iv is 8 bytes long Cipher cipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding"); try (FileInputStream in = new FileInputStream(inputFilename); CipherInputStream cipherInputStream = new CipherInputStream(in, cipher); FileOutputStream out = new FileOutputStream(outputFilename)) { byte[] buffer = new byte[8192]; in.read(iv); SecretKeySpec secretKeySpec = new SecretKeySpec(key, "Blowfish"); IvParameterSpec ivParameterSpec = new IvParameterSpec(iv); cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); int nread; while ((nread = cipherInputStream.read(buffer)) > 0) { out.write(buffer, 0, nread); } out.flush(); } }