2 Temmuz 2026 Perşembe

async-profiler Aracı

Giriş
Flame graph üretir, grafiği nasıl yorumlayacağımızı anlatan bir yazı burada. Kullanım şöyle
asprof -d 30 -f flamegraph.html <PID>

3 Şubat 2026 Salı

Eventual Immutability

Giriş
Bu konuyu ilk defa burada gördüm. Nesneyi mutable olarak yarattıktan sonra belli bir noktada freeze() metodunu çağırıyoruz ve bundan sonra nesne immutable oluyor.

14 Mart 2025 Cuma

JEP 491 - Synchronize Virtual Threads without Pinning.

Giriş
Açıklaması şöyle
Improve the scalability of Java code that uses synchronized methods and statements by arranging for virtual threads that block in such constructs to release their underlying platform threads for use by other virtual threads. This will eliminate nearly all cases of virtual threads being pinned to platform threads, which severely restricts the number of virtual threads available to handle an application's workload.
synchronized block kullanıyorsak Virtual Thread pinned oluyor. Bu JEP ile artık olmuyor

20 Ocak 2025 Pazartesi

IntelliJ Idea Comment İçin Code Style

Comment At Firt Column
Cevap burada
  • Settings | Editor | Code Style | Java | Code Generation | Comment Code | Line comment at first column -> Uncheck
  • Settings | Editor | Code Style | Java | Code Generation | Comment Code | Block comment at first column -> Uncheck
  • Settings | Editor | Code Style | Java | Wrapping and Braces | Keep when reformatting | Comment at first column -> Uncheck

Ayrıca Method Call Argument uzunsa ayrı satıra gelsin diye
  • Settings | Editor | Code Style | Java | Wrapping and Braces | Method Call Arguments | -> Wrap if long
Ayrıca Chained method calls her biri ayrı satıra gelsin diye
  • Settings | Editor | Code Style | Java | Wrapping and Braces | Chanied Method Calls | -> Wrap always

14 Ocak 2025 Salı

javadoc komutu

Örnek
Şöyle yaparız. docs/index.html dosyasını oluşturur
javadoc --enable-preview --source 22 -d docs Calculator.java


29 Aralık 2024 Pazar

JMeter CLI

CLI vs Non-CLI
Açıklaması şöyle
JMeter has two modes: CLI and Non-CLI. .... CLI mode doesn't have any user interface. But Non-CLI mode has a user interface where you can point-and-click and interact with the JMeter.

Non-CLI mode should be used for recording, scripting, and smoke testing. This mode utilizes more resources (CPU and memory). CLI mode must be used for load testing, stress testing, and other forms of performance testing as well as for CI/CD pipelines. This mode doesn't eat up more resources as there is no user interface to load and render.
Örnek
Şöyle yaparız
jmeter -n -t test_plan.jmx -l test_results.jtl


12 Aralık 2024 Perşembe

Java record İle Yapılamayacak Şeyler

1. Records Cannot Extend Another Class
2. Records Cannot Be Extended
Örnek
Şu kod derlenmez
public class PremiumRecord extends InsuranceRecord {…}
3. Records Cannot Have Additional Instance Fields
Örnek
Şu kod derlenmez
public record InsuranceRecord(String type, float premium) {
  private String policyNumber;  // This won't compile
}
4. Private Canonical Constructors Are Not Allowed
Örnek
Şu kod derlenmez
public record InsuranceRecord(String type, float premium) {
  private InsuranceRecord(String type, float premium) {
    this.type = type;
    this.premium = premium;
  }
  public static InsuranceRecord newInstance(String type, float premium) {
    return new InsuranceRecord(type, premium);
  }
}
5.  Records Cannot Have Setters
Örnek
Şu kod derlenmez
public record InsuranceRecord(String type, float premium) {
  public void setType(String type) {
    this.type = type;  // Won't compile
  }
}


3 Haziran 2024 Pazartesi

@Serial Anotasyonu

