Showing posts with label Java SE 9. Show all posts
Showing posts with label Java SE 9. Show all posts

Friday, July 14, 2017

Java SE 7 Kodunu Java SE 9'a Taşımak


Bu yazıda Java SE 7 ve öncesinde yazılmış bir uygulamada yer alan dizi ve torbalar üzerinde gerçekleştirilmiş döngülerin Java SE 9'a taşınması ile ilgili bir örnek ele alınacaktır. Aşağıda UML sınıf çizgesi verilen alan modelini önce Java 7'de kodlayalım:




Animal.java:

package com.example.animals.domain;

/**
 * 
 * @author Binnur KURT (binnur.kurt@gmail.com)
 *
 */
public abstract class Animal {
 protected int legs;

 public Animal(int legs) {
  this.legs = legs;
 }

 public int getLegs() {
  return legs;
 }

 public void walk() {
  System.out.println("Animal is walking now...");
 }

 public abstract void eat();
}

Pet.java:

package com.example.animals.domain;

/**
 * 
 * @author Binnur KURT (binnur.kurt@gmail.com)
 *
 */
public abstract interface Pet {
 void setName(String name);

 String getName();

 public abstract void play();
}

Spider.java:

package com.example.animals.domain;

/**
 * 
 * @author Binnur KURT (binnur.kurt@gmail.com)
 *
 */
public class Spider extends Animal {

 public Spider() {
  super(8);
 }

 @Override
 public void eat() {
  System.out.println("Spider is eating now...");
 }

 @Override
 public String toString() {
  return "Spider [legs=" + legs + "]";
 }

}

Cat.java:

package com.example.animals.domain;

/**
 * 
 * @author Binnur KURT (binnur.kurt@gmail.com)
 *
 */
public class Cat extends Animal implements Pet {
 private String name;

 public Cat() {
  this("Garfield");
 }

 public Cat(String name) {
  super(4);
  this.name = name;
 }

 @Override
 public void setName(String name) {
  this.name = name;
 }

 @Override
 public String getName() {
  return name;
 }

 @Override
 public void play() {
  System.out.println(name + " is playing now...");
 }

 @Override
 public void eat() {
  System.out.println(name + " is eating now...");
 }

 @Override
 public String toString() {
  return "Cat [name=" + name + ", legs=" + legs + "]";
 }

}

Fish.java:

package com.example.animals.domain;

/**
 * 
 * @author Binnur KURT (binnur.kurt@gmail.com)
 *
 */
public class Fish extends Animal implements Pet {
 private String name;

 public Fish() {
  this("Nemo");
 }

 public Fish(String name) {
  super(0);
  this.name = name;
 }

 @Override
 public void setName(String name) {
  this.name = name;
 }

 @Override
 public String getName() {
  return name;
 }

 @Override
 public void play() {
  System.out.println(name + " is playing now...");
 }

 @Override
 public void eat() {
  System.out.println(name + " is eating now...");
 }

 @Override
 public void walk() {
  System.out.println(name + " is swimming now...");
 }

 @Override
 public String toString() {
  return "Fish [name=" + name + ", legs=" + legs + "]";
 }

}

Şimdi bu alan modelini kullanan bir uygulama kodunu Java 7'de kodlayalım:

package com.example.animals.application;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.example.animals.domain.Animal;
import com.example.animals.domain.Cat;
import com.example.animals.domain.Fish;
import com.example.animals.domain.Pet;
import com.example.animals.domain.Spider;

/**
 * 
 * @author Binnur KURT (binnur.kurt@gmail.com)
 *
 */
public class AnimalAppInJava7 {

