31 Ocak 2023 Salı

Stream.peek metodu - Dikkatli Olmak Lazım

Tüm elemenlar için çağrılır.forEach() ile benzer ancak esas amacı debug içindir. Açıklaması şöyle.
This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline
SonarLint açıklaması şöyle
According to its JavaDocs, the intermediate Stream operation java.util.Stream.peek() “exists mainly to support debugging” purposes.

A key difference with other intermediate Stream operations is that the Stream implementation is free to skip calls to peek() for optimization purpose. This can lead to peek() being unexpectedly called only for some or none of the elements in the Stream.

As a consequence, relying on peek() without careful consideration can lead to error-prone code.
This rule raises an issue for each use of peek() to be sure that it is challenged and validated by the team to be meant for production debugging/logging purposes.
Verilen örnek şöyle
// Noncompliant Code Example
Stream.of("one", "two", "three", "four")
         .filter(e -> e.length() > 3)
         .peek(e -> System.out.println("Filtered value: " + e));

// Compliant Solution
Stream.of("one", "two", "three", "four")
         .filter(e -> e.length() > 3)
         .foreach(e -> System.out.println("Filtered value: " + e));
Debug
Örnek
Şöyle yaparız.
"abcd".chars().peek(e->System.out.print(e + ":"))
Çıktı olarak şunu alırız.
a:b:c:d:
Örnek
Şöyle yaparız.
Stream.of("one", "two", "three", "four")
  .filter(e -> e.length() > 3)
  .peek(e -> System.out.println("Filtered value: " + e))
  .map(String::toUpperCase)
  .peek(e -> System.out.println("Mapped value: " + e))
  .collect(Collectors.toList());
Setter Çağırmak
Açıklaması şöyle. Yani debug amacı dışında kullanılması yasak değil, ama teşvik te edilmiyor. Dolayısıyla tüm sorumluluk kodlayan kişide.
We can see that non-debugging usages are neither forbidden nor discouraged.
Örnek
Elimizde şöyle bir kod olsun. Burada peek() çağrılıyor. 
// The problem is that this behavior is highly deceiving because certain 
// Stream implementations can optimize out peek() calls.

Stream.of(Date.from(Instant.EPOCH))
  .peek(d -> d.setTime(Long.MAX_VALUE))
  .forEach(System.out::println);

// Sun Aug 17 08:12:55 CET 292278994
Ancak çağrılmadığı durumlar da olabilir. Bazı örnekler şöyle
List.of(1, 2, 3)
  .stream()
  .peek(System.out::println)
  .count();
// The result is empty

Stream.iterate(0, i -> i + 1)
  .peek(System.out::println)
  .findFirst();
// The result is empty
Örnek
Şöyle yaparız.
List<Foo> newFoos = foos.stream()
            .filter(Foo::isBlue)
            .peek(foo -> foo.setTitle("Some value"))
            .collect(Collectors.toList());
Hesap Yapmak
Örnek

Kalan yüzdeyi yazdırmak için kullanılabilir. Şöyle yaparız.
Stream<MyData> myStream = readData();
final AtomicInteger loader = new AtomicInteger();
int fivePercent = elementsCount / 20;
MyResult result = myStream
  .map(row -> process(row))
  .peek(stat -> {
    if (loader.incrementAndGet() % fivePercent == 0) {
      System.out.println(loader.get() + " elements on " + elementsCount + " treated");
      System.out.println((5*(loader.get() / fivePercent)) + "%");
    }
  })
  .reduce(MyStat::aggregate);

30 Ocak 2023 Pazartesi

Class.getDeclaredMethod metodu

Giriş
- Access modifier tipine bakmaksızın nesnenin tanımladığı - kalıtımla gelen hariç - ismi belirtilen metodu döner. 
- Class.getDeclaredMethod bir metodunun istenilen şeyi bulabilmesi için metoda geçilen parametrelerin de yani doğru verilmesi gerekir.

Örnek - public method
Elimizde şöyle bir sınıf olsun. Erişmek istediğiniz metod public.
public class Foo {
  public void isFoo(Object obj) {
    ...
  }
}
Metodu bulmak için şöyle yaparız.
Class c = Foo.class;
Method m = c.getDeclaredMethod("isFoo", Object.class);
Metodumuz birden çok parametre alsaydı ikinci parametreyi bir dizi olarak geçebilirdik.
String methodName = ...;
Class[] types = ...;
Method method = c.getDeclaredMethod(methodName, types);
Örnek - protected method
Elimizde şöyle bir sınıf olsun. Bu sefer erişmek istediğimiz metod protected.
public class PrivateCar {

  private String color;

  protected void drive() {
    System.out.println("this is private car! the color is:" + color);
  }
}
Şöyle yaparız.
Class clazz = loader.loadClass("javaReflect.test.PrivateCar");
Method method = clazz.getDeclaredMethod("drive");
Örnek - Method İmzası
MyClass sınıfı içinde bir main metodu olsun. 
public static void main(String[] args) {...}
Onu bulmak için şöyle yaparız. Burada metod imzasında parametrenin String[] olduğunu belirmek gerekiyor.
Method mainMethod = MyClass.classgetDeclaredMethod("main", String[].class);
Diğer
Örnek

Elimizde Foo ata sınıfı olsun.
public class Foo {
  public void doit() {
    System.out.println("good");
  }
}
Bu sınıftan kalıtan Bar sınıfı olsun
public class Bar extends Foo {
  public void doit() {
    System.out.println("bad");
  }
}
Method nesnesine Foo.class olarak erişsek bile ve hatta çağırırken yine Foo sınıfına cast etsek bile Bar sınıfının doIt() metodu çağrılır. Çıktı olarak bad alırız.
Bar b = new Bar();
/* Using Foo.class */
Method m = Foo.class.getDeclaredMethod("doit", new Class[]{});

m.invoke((Foo)b, new Object[]{});