Giriş
Bu anotasyon sadece kodda var yani byte code'a girmiyor. Açıklaması şöyleşöyle
This annotation exists purely to engage better compile-time type checking. It is analogous in this way to the @Override annotation, which exists purely to capture design intent, so that humans and tools have more information to work with. 

6 Mayıs 2024 Pazartesi

Virtual Threads - Thread Pinning

Thread Pinning 
Virtual Threads için JDK'daki bir çok kod baştan yazılmış. Böylece thread unloading işlemi yapılabiliyor.  Ancak bir kaç işlemde istisna var. Buna Thread Pinning deniliyor

1. Object.wait()
2. synchronized blok içinde
3. native metod çalıştırırken
4. UDP Sockets
5. Files & DNS

Açıklaması şöyle
Pinning describes the condition where a virtual thread, which maps the platform thread, is stuck to the carrier thread. It means that the virtual thread can’t be unmounted from the carrier threads because the state of it can’t be stored in the heap memory. The pinned thread prevents others from utilizing the same platform thread.
1. synchronized Thread Pinning
Açıklaması şöyle
Only one thread can enter it at a time. The other threads attempting to enter will be blocked until the current (running) thread exits. They would need an uninterrupted access to shared resources to prevent race conditions as well as an accurate state of the data.
Örnek
Şu kod carrier thread'i bloke eder
var e = Executors.newVirtualThreadPerTaskExecutor();
for (int i = 0; i < 1000; i++) {
    e.submit(() -> { new Test().test(); });
}
e.shutdown();
e.awaitTermination(1, TimeUnit.DAYS);

class Test {
  synchronized void test() {
    sleep(4000);
  }
}
synchronized yerine  ReentrantLock kullanılır. Şöyle yaparız
var e = Executors.newVirtualThreadPerTaskExecutor();
for (int i = 0; i < 1000; i++) {
    e.submit(() -> { new Test().test(); });
}
e.shutdown();
e.awaitTermination(1, TimeUnit.DAYS);

class Test {
  private ReentrantLock lock = new ReentrantLock();
  void test() {
    lock.tryLock();
    try {
      sleep(4000);
    } finally {
      lock.unlock();
    }
  }
}
MySQL-J JDBC sürücüsündeki bir açıklama şöyle
Synchronized blocks in the Connector/J code were replaced with ReentrantLocks. This allows carrier threads to unmount virtual threads when they are waiting on IO operations, making Connector/J virtual-thread friendly. Thanks to Bart De Neuter for contributing to this patch. ”

2. native method Thread Pinning
Açıklaması şöyle
This method lets you use code from other languages into your JAVA project, like C or C++. Native methods are invoked within the JAVA virtual machine but executed outside its control.
3. Sockets Thread Pinning
TCP socketlerini okurken Virtual Threads bloke olmuyor, ama UDP socketlerinde oluyor. Açıklaması şöyle
However, not all Java constructs have been retrofitted that way. Such operations include synchronized methods and code blocks. Using them causes the virtual thread to become pinned to the carrier thread. When a thread is pinned, blocking operations will block the underlying carrier thread-precisely as it would happen in pre-Loom times.
Eğer carrier therad'in bloke olma durumu varsa, virtual thread sayısı artırılır. En fazla kaç thread olabileceği  jdk.virtualThreadScheduler.maxPoolSize ile atanabilir

pinned thread Tracing
Açıklaması şöyle
Use the following JVM parameters as options to trace the pinned thread

-Djdk.tracePinnedThreads=full Prints a complete stack trace when a thread jams while pinned, highlighting native frames and frames holding monitors.

-Djdk.tracePinnedThreads=short Limits the output to just the problematic frames.

10 Mart 2024 Pazar

OpenRewrite

Giriş
OpenRewrite bir static kod analiz aracı. Diğer araçlardan farklı olarak sadece rapor üretmiyor aynı zamanda kodu da değiştirebiliyor.

1. dryRun Goal
target/rewrite dizini altında bir patch dosyası oluşturur

2. run Goal
Kodları direkt değiştirir

3. Recipe Listesi