    public static void main(String[] args) {
        List<Animal> animals = Arrays.asList(
            new Spider(), 
            new Cat(), 
            new Fish("Free Willy"), 
            new Cat("Tekir"),                        
            new Fish("Jaws"), 
            new Spider()
        );
        
        for (Animal animal : animals) {
            animal.walk();
            animal.eat();
            if (animal instanceof Pet) {
                ((Pet) animal).play();
            }
        }
        
        List<Animal> wildAnimals = new ArrayList<>();
        for (Animal animal : animals) {
            if (!(animal instanceof Pet))
                wildAnimals.add(animal);
        }
        System.out.println("Wild Animals: "+wildAnimals);        
        
        List<Pet> pets = new ArrayList<>();
        for (Animal animal : animals) {
            if (animal instanceof Pet)
                pets.add((Pet) animal);
        }
        System.out.println("Pets: "+pets);
        
        int maxLegs= -1;
        for (Animal animal: animals){
            final int legs = animal.getLegs();
            if (legs>maxLegs) maxLegs= legs;
        }
        System.out.println("max number of legs: "+maxLegs);
    }

}

Java SE 7'de yazdığımız uygulamada ağırlıklı olarak Java SE 5'de gelen for döngüsünü kullanarak torbalar üzerinde çalışan döngüler kurduk. Şimdi birebir aynı işi yapan uygulamayı Java SE 9'da kodlayalım:

package com.example.animals.application;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import com.example.animals.domain.Animal;
import com.example.animals.domain.Cat;
import com.example.animals.domain.Fish;
import com.example.animals.domain.Pet;
import com.example.animals.domain.Spider;

/**
 * 
 * @author Binnur KURT (binnur.kurt@gmail.com)
 *
 */
public class AnimalAppInJava9 {

    public static void main(String[] args) {
        List<Animal> animals= List.of(
            new Spider(),
            new Cat(),
            new Fish("Free Willy"),
            new Cat("Tekir"),
            new Fish("Jaws"),
            new Spider()
        );

        Class<Pet> clazz = Pet.class;
        Consumer<Animal> walk = Animal::walk;
        Consumer<Animal> eat = Animal::eat;
        Consumer<Animal> playIfPet = animal -> {
            if (clazz.isInstance(animal)) 
                clazz.cast(animal).play();
        };
        animals.forEach(walk.andThen(eat).andThen(playIfPet));
        
        Predicate<? super Animal> isPet = animal -> animal instanceof Pet;
        animals.stream().filter(isPet).map(Pet.class::cast).forEach(Pet::play);

        List<Animal> pets= animals.stream()
                                  .filter(isPet)
                                  .collect(Collectors.toList());
        System.out.println("Pets: "+pets);
        
        Predicate<? super Animal> isWild= isPet.negate();
        List<Animal> wildAnimals= animals.stream()
                                    .filter(isWild)
                                    .collect(Collectors.toList());
        System.out.println("Wild animals: "+wildAnimals);

        animals.stream().map(Animal::getLegs)
                        .max(Integer::compare)
                        .ifPresent(System.out::println);
    }

}

Java 7 ve öncesinde uzun uzun yazdığımız döngüleri Java 9'da tek satırlık ifadelerle karşılamak mümkün:
  • Önce hayvanları yürüyüşe çıkaralım, ardından karınlarını doyuralım ve evcil olanları ile oyun oynayalım:
animals.forEach(walk.andThen(eat).andThen(playIfPet));
  • Evcil hayvanlar ile oyun oynayalım:
animals.stream().filter(Pet.class::isInstance).map(Pet.class::cast).forEach(Pet::play);
  • Vahşi hayvanların listesini alalım:
animals.stream().filter(isWild).collect(Collectors.toList());
  • Evcil hayvanların listesini alalım:
animals.stream().filter(isPet).collect(Collectors.toList());
  • En çok ayağa sahip hayvanda kaç adet ayak bulunur:
animals.stream().map(Animal::getLegs).max(Integer::compare).ifPresent(System.out::println);
  • Hayvanların toplam ayak sayısı:
int numberOfLegs= animals.stream().mapToInt(Animal::getLegs).sum();

Tek Satırlık İfadeler

Java SE 8'de gelen Fonksiyonel Programlama, Stream API ve MapReduce çatıları sayesinde çözümü tek satırlık ifadelerle oluşturabiliyoruz. Bu tek satırlık ifadelere örnekler oluşturabilmek amacıyla yukardıki örnek alan modelini kullanarak, farklı problemler çözelim.  