3.1 CommonStaticAnalysis Recipe
Sanırım en işe yarayan recipe'lerden bir tanesi. Bur recipe ile yapılabilecek işlerin listesi burada

Benim hazelcast kodunda çalıştırdıklarım şöyle
  1. org.openrewrite.staticanalysis.UseDiamondOperator
  2. org.openrewrite.staticanalysis.UnncessaryThrows
  3. org.openrewrite.staticanalysis.NoRedundantJumpStatements
  4. org.openrewrite.staticanalysis.NestedEnumsAreNotStatic
  5. org.openrewrite.staticanalysis.RemoveRedundantTypeCast
  6. org.openrewrite.staticanalysis.LambdaBlockToExpression. EE için koşmadım
  7. org.openrewrite.staticanalysis.UnnecessaryExplicitTypeArguments
  8. org.openrewrite.staticanalysis.SimplifyTernaryRecipes
  9. org.openrewrite.staticanalysis.ReplaceRedundantFormatWithPrintf
  10. org.openrewrite.staticanalysis.InstanceOfPatternMatch.  EE için koşmadım. OS için yarım koştum
  11. org.openrewrite.staticanalysis.JavaApiBestPractices
  12. org.openrewrite.staticanalysis.PrimitiveWrapperClassConstructorToValueOf
  13. org.openrewrite.staticanalysis.NoPrimitiveWrappersForToStringOrCompareTo
  14. org.openrewrite.staticanalysis.UseMapContainsKey
AddSerialAnnotationToserialVersionUID 
Örnek
Şöyle yaparız
./mvnw 
-Dskip-modulepath-tests 
-Dcheckstyle.skip 
 clean 
 org.openrewrite.maven:rewrite-maven-plugin:run 
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-static-analysis:RELEASE 
-Drewrite.activeRecipes=org.openrewrite.staticanalysis.AddSerialAnnotationToserialVersionUID 
-Drewrite.exportDatatables=true
MissingOverrideAnnotation
Örnek
Şöyle yaparız
./mvnw 
-Dskip-modulepath-tests 
-Dcheckstyle.skip 
 clean 
 org.openrewrite.maven:rewrite-maven-plugin:run 
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-static-analysis:RELEASE 
-Drewrite.activeRecipes=org.openrewrite.staticanalysis.MissingOverrideAnnotation
-Drewrite.exportDatatables=true -Drewrite.options=ignoreAnonymousClassMethods=true

Örnek
Şöyle yaparız
<plugin>
  <groupId>org.openrewrite.maven</groupId>
  <artifactId>rewrite-maven-plugin</artifactId>
  <version>5.23.1</version>
  <configuration>
    <activeRecipes>
      <recipe>org.openrewrite.staticanalysis.CommonStaticAnalysis</recipe>
    </activeRecipes>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>org.openrewrite.recipe</groupId>
      <artifactId>rewrite-static-analysis</artifactId>
      <version>1.3.1</version>
    </dependency>
  </dependencies>
</plugin>
Eğer proje çok büyükse sadece bazı şeyleri çalıştırmak için proje kök dizininde bir tane rewrite.yml dosyası oluştururuz.  Şöyle yaparız. Eğer proje multi-module ise yine en tepedeki dizine koymak lazım
---
type: specs.openrewrite.org/v1beta/recipe
name: orcun.CommonStaticAnalysis
displayName: Common static analysis issues
description: Resolve common static analysis issues discovered through 3rd party tools.
recipeList:
  - org.openrewrite.staticanalysis.UseDiamondOperator
pom.xml şöyle olur.
<plugin>
  <groupId>org.openrewrite.maven</groupId>
  <artifactId>rewrite-maven-plugin</artifactId>
  <version>5.23.1</version>
  <configuration>
    <activeRecipes>
      <recipe>orcun.CommonStaticAnalysis</recipe>
    </activeRecipes>
  </configuration>
  <dependencies>
    <dependency>
      <groupId>org.openrewrite.recipe</groupId>
      <artifactId>rewrite-static-analysis</artifactId>
      <version>1.3.1</version>
    </dependency>
  </dependencies>
</plugin>
3.2 Migration
CompareEnumsWithEqualityOperator 
Örnek
Şöyle yaparız
./mvnw 
-Dskip-modulepath-tests 
-Dcheckstyle.skip 
clean 
org.openrewrite.maven:rewrite-maven-plugin:run 
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:RELEASE 
-Drewrite.activeRecipes=org.openrewrite.staticanalysis.CompareEnumsWithEqualityOperator 
-Drewrite.exportDatatables=true
StringRulesRecipes
Örnek
Şöyle yaparız
./mvnw 
-T1 
-Dskip-modulepath-tests 
-Dcheckstyle.skip 
clean 
org.openrewrite.maven:rewrite-maven-plugin:run 
-Drewrite.recipeArtifactCoordinates=org.openrewrite.recipe:rewrite-migrate-java:RELEASE 
-Drewrite.activeRecipes=org.openrewrite.java.migrate.lang.StringRulesRecipes$RedundantCallRecipe 
-Drewrite.exportDatatables=true








22 Ocak 2024 Pazartesi

Project Panama - Bridge The Gap Between Java And Native Code

Giriş
Açıklaması şöyle
Project Panama represents a significant advancement in the Java ecosystem, primarily focusing on enhancing Java’s interaction with foreign APIs, particularly those written in languages like C and C++. Traditionally, Java used the Java Native Interface (JNI) to invoke foreign functions, but JNI had several limitations. Project Panama addresses these by removing the need to write native code wrappers in Java, replacing the ByteBuffer API with a more advanced Memory API, and introducing a secure, memory-efficient method to invoke native code from Java. The project comprises several key components, including the Foreign-Function and Memory API, the Vector API, and the JExtract tool​​.

19 Ocak 2024 Cuma

JEP 401 - Project Valhalla - Improve Java’s Memory Efficiency

Giriş
Java'nın kullandığı Memory Model özellikle Integer[] gibi yapılarda işlemcinin israf edilmesine sebep oluyor. Bunu gösteren bir şekil burada

Sebebi ise şöyle
Accessing the value of an Integer (non-primitive) includes an extra memory access
Çünkü her bir Integer için kullanılan Metadata nesnesi bellekte rastgele bir yerde duruyor
Bu da günümüzdeki modern işlemcilerde CPU cache israfına sebep oluyor

Project Valhalla
İlk fikir 2014 yılında ortaya atıldı. Açıklaması şöyle
... give the user the ability to flatten his objects and enjoy the performance of primitives in exchange for some limitations ...
Kod olarak şöyle
// Before
public class Point {
  private final int x;
  private final int y;
}

// After
public primitive class Point {
  private final int x;
  private final int y;
}



7 Ocak 2024 Pazar

GSON Kullanımı

Maven
Şu satırı dahil ederiz
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.9</version>
</dependency>
Gson Sınıfı
Gson Sınıfı toJson() ile nesneyi JSON String'e çevirir. fromJson() ile JSON String'den nesneye çevirir

@SerializedName Anotasyonu
@SerializedName Anotasyonu yazısına taşıdım

@Expose Anotasyonu
@Expose Anotasyonu yazısına taşıdım

@Since Anotasyonu
@Since Anotasyonu yazısına taşıdım

Gson @Since Anotasyonu - Specify Version Information For Fields

Örnek
Şöyle yaparız
import com.google.gson.annotations.Since;
import com.google.gson.annotations.Until;

public class Product {
    @Since(1.0)
    private String name;
    @Until(2.0)
    private double price;

    // getters and setters
}


2 Ocak 2024 Salı

Hikari API HikariDataSource Sınıfı

Giriş
Şu satırı dahil ederiz
import com.zaxxer.hikari.HikariDataSource;
constructor
Örnek
Hikari sayfasındaki örnek şöyle
HikariConfig config = ...
HikariDataSource ds = new HikariDataSource(config);
isClosed metodu
Sınıf şöyle
public class HikariDataSource extends HikariConfig implements DataSource, Closeable {
  ...
  private final AtomicBoolean isShutdown = new AtomicBoolean();
  ...
}
Metodun içi şöyle
public boolean isClosed() {
  return isShutdown.get();
}