1. Java 9'da rastgele olarak 100 Animal türünden nesne ile dolu bir liste elde etmeye çalışalım:

List<Supplier<Animal>> constructors= List.of(Spider::new,Cat::new,Fish::new);
List<Animal> randomAnimals= 
          new Random().ints(0,constructors.size())
                      .limit(100)
                      .mapToObj(constructors::get)
                      .map( Supplier::get )
                      .collect( Collectors.toList() );
randomAnimals.forEach(System.out::println);

2. Her bir Animal türünden kaç adet nesne var sınıflandırmaya çalışalım:

Function<Animal, String> groupByClassName = animal -> animal.getClass().getSimpleName();
Map<String, Long> animalCountsByClassName = 
        randomAnimals.stream()
               .collect(
                   Collectors.groupingBy( groupByClassName, Collectors.counting() )
               );
System.out.println(animalCountsByClassName);

Yukarıdaki kod parçasını çalıştırdığımızda ekranda aşağıdaki gibi bir ileti alıyoruz:

{Cat=36, Spider=35, Fish=29}

3. Aynı ayak sayısına sahip hayvanların listesini alalım:

Function<Animal, String> classNameMapper = animal -> animal.getClass().getSimpleName();
Map<Integer, Set<String>> animalCountsByLegs = 
    randomAnimals.stream().collect(
        Collectors.groupingBy(
            Animal::getLegs,
            Collectors.mapping(classNameMapper,Collectors.toSet())
        )
    );        
System.out.println(animalCountsByLegs);

Yukarıdaki kod parçasını çalıştırdığımızda ekranda aşağıdaki gibi bir ileti alıyoruz:

{0=[Fish], 4=[Cat], 8=[Spider]}

4. Hayvanları önce ayak sayısına göre, ayak sayıları eşit olanları ise sınıf adına göre sıralı olacak şekilde ekrana yazmak istiyoruz:

final Comparator<Animal> compareByLegNumbers = (left,right) -> left.getLegs() - right.getLegs();
final Comparator<Animal> compareByClassName = (left,right) -> left.getClass().getSimpleName().compareTo(right.getClass().getSimpleName());
randomAnimals.stream().sorted(compareByLegNumbers.thenComparing(compareByClassName)).forEach(System.out::println);

5. Dört ayaklı evcil hayvanlar içerisinde en kalabalık türün adını bulmaya çalışalım:

final Predicate<? super Animal> isPet = animal -> animal instanceof Pet;        
final Comparator<Animal> compareByClassName = (left,right) -> left.getClass().getSimpleName().compareTo(right.getClass().getSimpleName());
final Function<Animal, String> classNameMapper = animal -> animal.getClass().getSimpleName();
final Comparator<Animal> compareByLegNumbers = (left,right) -> left.getLegs() - right.getLegs();
final Collector<Animal, ?, Map<String, Long>> clusterByAnimalTypeAndCountClusterSize = Collectors.groupingBy(classNameMapper,Collectors.counting());
final Comparator<Map.Entry<String, Long>> clusterSizeComparator = (e1,e2) -> Long.valueOf(e1.getValue() - e2.getValue()).intValue();
randomAnimals.stream()
             .filter(isPet)
             .collect(clusterByAnimalTypeAndCountClusterSize)
             .entrySet()
             .stream()
             .max(clusterSizeComparator)
             .map(Map.Entry::getKey)
             .ifPresent(System.out::println);

Thursday, April 27, 2017

Creating Strong Password using Stream API of Java 9


Creating a strong password has never been so easy in Java when Stream API is used. Stream API is introduced in Java SE 8 and has changed the way we think and develop in Java together with the functional programming and lambda expressions. Java 9 will improve the Stream API with new convenience methods. Stream API is basically designed to work with collections in functional style. I would like to exemplify this new way of thinking simply by creating a strong password: 

package com.example.java9.features;