1 Ocak 2024 Pazartesi

JEP 359 record ve Builder

Örnek
Elimizde şöyle bir kod olsun
public record FilmWithRecord(String title, String director, int releaseYear) {
  
public static class Builder {
  private String title;
  private String director;
  private int releaseYear;

  public Builder title(String title) {
   this.title = title;
   return this;
  }

  public Builder director(String director) {
   this.director = director;
   return this;
  }

  public Builder releaseYear(int releaseYear) {
   this.releaseYear = releaseYear;
   return this;
  }

  public FilmWithRecord build() {
   return new FilmWithRecord(title, director, releaseYear);
  }
  }
}
Kullanmak için şöyle yaparız
// Example of using the builder:
FilmWithRecord film = new FilmWithRecord
 .Builder()
 .title("The Dark Knight")
 .director("Christopher Nolan")
 .releaseYear(2008)
 .build();

26 Aralık 2023 Salı

Logback logback.xml FileAppender Tanımlama

Örnek
Şöyle yaparız. Burada farklı log seviyeleri farklı dosyalara gönderiliyor. ch.qos.logback.classic.filter.ThresholdFilter ve ch.qos.logback.classic.filter.LevelFilter kullanılıyor. 
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="WARN">

  <property name="logging.error.file.name" value="error-log" />
  <property name="logging.error.file.path" value="./"/>
  <property name="logging.file.name" value="info-log" />
  <property name="logging.file.path" value="./"/>

  <!-- Normal log appender -->
  <appender name="INFO_FILE" class="ch.qos.logback.core.FileAppender">
    <file>${logging.file.path}/${logging.file.name}</file>
    <encoder>
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
    </encoder>
    <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>INFO, DEBUG, TRACE</level>
    </filter>
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
      <level>ERROR, WARN</level>
      <onMatch>DENY</onMatch>
      <onMisMatch>NEUTRAL</onMisMatch>
    </filter>
  </appender>

  <!-- Error log appender -->
  <appender name="ERROR_FILE" class="ch.qos.logback.core.FileAppender">
    <file>${logging.error.file.path}/${logging.error.file.name}</file>
      <encoder>
        <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
      </encoder>
      <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
        <level>ERROR, WARN</level>
      </filter>
      <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <level>INFO, DEBUG, WARN</level>
        <onMatch>DENY</onMatch>
        <onMisMatch>NEUTRAL</onMisMatch>
      </filter>
    </appender>

  <root level="INFO">
    <appender-ref ref="INFO_FILE"/>
    <appender-ref ref="ERROR_FILE"/>
  </root>
</configuration>
Açıklaması şöyle
- Trace < Debug < Info < Warn < Error < Fatal

- LevelFilter filters events based on exact level matching. If the event's level is equal to the configured level, the filter accepts or denies the event, depending on the configuration of the onMatch and onMismatch properties.

- The ThresholdFilter filters events below the specified threshold. 
1. Normal appender ThresholdFilter ile INFO, DEBUG, TRACE olaylarının altındakileri kabul etmez. 

2. Error appender ThresholdFilter ile ERROR, WARN olaylarının altındakileri kabul etmez.



14 Aralık 2023 Perşembe

TestContainers LocalStackContainer Sınıfı - SQS İle Kullanım

Örnek
1. Şöyle yaparız. Burada SQS_ENDPOINT_STRATEGY path veriliyor. Böylece kuyruğa erişmek için üretilen URL http://localhost:8701/queue/us-east-1/000000000000/myqueue şeklinde oluyor. Eğer böyle yapmazsak UnknownHostException alırız
2. Eğer istenirse awslocal komutu container içinde çalıştırılabilir.
@ClassRule
public static LocalStackContainer container = 
  new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.0.2"))
  .withServices(LocalStackContainer.Service.SQS)
  .withEnv("SQS_ENDPOINT_STRATEGY", "path"); // Burası

@BeforeClass
public static void beforeClass() {
  container.execInContainer("awslocal",
    "sqs",
    "create-queue",
    "--queue-name",
    "myqueue");
}
SQSClient ile kullanmak için şöyle yaparız. SQSClient  aws.accessKeyId ve aws.secretKey değişkenlerini istiyor. Yoksa  "Unable to load AWS credentials from any provider in the chain ..." hatası alırız
void insertData() throws URISyntaxException {
  System.setProperty("aws.accessKeyId", container.getAccessKey());
  System.setProperty("aws.secretKey", container.getSecretKey());

  SqsClient sqs = SqsClient.builder()
    .endpointOverride(container.getEndpointOverride(LocalStackContainer.Service.SQS))
    .credentialsProvider(
      StaticCredentialsProvider.create(
        AwsBasicCredentials.create(container.getAccessKey(), container.getSecretKey())
      )
    )
    .region(Region.of(container.getRegion()))
    .build();
    ...
}

13 Aralık 2023 Çarşamba

Lettuce - Redis Stream Örnekleri

xadd metodu
İmzası şöyle. Stream'e yeni veri ekler
String xadd(K key, Map<K, V> body);
Örnek
Bu örnekte Lettuce ile Testcontainers ile başlatılan Redis Stream'e veri yazılıyor.  Örneğin bir kısmını Getting Started with Redis Streams and Java yazısından aldım

Maven için şu satırı dahil ederiz
<dependency>
<groupId>com.redis</groupId> <artifactId>testcontainers-redis</artifactId> <version>2.0.1</version> <scope>test</scope> </dependency> <dependency> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> <version>6.2.3.RELEASE</version> </dependency>
Şöyle yaparız. Burada JUnit4 kullanıldığı için @ClassRule anotasyonu var.
import com.redis.testcontainers.RedisContainer;

@ClassRule
public static final RedisContainer container = 
  new RedisContainer(DockerImageName.parse("redis:6.2.6"))
  .withLogConsumer(new Slf4jLogConsumer(LOGGER).withPrefix("Docker"));
Veri ile doldururuz. Şöyle yaparız. Artık aboneler veriyi okuyabilir.
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

void insertData() {
  String redisURI = container.getRedisURI();
  try (RedisClient client = RedisClient.create(redisURI);
       StatefulRedisConnection<String, String> connection = client.connect()) {

    RedisCommands<String, String> syncCommands = connection.sync();

    for (int index = 0; index < ITEM_COUNT; index++) {
      // Redis Streams messages are string key/values in Java.
      Map<String, String> messageBody = createMessageBody(index);

      String messageId = syncCommands.xadd(
        STREAM_NAME,
        messageBody);

        LOGGER.info("Message {} : {} posted", messageId, messageBody);
    }
  }
}

Map<String, String> createMessageBody(int index) {
  Map<String, String> messageBody = new HashMap<>();
  messageBody.put("speed", String.valueOf(index));
  messageBody.put("direction", "270");
  messageBody.put("sensor_ts", String.valueOf(System.currentTimeMillis()));
  return messageBody;
}


12 Aralık 2023 Salı

JDBC Sürücüsü Yazma

Giriş
Böyle bir şey ilk defa hazelcast-jdbc projesinin hazelcast-jdbc-core modülünde şahit oldum

Bize gereken sınıflar şöyle
java.sql.Connection
java.sql.Driver
java.sql.DatabaseMetaData
java.sql.PreparedStatement
java.sql.ResultSet
java.sql.ResultSetMetaData
java.sql.Statement

java.sql.DriverManager Sınıfı
java.sql.DriverManager sınıfından kalıtmaya gerek yok. Açıklaması şöyle
The DriverManager class included with the java.sql package tracks the loaded JDBC drivers. The client application retrieves the desired database connections through the DriverManager class
getConnection metodu
java.sql.DriverManager#getConnection("jdbc:...") metodu kendisine kayıtlı tüm Driver nesnelerine teker teker belirtilen JDBC adresini kabul edip etmediğini sorar. Kabul eden yani bağlantı açan ilk Driver nesnesini döndürür.