import java.security.SecureRandom;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public final class StrongPasswordApplication {
    private static final List<String> CHARACTER_TABLE= List.of(
        "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
        "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", 
        "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
        "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", 
        "0", "1", "2", "3", "4", "5", "6","7","8","9",
        "_", "-", "$", "@", "#", "?", "%" 
    );
    public static String create(int length){
        return new SecureRandom()
                .ints(0,CHARACTER_TABLE.size())
                .limit(length)
                .boxed()
                .map( CHARACTER_TABLE::get )                
                .collect(Collectors.joining());
    }    
}

There are new methods added to the Stream interface in Java 9: dropWhile, takeWhile, ofNullable. Now, we allow the application programmer to define what strong password is and create a password that conforms that definition:

package com.example.java9.features;

import java.security.SecureRandom;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class RandomPasswordApplication {

    private static final List<String> CHARACTER_TABLE = List.of(
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
            "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
            "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
            "_", "-", "$", "@", "#", "&", "%", "/", "\\", "?",
            "*", "+", "!", ".", ",", ";", "~", "'", "\"", "<", ">"
    );

    public static void main(String[] args) {
        IntStream.range(8, 15)
                .boxed()
                .map(RandomPasswordApplication::createpassword)
                .map(password -> String.format("Password [length=%d] is %s", password.length(), password))
                .forEach(System.out::println);
    }

    public static String createpassword(int length) {
        final StrongPassword strongness = new StrongPassword.Builder()
                .minimumNumberOfDigits(1)
                .minimumNumberOfSpecialCharacters(1)
                .minimumNumberOfCapitalLetters(1)
                .minimumLength(length)
                .build();
        return new SecureRandom()
                .ints(0, CHARACTER_TABLE.size())
                .boxed()
                .map(CHARACTER_TABLE::get)
                .takeWhile(strongness::isWeek)
                .collect(Collectors.joining());
    }

}

StrongPassword class defines the strongness of the password:

package com.example.java9.features;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class StrongPassword {

    private final int minimumNumberOfDigits;
    private final int minimumNumberOfCapitalLetters;
    private final int minimumNumberOfSpecialCharacters;
    private final int minimumLength;
    private int length;
    private int numberOfDigits;
    private int numberOfSpecialCharacters;
    private int numberOfCapitalLetters;

    private StrongPassword(Builder builder) {
        this.minimumNumberOfDigits = builder.minimumNumberOfDigits;
        this.minimumNumberOfCapitalLetters = builder.minimumNumberOfCapitalLetters;
        this.minimumNumberOfSpecialCharacters = builder.minimumNumberOfSpecialCharacters;
        this.minimumLength = builder.minimumLength;
    }

    public boolean isWeek(String s) {
        final boolean isWeekPassword = (length < minimumLength)
                || (numberOfDigits < minimumNumberOfDigits)
                || (numberOfSpecialCharacters < minimumNumberOfSpecialCharacters)
                || (numberOfCapitalLetters < minimumNumberOfCapitalLetters);
        length++;
        if (Character.isDigit(s.charAt(0))) {
            numberOfDigits++;
        } else if (!Character.isLetter(s.charAt(0))) {
            numberOfSpecialCharacters++;
        } else if (s.equals(s.toUpperCase())) {
            numberOfCapitalLetters++;
        }
        return isWeekPassword;
    }

    public static class Builder {

        private int minimumNumberOfDigits;
        private int minimumNumberOfCapitalLetters;
        private int minimumNumberOfSpecialCharacters;
        private int minimumLength;

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

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

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

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

        public StrongPassword build() {
            return new StrongPassword(this);
        }
    }
}

One example output of the execution is given below:

Password [length=8] is k@\D%b16
Password [length=9] is "+fORbi9f
Password [length=10] is D35g,'7zKN
Password [length=11] is PJTnpN~YN1o
Password [length=12] is 2AD!H"xGhBZd
Password [length=13] is b+A9-Ovzc+,RD
Password [length=14] is *@Nj\89nW7ep5B

You could retrieve the code from this URL as NetBeans IDE Dev (Build 2017-06-14-0001) project.