SlideShare ist ein Scribd-Unternehmen logo
1 von 96
LEKCJA STYLU
  czy w Javie można jeszcze dostrzec piękno?




Wiktor Gworek   •   Javarsovia 2010   •   Google
@wwiktorr ^wwiktorr

  wiktorgworek.com
blog.mocna-kawa.com
PIĘKNO KODU
definicja dla Javy
czytelność

                                    boilerplate
   łatwe
testowanie
              PIĘKNO KODU
              definicja dla Javy


          statyczne
                                  narzędzia
         typowanie
NARZĘDZIA
• Google Guava
  • http://code.google.com/p/guava-libraries/
• Google Guice
  • http://code.google.com/p/google-guice/
• Mockito
  •   http://code.google.com/p/mockito/
Czytelność   Funkcyjność
POPRAWIANIE
                                                  CZYTELNOŚCI

http://www.flickr.com/photos/jleveque/2151484964
“Jejku, ten kod wygląda, jakby go pisał sam
 Steven King. Horror, aż strach przejść na
 kolejną stronę.”

                       – anonimowy programista
if (GOOGLE) {
  CODE.STYLE();
}
100 znaków



if (GOOGLE) {
  CODE.STYLE();
}
100 znaków



if (GOOGLE) {
 t
  CODE.STYLE();
}
100 znaków



if (GOOGLE) {
 t
  CODE.STYLE();
}
2 znaki
100 znaków



if (GOOGLE) {
 t
  CODE.STYLE();
}
2 znaki
KODOWANIE DEFENSYWNE




                http://www.flickr.com/photos/mosca27/166707333/
KODOWANIE DEFENSYWNE

 public void analyze(String msg) {
  if (msg == null) {
    throw NullPointerException();
  }
  if (msg.length() > 160) {
    throw IllegalArgumentException(
       “Tak długa wiadomość?”);
  }

     // analiza wiadomości
 }
KODOWANIE DEFENSYWNE

 public void analyze(String msg) {
  Preconditions.checkNotNull(msg);
  Preconditions.checkArgument(
     msg.length() <= 160,
     “Tak długa wiadomość?”);


     // analiza wiadomości
 }
ZBĘDNY KOD
KOLEKCJE
com.google.common.collect

     Map<String, List<User, Role>> map =
       new HashMap<String, List<User, Role>>;
KOLEKCJE
com.google.common.collect

       Map<String, List<User, Role>> map =
         new HashMap<String, List<User, Role>>;




Map<String, List<User, Role>> m = Maps.newHashMap();

List<Long> l = Lists.newArrayListWithExpectedSize(3);

Set<Pair<String, User>> set = Sets.newHashSet();

Set<String> set = Sets.newHashSet(“a”, “b”, “c”);
NIEMODYFIKOWANE OBIEKTY
NIEMODYFIKOWANE OBIEKTY
   public void setName(String newName);


  private final Address address;
NIEMODYFIKOWANE OBIEKTY
   public void setName(String newName);


  private final Address address;


  // Wykorzystanie Protocol Buffers

  Post newPost = post.toBuilder()
    .setTitle(newTitle)
    .build();
KOLEKCJE
com.google.common.collect

 List<String> list = new ArrayList<String>();
 list.add(“a”);
 list.add(“b”);
 list.add(“c”);


 public static final Set<Integer> LUCKY_NUMBERS;
 static {
   Set<Integer> set = new LinkedHashSet<Integer>;
   set.add(4);
   set.add(7);
   set.add(42);
   LUCKY_NUMBERS = Collections.unmodifiableSet(set);
 }
KOLEKCJE
com.google.common.collect



 public static final Set<Integer> LUCKY_NUMBERS =
  Collections.unmodifiableSet(
   new LinkedHashSet<Integer>(
    Arrays.asList(4, 7, 42)));
KOLEKCJE
com.google.common.collect
KOLEKCJE
com.google.common.collect


List<String> list = ImmutableList.of(“a”, “b”, “c”);
KOLEKCJE
com.google.common.collect


List<String> list = ImmutableList.of(“a”, “b”, “c”);




static final Set<Integer> LUCKY_NUMBERS =
   ImmutableSet.of(4, 7, 42);
KOLEKCJE
com.google.common.collect


List<String> list = ImmutableList.of(“a”, “b”, “c”);




static final Set<Integer> LUCKY_NUMBERS =
   ImmutableSet.of(4, 7, 42);




static final Map<String, String> FORBIDDEN =
   ImmutableMap.of(“key1”, “val1”, “key2”, “val2”);
ZNOWU TO SAMO...




                   http://www.flickr.com/photos/nifmus/2385966735/
KOLEKCJE
com.google.common.collect


 Map<String, List<String>> map = Maps.newHashMap();

 for (Pair<String, String> pair : input) {
   if (map.containsKey(pair.fst)) {
     map.get(pair.fst).add(pair.snd);
   } else {
     map.put(pair.fst, Lists.newArrayList(pair.snd));
   }
 }

 List<String> result = map.get(“Kasia”);
KOLEKCJE
com.google.common.collect


 Map<String, List<String>> map = Maps.newHashMap();

 for (Pair<String, String> pair : input) {
   if (map.containsKey(pair.fst)) {
     map.get(pair.fst).add(pair.snd);
   } else {
     map.put(pair.fst, Lists.newArrayList(pair.snd));
   }
 }

 List<String> result = map.get(“Kasia”);
KOLEKCJE
com.google.common.collect


 Map<String, List<String>> map = Maps.newHashMap();

 for (Pair<String, String> pair : input) {
   if (map.containsKey(pair.fst)) {
     map.get(pair.fst).add(pair.snd);
   } else {
     map.put(pair.fst, Lists.newArrayList(pair.snd));
   }
 }

 List<String> result = map.get(“Kasia”);
KOLEKCJE
com.google.common.collect


 Map<String, List<String>> map = Maps.newHashMap();

 for (Pair<String, String> pair : input) {
   if (map.containsKey(pair.fst)) {
     map.get(pair.fst).add(pair.snd);
   } else {
     map.put(pair.fst, Lists.newArrayList(pair.snd));
   }
 }

 List<String> result = map.get(“Kasia”);
KOLEKCJE
com.google.common.collect


 Map<String, List<String>> map = Maps.newHashMap();

 for (Pair<String, String> pair : input) {
   if (map.containsKey(pair.fst)) {
     map.get(pair.fst).add(pair.snd);
   } else {
     map.put(pair.fst, Lists.newArrayList(pair.snd));
   }
 }

 List<String> result = map.get(“Kasia”);
KOLEKCJE
com.google.common.collect


 Map<String, List<String>> map = Maps.newHashMap();

 for (Pair<String, String> pair : input) {
   if (map.containsKey(pair.fst)) {
     map.get(pair.fst).add(pair.snd);
   } else {
     map.put(pair.fst, Lists.newArrayList(pair.snd));
   }
 }

 List<String> result = map.get(“Kasia”);
KOLEKCJE
com.google.common.collect



 Multimap<String, String> multimap =
   ArrayListMultimap.create();

 for (Pair<String, String> pair : input) {
   multimap.put(pair.fst, pair.snd);
 }

 List<String> result = multimap.get(“Kasia”);
KOLEKCJE
com.google.common.collect



 Multimap<String, String> multimap =
   ArrayListMultimap.create();

 for (Pair<String, String> pair : input) {
   multimap.put(pair.fst, pair.snd);
 }

 List<String> result = multimap.get(“Kasia”);
KOLEKCJE
com.google.common.collect



 Multimap<String, String> multimap =
   ArrayListMultimap.create();

 for (Pair<String, String> pair : input) {
   multimap.put(pair.fst, pair.snd);
 }

 List<String> result = multimap.get(“Kasia”);
KOLEKCJE
com.google.common.collect



 Multimap<String, String> multimap =
   ArrayListMultimap.create();

 for (Pair<String, String> pair : input) {
   multimap.put(pair.fst, pair.snd);
 }

 List<String> result = multimap.get(“Kasia”);
KOLEKCJE
com.google.common.collect



 Multimap<String, String> multimap =
   ArrayListMultimap.create();

 for (Pair<String, String> pair : input) {
   multimap.put(pair.fst, pair.snd);
 }

 List<String> result = multimap.get(“Kasia”);
FLUENT INTERFACE
com.google.common.base.Joiner
FLUENT INTERFACE
com.google.common.base.Joiner

 String s = Joiner.on(",").join(episodes);

 String s = Joiner.on(“|”).skipNulls().join(users);
FLUENT INTERFACE
com.google.common.base.Joiner

 String s = Joiner.on(",").join(episodes);

 String s = Joiner.on(“|”).skipNulls().join(users);

 StringBuffer sb = ...;
 Joiner.on(“|”)
    .useForNull("[user removed]")
    .appendTo(sb, users);
FLUENT INTERFACE
com.google.common.base.Joiner

 String s = Joiner.on(",").join(episodes);

 String s = Joiner.on(“|”).skipNulls().join(users);

 StringBuffer sb = ...;
 Joiner.on(“|”)
    .useForNull("[user removed]")
    .appendTo(sb, users);

 Joiner.on(“;”)
    .userForNull(“NODATA”)
    .withKeyValueSeparator(“:”)
    .join(ImmutableMap.of(“key”, “value”, ...));
ZABAWA Z
                                                 FUNKCYJNOŚCIĄ


http://www.flickr.com/photos/infrarad/182786930
WEJŚCIE: lista loginów w serwisie


WYJŚCIE: posortowana lista użytkowników,
         którzy mają więcej niż 18 lat
logins
  .map{ |login| User.select_by_login(login)}
  .find_all{ |user| user != nil && user.age > 18 }
  .sort_by{ |user| [user.surname, user.name] }
logins
  .map{ |login| User.select_by_login(login)}
  .find_all{ |user| user != nil && user.age > 18 }
  .sort_by{ |user| [user.surname, user.name] }
logins
  .map{ |login| User.select_by_login(login)}
  .find_all{ |user| user != nil && user.age > 18 }
  .sort_by{ |user| [user.surname, user.name] }
logins
  .map{ |login| User.select_by_login(login)}
  .find_all{ |user| user != nil && user.age > 18 }
  .sort_by{ |user| [user.surname, user.name] }
PIERWSZA PRÓBA
List<String> logins = ...;
List<User> users = new ArrayList();

for (String login : logins) {
  if (!Strings.isNullOrEmpty(login)) {
    User user = userDao.selectByLogin(login);
    if (user != null && user.getAge() >= 18) {
      users.add(user);
    }
  }
}

Collections.sort(users, new Comparator<User>() {
 @Override public int compare(User u1, User u2) {
  int result = u1.getSurname().compareTo(u2.getSurname());
  if (result != 0) {
    return result;
   }
   return u1.getName().compareTo(u2.getName());
 }});
PIERWSZA PRÓBA
List<String> logins = ...;
List<User> users = new ArrayList();

for (String login : logins) {
  if (!Strings.isNullOrEmpty(login)) {
    User user = userDao.selectByLogin(login);
    if (user != null && user.getAge() >= 18) {
      users.add(user);
    }
  }
}

Collections.sort(users, new Comparator<User>() {
 @Override public int compare(User u1, User u2) {
  int result = u1.getSurname().compareTo(u2.getSurname());
  if (result != 0) {
    return result;
   }
   return u1.getName().compareTo(u2.getName());
 }});
PIERWSZA PRÓBA
List<String> logins = ...;
List<User> users = new ArrayList();

for (String login : logins) {
  if (!Strings.isNullOrEmpty(login)) {
    User user = userDao.selectByLogin(login);
    if (user != null && user.getAge() >= 18) {
      users.add(user);
    }
  }
}

Collections.sort(users, new Comparator<User>() {
 @Override public int compare(User u1, User u2) {
  int result = u1.getSurname().compareTo(u2.getSurname());
  if (result != 0) {
    return result;
   }
   return u1.getName().compareTo(u2.getName());
 }});
PIERWSZA PRÓBA
List<String> logins = ...;
List<User> users = new ArrayList();

for (String login : logins) {
  if (!Strings.isNullOrEmpty(login)) {
    User user = userDao.selectByLogin(login);
    if (user != null && user.getAge() >= 18) {
      users.add(user);
    }
  }
}

Collections.sort(users, new Comparator<User>() {
 @Override public int compare(User u1, User u2) {
  int result = u1.getSurname().compareTo(u2.getSurname());
  if (result != 0) {
    return result;
   }
   return u1.getName().compareTo(u2.getName());
 }});
PIERWSZA PRÓBA
List<String> logins = ...;
List<User> users = new ArrayList();

for (String login : logins) {
  if (!Strings.isNullOrEmpty(login)) {
    User user = userDao.selectByLogin(login);
    if (user != null && user.getAge() >= 18) {
      users.add(user);
    }
  }
}

Collections.sort(users, new Comparator<User>() {
 @Override public int compare(User u1, User u2) {
  int result = u1.getSurname().compareTo(u2.getSurname());
  if (result != 0) {
    return result;
   }
   return u1.getName().compareTo(u2.getName());
 }});
PIERWSZA PRÓBA
List<String> logins = ...;
List<User> users = new ArrayList();

for (String login : logins) {
  if (!Strings.isNullOrEmpty(login)) {
    User user = userDao.selectByLogin(login);
    if (user != null && user.getAge() >= 18) {
      users.add(user);
    }
  }
}

Collections.sort(users, new Comparator<User>() {
 @Override public int compare(User u1, User u2) {
  int result = u1.getSurname().compareTo(u2.getSurname());
  if (result != 0) {
    return result;
   }
   return u1.getName().compareTo(u2.getName());
 }});
PIERWSZA PRÓBA
List<String> logins = ...;
List<User> users = new ArrayList();

for (String login : logins) {
  if (!Strings.isNullOrEmpty(login)) {
    User user = userDao.selectByLogin(login);
    if (user != null && user.getAge() >= 18) {
      users.add(user);
    }
  }
}

Collections.sort(users, new Comparator<User>() {
 @Override public int compare(User u1, User u2) {
  int result = u1.getSurname().compareTo(u2.getSurname());
  if (result != 0) {
    return result;
   }
   return u1.getName().compareTo(u2.getName());
 }});
PIERWSZA PRÓBA
List<String> logins = ...;
List<User> users = new ArrayList();

for (String login : logins) {
  if (!Strings.isNullOrEmpty(login)) {
    User user = userDao.selectByLogin(login);
    if (user != null && user.getAge() >= 18) {
      users.add(user);
    }
  }
}

Collections.sort(users, new Comparator<User>() {
 @Override public int compare(User u1, User u2) {
  int result = u1.getSurname().compareTo(u2.getSurname());
  if (result != 0) {
    return result;
   }
   return u1.getName().compareTo(u2.getName());
 }});
PIERWSZA PRÓBA
List<String> logins = ...;
List<User> users = new ArrayList();

for (String login : logins) {
  if (!Strings.isNullOrEmpty(login)) {
    User user = userDao.selectByLogin(login);
    if (user != null && user.getAge() >= 18) {
      users.add(user);
    }
  }
}

Collections.sort(users, new Comparator<User>() {
 @Override public int compare(User u1, User u2) {
  int result = u1.getSurname().compareTo(u2.getSurname());
  if (result != 0) {
    return result;
   }
   return u1.getName().compareTo(u2.getName());
 }});
FUNKCJE
com.google.common.base.Function




   public interface Function<F, T> {

       T apply(@Nullable F from);

   }
FUNKCJE
com.google.common.base.Function

static class FetchUsers implements Function<String, User> {

     private final UserDao userDao;

     public FetchUsers(UserDao userDao) {
       this.userDao = userDao;
     }

     @Override public User apply(String login) {
       if (Strings.isNullOrEmpty(login)) {
         return null;
       }
       return userDao.selectByLogin(login);
     }
 }
FUNKCJE
com.google.common.base.Function

static class FetchUsers implements Function<String, User> {

     private final UserDao userDao;

     public FetchUsers(UserDao userDao) {
       this.userDao = userDao;
     }

     @Override public User apply(String login) {
       if (Strings.isNullOrEmpty(login)) {
         return null;
       }
       return userDao.selectByLogin(login);
     }
 }
FUNKCJE
com.google.common.base.Function

static class FetchUsers implements Function<String, User> {

     private final UserDao userDao;

     public FetchUsers(UserDao userDao) {
       this.userDao = userDao;
     }

     @Override public User apply(String login) {
       if (Strings.isNullOrEmpty(login)) {
         return null;
       }
       return userDao.selectByLogin(login);
     }
 }
FUNKCJE
com.google.common.base.Function

static class FetchUsers implements Function<String, User> {

     private final UserDao userDao;

     public FetchUsers(UserDao userDao) {
       this.userDao = userDao;
     }

     @Override public User apply(String login) {
       if (Strings.isNullOrEmpty(login)) {
         return null;
       }
       return userDao.selectByLogin(login);
     }
 }
FUNKCJE
com.google.common.base.Function

static class FetchUsers implements Function<String, User> {

     private final UserDao userDao;

     public FetchUsers(UserDao userDao) {
       this.userDao = userDao;
     }

     @Override public User apply(String login) {
       if (Strings.isNullOrEmpty(login)) {
         return null;
       }
       return userDao.selectByLogin(login);
     }
 }
PREDYKATY
com.google.common.base.Predicate




  public interface Predicate<T> {

      boolean apply(@Nullable T input);

  }
PREDYKATY
com.google.common.base.Predicate



static final Predicate<User> OVER_18 =
   new Predicate<User>() {

   @Override public boolean apply(User user) {
     return user.getAge() >= 18;
   }

  };
PREDYKATY
com.google.common.base.Predicate



static final Predicate<User> OVER_18 =
   new Predicate<User>() {

   @Override public boolean apply(User user) {
     return user.getAge() >= 18;
   }

  };
PREDYKATY
com.google.common.base.Predicate



static final Predicate<User> OVER_18 =
   new Predicate<User>() {

   @Override public boolean apply(User user) {
     return user.getAge() >= 18;
   }

  };
PREDYKATY
com.google.common.base.Predicate



static final Predicate<User> OVER_18 =
   new Predicate<User>() {

   @Override public boolean apply(User user) {
     return user.getAge() >= 18;
   }

  };
ŁADNY KOMPARATOR
com.google.common.collect.ComparisonChain


static final Comparator<User> NAME_ASC =
 new Comparator<User>() {

  @Override public int compare(User u1, User u2) {
    return ComparisonChain.start()
       .compare(u1.getSurname(), u2.getSurname())
       .compare(u1.getName(), u2.getName())
       .result();
  }

 };
ŁADNY KOMPARATOR
com.google.common.collect.ComparisonChain


static final Comparator<User> NAME_ASC =
 new Comparator<User>() {

  @Override public int compare(User u1, User u2) {
    return ComparisonChain.start()
       .compare(u1.getSurname(), u2.getSurname())
       .compare(u1.getName(), u2.getName())
       .result();
  }

 };
ŁADNY KOMPARATOR
com.google.common.collect.ComparisonChain


static final Comparator<User> NAME_ASC =
 new Comparator<User>() {

  @Override public int compare(User u1, User u2) {
    return ComparisonChain.start()
       .compare(u1.getSurname(), u2.getSurname())
       .compare(u1.getName(), u2.getName())
       .result();
  }

 };
ŁADNY KOMPARATOR
com.google.common.collect.ComparisonChain


static final Comparator<User> NAME_ASC =
 new Comparator<User>() {

  @Override public int compare(User u1, User u2) {
    return ComparisonChain.start()
       .compare(u1.getSurname(), u2.getSurname())
       .compare(u1.getName(), u2.getName())
       .result();
  }

 };
ŁADNY KOMPARATOR
com.google.common.collect.ComparisonChain


static final Comparator<User> NAME_ASC =
 new Comparator<User>() {

  @Override public int compare(User u1, User u2) {
    return ComparisonChain.start()
       .compare(u1.getSurname(), u2.getSurname())
       .compare(u1.getName(), u2.getName())
       .result();
  }

 };
ŁADNY KOMPARATOR
com.google.common.collect.ComparisonChain


static final Comparator<User> NAME_ASC =
 new Comparator<User>() {

  @Override public int compare(User u1, User u2) {
    return ComparisonChain.start()
       .compare(u1.getSurname(), u2.getSurname())
       .compare(u1.getName(), u2.getName())
       .result();
  }

 };
DRUGA PRÓBA
com.google.common.collect.Iterables

import static com.google.common.collect.Iterables.*;

Iterable<User> users =
   transform(logins, new FetchUsers(userDao));

Iterable<User> notNullUsers =
   filter(users, Predicates.notNull());

Iterable<User> matureUsers =
   filter(notNullUsers, OVER_18);

List<User> result =
   com.google.common.collect.Ordering
     .from(NAME_ASC)
     .reverse()
     .immutableSortedCopy(matureUsers);
DRUGA PRÓBA
com.google.common.collect.Iterables

import static com.google.common.collect.Iterables.*;

Iterable<User> users =
   transform(logins, new FetchUsers(userDao));

Iterable<User> notNullUsers =
   filter(users, Predicates.notNull());

Iterable<User> matureUsers =
   filter(notNullUsers, OVER_18);

List<User> result =
   com.google.common.collect.Ordering
     .from(NAME_ASC)
     .reverse()
     .immutableSortedCopy(matureUsers);
DRUGA PRÓBA
com.google.common.collect.Iterables

import static com.google.common.collect.Iterables.*;

Iterable<User> users =
   transform(logins, new FetchUsers(userDao));

Iterable<User> notNullUsers =
   filter(users, Predicates.notNull());

Iterable<User> matureUsers =
   filter(notNullUsers, OVER_18);

List<User> result =
   com.google.common.collect.Ordering
     .from(NAME_ASC)
     .reverse()
     .immutableSortedCopy(matureUsers);
DRUGA PRÓBA
com.google.common.collect.Iterables

import static com.google.common.collect.Iterables.*;

Iterable<User> users =
   transform(logins, new FetchUsers(userDao));

Iterable<User> notNullUsers =
   filter(users, Predicates.notNull());

Iterable<User> matureUsers =
   filter(notNullUsers, OVER_18);

List<User> result =
   com.google.common.collect.Ordering
     .from(NAME_ASC)
     .reverse()
     .immutableSortedCopy(matureUsers);
DRUGA PRÓBA
com.google.common.collect.Iterables

import static com.google.common.collect.Iterables.*;

Iterable<User> users =
   transform(logins, new FetchUsers(userDao));

Iterable<User> notNullUsers =
   filter(users, Predicates.notNull());

Iterable<User> matureUsers =
   filter(notNullUsers, OVER_18);

List<User> result =
   com.google.common.collect.Ordering
     .from(NAME_ASC)
     .reverse()
     .immutableSortedCopy(matureUsers);
DRUGA PRÓBA
com.google.common.collect.Iterables

import static com.google.common.collect.Iterables.*;

Iterable<User> users =
   transform(logins, new FetchUsers(userDao));

Iterable<User> notNullUsers =
   filter(users, Predicates.notNull());

Iterable<User> matureUsers =
   filter(notNullUsers, OVER_18);

List<User> result =
   com.google.common.collect.Ordering
     .from(NAME_ASC)
     .reverse()
     .immutableSortedCopy(matureUsers);
DRUGA PRÓBA
com.google.common.collect.Iterables

import static com.google.common.collect.Iterables.*;

Iterable<User> users =
   transform(logins, new FetchUsers(userDao));

Iterable<User> notNullUsers =
   filter(users, Predicates.notNull());

Iterable<User> matureUsers =
   filter(notNullUsers, OVER_18);

List<User> result =
   com.google.common.collect.Ordering
     .from(NAME_ASC)
     .reverse()
     .immutableSortedCopy(matureUsers);
DRUGA PRÓBA
com.google.common.collect.Iterables

import static com.google.common.collect.Iterables.*;

Iterable<User> users =
   transform(logins, new FetchUsers(userDao));

Iterable<User> notNullUsers =
   filter(users, Predicates.notNull());

Iterable<User> matureUsers =
   filter(notNullUsers, OVER_18);

List<User> result =
   com.google.common.collect.Ordering
     .from(NAME_ASC)
     .reverse()
     .immutableSortedCopy(matureUsers);
DRUGA PRÓBA
com.google.common.collect.Iterables

import static com.google.common.collect.Iterables.*;

Iterable<User> users =
   transform(logins, new FetchUsers(userDao));

Iterable<User> notNullUsers =
   filter(users, Predicates.notNull());

Iterable<User> matureUsers =
   filter(notNullUsers, OVER_18);

List<User> result =
   com.google.common.collect.Ordering
     .from(NAME_ASC)
     .reverse()
     .immutableSortedCopy(matureUsers);
TRZECIA PRÓBA


ImmutableList<User> result = FluentIterable
  .with(logins)
  .transform(new FetchUsers(userDao))
  .filter(Predicates.notNull())
  .filter(OVER_18)
  .sort(NAME_DESC)
  .immutableCopy();
TRZECIA PRÓBA


ImmutableList<User> result = FluentIterable
  .with(logins)
  .transform(new FetchUsers(userDao))
  .filter(Predicates.notNull())
  .filter(OVER_18)
  .sort(NAME_DESC)
  .immutableCopy();
TRZECIA PRÓBA


ImmutableList<User> result = FluentIterable
  .with(logins)
  .transform(new FetchUsers(userDao))
  .filter(Predicates.notNull())
  .filter(OVER_18)
  .sort(NAME_DESC)
  .immutableCopy();
TRZECIA PRÓBA


ImmutableList<User> result = FluentIterable
  .with(logins)
  .transform(new FetchUsers(userDao))
  .filter(Predicates.notNull())
  .filter(OVER_18)
  .sort(NAME_DESC)
  .immutableCopy();
TRZECIA PRÓBA


ImmutableList<User> result = FluentIterable
  .with(logins)
  .transform(new FetchUsers(userDao))
  .filter(Predicates.notNull())
  .filter(OVER_18)
  .sort(NAME_DESC)
  .immutableCopy();
TRZECIA PRÓBA


ImmutableList<User> result = FluentIterable
  .with(logins)
  .transform(new FetchUsers(userDao))
  .filter(Predicates.notNull())
  .filter(OVER_18)
  .sort(NAME_DESC)
  .immutableCopy();
TRZECIA PRÓBA


ImmutableList<User> result = FluentIterable
  .with(logins)
  .transform(new FetchUsers(userDao))
  .filter(Predicates.notNull())
  .filter(OVER_18)
  .sort(NAME_DESC)
  .immutableCopy();
Czytelność   Funkcyjność
Pytania?



Wiktor Gworek   •   Javarsovia 2010   •   Google

Weitere ähnliche Inhalte

Was ist angesagt?

Doctype htm1
Doctype htm1Doctype htm1
Doctype htm1Eddy_TKJ
 
Native json in the Cache' ObjectScript 2016.*
Native json in the Cache' ObjectScript 2016.*Native json in the Cache' ObjectScript 2016.*
Native json in the Cache' ObjectScript 2016.*Timur Safin
 
A evolução da persistência de dados (com sqlite) no android
A evolução da persistência de dados (com sqlite) no androidA evolução da persistência de dados (com sqlite) no android
A evolução da persistência de dados (com sqlite) no androidRodrigo de Souza Castro
 
The Ring programming language version 1.3 book - Part 34 of 88
The Ring programming language version 1.3 book - Part 34 of 88The Ring programming language version 1.3 book - Part 34 of 88
The Ring programming language version 1.3 book - Part 34 of 88Mahmoud Samir Fayed
 
The Ring programming language version 1.10 book - Part 56 of 212
The Ring programming language version 1.10 book - Part 56 of 212The Ring programming language version 1.10 book - Part 56 of 212
The Ring programming language version 1.10 book - Part 56 of 212Mahmoud Samir Fayed
 
WordPressでIoTをはじめよう
WordPressでIoTをはじめようWordPressでIoTをはじめよう
WordPressでIoTをはじめようYuriko IKEDA
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeMongoDB
 
Super Advanced Python –act1
Super Advanced Python –act1Super Advanced Python –act1
Super Advanced Python –act1Ke Wei Louis
 
Mozilla とブラウザゲーム
Mozilla とブラウザゲームMozilla とブラウザゲーム
Mozilla とブラウザゲームNoritada Shimizu
 
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"South Tyrol Free Software Conference
 
JSDC 2014 - functional java script, why or why not
JSDC 2014 - functional java script, why or why notJSDC 2014 - functional java script, why or why not
JSDC 2014 - functional java script, why or why notChengHui Weng
 
Groovy collection api
Groovy collection apiGroovy collection api
Groovy collection apitrygvea
 
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseEclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseHeiko Behrens
 
beyond tellerrand: Mobile Apps with JavaScript – There's More Than Web
beyond tellerrand: Mobile Apps with JavaScript – There's More Than Webbeyond tellerrand: Mobile Apps with JavaScript – There's More Than Web
beyond tellerrand: Mobile Apps with JavaScript – There's More Than WebHeiko Behrens
 
JSON and Swift, Still A Better Love Story Than Twilight
JSON and Swift, Still A Better Love Story Than TwilightJSON and Swift, Still A Better Love Story Than Twilight
JSON and Swift, Still A Better Love Story Than TwilightDonny Wals
 
Store and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraStore and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraDeependra Ariyadewa
 

Was ist angesagt? (20)

Doctype htm1
Doctype htm1Doctype htm1
Doctype htm1
 
Native json in the Cache' ObjectScript 2016.*
Native json in the Cache' ObjectScript 2016.*Native json in the Cache' ObjectScript 2016.*
Native json in the Cache' ObjectScript 2016.*
 
A evolução da persistência de dados (com sqlite) no android
A evolução da persistência de dados (com sqlite) no androidA evolução da persistência de dados (com sqlite) no android
A evolução da persistência de dados (com sqlite) no android
 
The Ring programming language version 1.3 book - Part 34 of 88
The Ring programming language version 1.3 book - Part 34 of 88The Ring programming language version 1.3 book - Part 34 of 88
The Ring programming language version 1.3 book - Part 34 of 88
 
The Ring programming language version 1.10 book - Part 56 of 212
The Ring programming language version 1.10 book - Part 56 of 212The Ring programming language version 1.10 book - Part 56 of 212
The Ring programming language version 1.10 book - Part 56 of 212
 
WordPressでIoTをはじめよう
WordPressでIoTをはじめようWordPressでIoTをはじめよう
WordPressでIoTをはじめよう
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at Stripe
 
Super Advanced Python –act1
Super Advanced Python –act1Super Advanced Python –act1
Super Advanced Python –act1
 
Ricky Bobby's World
Ricky Bobby's WorldRicky Bobby's World
Ricky Bobby's World
 
MongoDB
MongoDBMongoDB
MongoDB
 
Mozilla とブラウザゲーム
Mozilla とブラウザゲームMozilla とブラウザゲーム
Mozilla とブラウザゲーム
 
H base programming
H base programmingH base programming
H base programming
 
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"
SFScon17 - Patrick Puecher: "Exploring data with Elasticsearch and Kibana"
 
JSDC 2014 - functional java script, why or why not
JSDC 2014 - functional java script, why or why notJSDC 2014 - functional java script, why or why not
JSDC 2014 - functional java script, why or why not
 
Groovy collection api
Groovy collection apiGroovy collection api
Groovy collection api
 
Mobile Web 5.0
Mobile Web 5.0Mobile Web 5.0
Mobile Web 5.0
 
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with EclipseEclipseCon2011 Cross-Platform Mobile Development with Eclipse
EclipseCon2011 Cross-Platform Mobile Development with Eclipse
 
beyond tellerrand: Mobile Apps with JavaScript – There's More Than Web
beyond tellerrand: Mobile Apps with JavaScript – There's More Than Webbeyond tellerrand: Mobile Apps with JavaScript – There's More Than Web
beyond tellerrand: Mobile Apps with JavaScript – There's More Than Web
 
JSON and Swift, Still A Better Love Story Than Twilight
JSON and Swift, Still A Better Love Story Than TwilightJSON and Swift, Still A Better Love Story Than Twilight
JSON and Swift, Still A Better Love Story Than Twilight
 
Store and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraStore and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and Cassandra
 

Andere mochten auch

Code Review, czyli przegląd kodu - prezentacja tematu pracy magisterskiej
Code Review, czyli przegląd kodu -  prezentacja tematu pracy magisterskiejCode Review, czyli przegląd kodu -  prezentacja tematu pracy magisterskiej
Code Review, czyli przegląd kodu - prezentacja tematu pracy magisterskiejWiktor Gworek
 
Integracja JSF + Facelets + Spring + JPA + Tomahawk
Integracja JSF + Facelets + Spring + JPA + TomahawkIntegracja JSF + Facelets + Spring + JPA + Tomahawk
Integracja JSF + Facelets + Spring + JPA + TomahawkWiktor Gworek
 
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarkaThymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarkaMaciej Ziarko
 

Andere mochten auch (6)

Słownik dla Maka
Słownik dla MakaSłownik dla Maka
Słownik dla Maka
 
Code Review, czyli przegląd kodu - prezentacja tematu pracy magisterskiej
Code Review, czyli przegląd kodu -  prezentacja tematu pracy magisterskiejCode Review, czyli przegląd kodu -  prezentacja tematu pracy magisterskiej
Code Review, czyli przegląd kodu - prezentacja tematu pracy magisterskiej
 
Integracja JSF + Facelets + Spring + JPA + Tomahawk
Integracja JSF + Facelets + Spring + JPA + TomahawkIntegracja JSF + Facelets + Spring + JPA + Tomahawk
Integracja JSF + Facelets + Spring + JPA + Tomahawk
 
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarkaThymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
Thymeleaf - szablony, które bez przetworzenia zrozumie twoja przeglądarka
 
JRuby On Rails
JRuby On Rails JRuby On Rails
JRuby On Rails
 
Java™ in Web 2.0
Java™ in Web 2.0Java™ in Web 2.0
Java™ in Web 2.0
 

Ähnlich wie Lekcja stylu

Java Unicode with Cool GUI Examples
Java Unicode with Cool GUI ExamplesJava Unicode with Cool GUI Examples
Java Unicode with Cool GUI ExamplesOXUS 20
 
Java Unicode with Live GUI Examples
Java Unicode with Live GUI ExamplesJava Unicode with Live GUI Examples
Java Unicode with Live GUI ExamplesAbdul Rahman Sherzad
 
Roman iovlev. Test UI with JDI - Selenium camp
Roman iovlev. Test UI with JDI - Selenium campRoman iovlev. Test UI with JDI - Selenium camp
Roman iovlev. Test UI with JDI - Selenium campРоман Иовлев
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs偉格 高
 
Intro To PostGIS
Intro To PostGISIntro To PostGIS
Intro To PostGISmleslie
 
2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locatorAlberto Paro
 
2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locatorAlberto Paro
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript IntroductionDmitry Sheiko
 
Юрий Буянов «Squeryl — ORM с человеческим лицом»
Юрий Буянов «Squeryl — ORM с человеческим лицом»Юрий Буянов «Squeryl — ORM с человеческим лицом»
Юрий Буянов «Squeryl — ORM с человеческим лицом»e-Legion
 
Cascading Through Hadoop for the Boulder JUG
Cascading Through Hadoop for the Boulder JUGCascading Through Hadoop for the Boulder JUG
Cascading Through Hadoop for the Boulder JUGMatthew McCullough
 
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"epamspb
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with ClojureDmitry Buzdin
 
Write a program that reads a graph from a file and determines whether.docx
 Write a program that reads a graph from a file and determines whether.docx Write a program that reads a graph from a file and determines whether.docx
Write a program that reads a graph from a file and determines whether.docxajoy21
 
in this assignment you are asked to write a simple driver program an.pdf
in this assignment you are asked to write a simple driver program an.pdfin this assignment you are asked to write a simple driver program an.pdf
in this assignment you are asked to write a simple driver program an.pdfmichardsonkhaicarr37
 
Wprowadzenie do technologi Big Data i Apache Hadoop
Wprowadzenie do technologi Big Data i Apache HadoopWprowadzenie do technologi Big Data i Apache Hadoop
Wprowadzenie do technologi Big Data i Apache HadoopSages
 
Sapo GIS Hands-On
Sapo GIS Hands-OnSapo GIS Hands-On
Sapo GIS Hands-Oncodebits
 
Gis SAPO Hands On
Gis SAPO Hands OnGis SAPO Hands On
Gis SAPO Hands Oncodebits
 
How Quick Can We Be? Data Visualization Techniques for Engineers.
How Quick Can We Be? Data Visualization Techniques for Engineers. How Quick Can We Be? Data Visualization Techniques for Engineers.
How Quick Can We Be? Data Visualization Techniques for Engineers. Avni Khatri
 
code for quiz in my sql
code for quiz  in my sql code for quiz  in my sql
code for quiz in my sql JOYITAKUNDU1
 
Introduction To PostGIS
Introduction To PostGISIntroduction To PostGIS
Introduction To PostGISmleslie
 

Ähnlich wie Lekcja stylu (20)

Java Unicode with Cool GUI Examples
Java Unicode with Cool GUI ExamplesJava Unicode with Cool GUI Examples
Java Unicode with Cool GUI Examples
 
Java Unicode with Live GUI Examples
Java Unicode with Live GUI ExamplesJava Unicode with Live GUI Examples
Java Unicode with Live GUI Examples
 
Roman iovlev. Test UI with JDI - Selenium camp
Roman iovlev. Test UI with JDI - Selenium campRoman iovlev. Test UI with JDI - Selenium camp
Roman iovlev. Test UI with JDI - Selenium camp
 
Functional programming using underscorejs
Functional programming using underscorejsFunctional programming using underscorejs
Functional programming using underscorejs
 
Intro To PostGIS
Intro To PostGISIntro To PostGIS
Intro To PostGIS
 
2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator
 
2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator2017 02-07 - elastic & spark. building a search geo locator
2017 02-07 - elastic & spark. building a search geo locator
 
TypeScript Introduction
TypeScript IntroductionTypeScript Introduction
TypeScript Introduction
 
Юрий Буянов «Squeryl — ORM с человеческим лицом»
Юрий Буянов «Squeryl — ORM с человеческим лицом»Юрий Буянов «Squeryl — ORM с человеческим лицом»
Юрий Буянов «Squeryl — ORM с человеческим лицом»
 
Cascading Through Hadoop for the Boulder JUG
Cascading Through Hadoop for the Boulder JUGCascading Through Hadoop for the Boulder JUG
Cascading Through Hadoop for the Boulder JUG
 
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
#ITsubbotnik Spring 2017: Roman Iovlev "Java edge in test automation"
 
Refactoring to Macros with Clojure
Refactoring to Macros with ClojureRefactoring to Macros with Clojure
Refactoring to Macros with Clojure
 
Write a program that reads a graph from a file and determines whether.docx
 Write a program that reads a graph from a file and determines whether.docx Write a program that reads a graph from a file and determines whether.docx
Write a program that reads a graph from a file and determines whether.docx
 
in this assignment you are asked to write a simple driver program an.pdf
in this assignment you are asked to write a simple driver program an.pdfin this assignment you are asked to write a simple driver program an.pdf
in this assignment you are asked to write a simple driver program an.pdf
 
Wprowadzenie do technologi Big Data i Apache Hadoop
Wprowadzenie do technologi Big Data i Apache HadoopWprowadzenie do technologi Big Data i Apache Hadoop
Wprowadzenie do technologi Big Data i Apache Hadoop
 
Sapo GIS Hands-On
Sapo GIS Hands-OnSapo GIS Hands-On
Sapo GIS Hands-On
 
Gis SAPO Hands On
Gis SAPO Hands OnGis SAPO Hands On
Gis SAPO Hands On
 
How Quick Can We Be? Data Visualization Techniques for Engineers.
How Quick Can We Be? Data Visualization Techniques for Engineers. How Quick Can We Be? Data Visualization Techniques for Engineers.
How Quick Can We Be? Data Visualization Techniques for Engineers.
 
code for quiz in my sql
code for quiz  in my sql code for quiz  in my sql
code for quiz in my sql
 
Introduction To PostGIS
Introduction To PostGISIntroduction To PostGIS
Introduction To PostGIS
 

Lekcja stylu

  • 1. LEKCJA STYLU czy w Javie można jeszcze dostrzec piękno? Wiktor Gworek • Javarsovia 2010 • Google
  • 2. @wwiktorr ^wwiktorr wiktorgworek.com blog.mocna-kawa.com
  • 3.
  • 4.
  • 6. czytelność boilerplate łatwe testowanie PIĘKNO KODU definicja dla Javy statyczne narzędzia typowanie
  • 7. NARZĘDZIA • Google Guava • http://code.google.com/p/guava-libraries/ • Google Guice • http://code.google.com/p/google-guice/ • Mockito • http://code.google.com/p/mockito/
  • 8. Czytelność Funkcyjność
  • 9. POPRAWIANIE CZYTELNOŚCI http://www.flickr.com/photos/jleveque/2151484964
  • 10. “Jejku, ten kod wygląda, jakby go pisał sam Steven King. Horror, aż strach przejść na kolejną stronę.” – anonimowy programista
  • 11. if (GOOGLE) { CODE.STYLE(); }
  • 12. 100 znaków if (GOOGLE) { CODE.STYLE(); }
  • 13. 100 znaków if (GOOGLE) { t CODE.STYLE(); }
  • 14. 100 znaków if (GOOGLE) { t CODE.STYLE(); } 2 znaki
  • 15. 100 znaków if (GOOGLE) { t CODE.STYLE(); } 2 znaki
  • 16. KODOWANIE DEFENSYWNE http://www.flickr.com/photos/mosca27/166707333/
  • 17. KODOWANIE DEFENSYWNE public void analyze(String msg) { if (msg == null) { throw NullPointerException(); } if (msg.length() > 160) { throw IllegalArgumentException( “Tak długa wiadomość?”); } // analiza wiadomości }
  • 18. KODOWANIE DEFENSYWNE public void analyze(String msg) { Preconditions.checkNotNull(msg); Preconditions.checkArgument( msg.length() <= 160, “Tak długa wiadomość?”); // analiza wiadomości }
  • 20. KOLEKCJE com.google.common.collect Map<String, List<User, Role>> map = new HashMap<String, List<User, Role>>;
  • 21. KOLEKCJE com.google.common.collect Map<String, List<User, Role>> map = new HashMap<String, List<User, Role>>; Map<String, List<User, Role>> m = Maps.newHashMap(); List<Long> l = Lists.newArrayListWithExpectedSize(3); Set<Pair<String, User>> set = Sets.newHashSet(); Set<String> set = Sets.newHashSet(“a”, “b”, “c”);
  • 23. NIEMODYFIKOWANE OBIEKTY public void setName(String newName); private final Address address;
  • 24. NIEMODYFIKOWANE OBIEKTY public void setName(String newName); private final Address address; // Wykorzystanie Protocol Buffers Post newPost = post.toBuilder() .setTitle(newTitle) .build();
  • 25. KOLEKCJE com.google.common.collect List<String> list = new ArrayList<String>(); list.add(“a”); list.add(“b”); list.add(“c”); public static final Set<Integer> LUCKY_NUMBERS; static { Set<Integer> set = new LinkedHashSet<Integer>; set.add(4); set.add(7); set.add(42); LUCKY_NUMBERS = Collections.unmodifiableSet(set); }
  • 26. KOLEKCJE com.google.common.collect public static final Set<Integer> LUCKY_NUMBERS = Collections.unmodifiableSet( new LinkedHashSet<Integer>( Arrays.asList(4, 7, 42)));
  • 28. KOLEKCJE com.google.common.collect List<String> list = ImmutableList.of(“a”, “b”, “c”);
  • 29. KOLEKCJE com.google.common.collect List<String> list = ImmutableList.of(“a”, “b”, “c”); static final Set<Integer> LUCKY_NUMBERS = ImmutableSet.of(4, 7, 42);
  • 30. KOLEKCJE com.google.common.collect List<String> list = ImmutableList.of(“a”, “b”, “c”); static final Set<Integer> LUCKY_NUMBERS = ImmutableSet.of(4, 7, 42); static final Map<String, String> FORBIDDEN = ImmutableMap.of(“key1”, “val1”, “key2”, “val2”);
  • 31. ZNOWU TO SAMO... http://www.flickr.com/photos/nifmus/2385966735/
  • 32. KOLEKCJE com.google.common.collect Map<String, List<String>> map = Maps.newHashMap(); for (Pair<String, String> pair : input) { if (map.containsKey(pair.fst)) { map.get(pair.fst).add(pair.snd); } else { map.put(pair.fst, Lists.newArrayList(pair.snd)); } } List<String> result = map.get(“Kasia”);
  • 33. KOLEKCJE com.google.common.collect Map<String, List<String>> map = Maps.newHashMap(); for (Pair<String, String> pair : input) { if (map.containsKey(pair.fst)) { map.get(pair.fst).add(pair.snd); } else { map.put(pair.fst, Lists.newArrayList(pair.snd)); } } List<String> result = map.get(“Kasia”);
  • 34. KOLEKCJE com.google.common.collect Map<String, List<String>> map = Maps.newHashMap(); for (Pair<String, String> pair : input) { if (map.containsKey(pair.fst)) { map.get(pair.fst).add(pair.snd); } else { map.put(pair.fst, Lists.newArrayList(pair.snd)); } } List<String> result = map.get(“Kasia”);
  • 35. KOLEKCJE com.google.common.collect Map<String, List<String>> map = Maps.newHashMap(); for (Pair<String, String> pair : input) { if (map.containsKey(pair.fst)) { map.get(pair.fst).add(pair.snd); } else { map.put(pair.fst, Lists.newArrayList(pair.snd)); } } List<String> result = map.get(“Kasia”);
  • 36. KOLEKCJE com.google.common.collect Map<String, List<String>> map = Maps.newHashMap(); for (Pair<String, String> pair : input) { if (map.containsKey(pair.fst)) { map.get(pair.fst).add(pair.snd); } else { map.put(pair.fst, Lists.newArrayList(pair.snd)); } } List<String> result = map.get(“Kasia”);
  • 37. KOLEKCJE com.google.common.collect Map<String, List<String>> map = Maps.newHashMap(); for (Pair<String, String> pair : input) { if (map.containsKey(pair.fst)) { map.get(pair.fst).add(pair.snd); } else { map.put(pair.fst, Lists.newArrayList(pair.snd)); } } List<String> result = map.get(“Kasia”);
  • 38. KOLEKCJE com.google.common.collect Multimap<String, String> multimap = ArrayListMultimap.create(); for (Pair<String, String> pair : input) { multimap.put(pair.fst, pair.snd); } List<String> result = multimap.get(“Kasia”);
  • 39. KOLEKCJE com.google.common.collect Multimap<String, String> multimap = ArrayListMultimap.create(); for (Pair<String, String> pair : input) { multimap.put(pair.fst, pair.snd); } List<String> result = multimap.get(“Kasia”);
  • 40. KOLEKCJE com.google.common.collect Multimap<String, String> multimap = ArrayListMultimap.create(); for (Pair<String, String> pair : input) { multimap.put(pair.fst, pair.snd); } List<String> result = multimap.get(“Kasia”);
  • 41. KOLEKCJE com.google.common.collect Multimap<String, String> multimap = ArrayListMultimap.create(); for (Pair<String, String> pair : input) { multimap.put(pair.fst, pair.snd); } List<String> result = multimap.get(“Kasia”);
  • 42. KOLEKCJE com.google.common.collect Multimap<String, String> multimap = ArrayListMultimap.create(); for (Pair<String, String> pair : input) { multimap.put(pair.fst, pair.snd); } List<String> result = multimap.get(“Kasia”);
  • 44. FLUENT INTERFACE com.google.common.base.Joiner String s = Joiner.on(",").join(episodes); String s = Joiner.on(“|”).skipNulls().join(users);
  • 45. FLUENT INTERFACE com.google.common.base.Joiner String s = Joiner.on(",").join(episodes); String s = Joiner.on(“|”).skipNulls().join(users); StringBuffer sb = ...; Joiner.on(“|”) .useForNull("[user removed]") .appendTo(sb, users);
  • 46. FLUENT INTERFACE com.google.common.base.Joiner String s = Joiner.on(",").join(episodes); String s = Joiner.on(“|”).skipNulls().join(users); StringBuffer sb = ...; Joiner.on(“|”) .useForNull("[user removed]") .appendTo(sb, users); Joiner.on(“;”) .userForNull(“NODATA”) .withKeyValueSeparator(“:”) .join(ImmutableMap.of(“key”, “value”, ...));
  • 47. ZABAWA Z FUNKCYJNOŚCIĄ http://www.flickr.com/photos/infrarad/182786930
  • 48. WEJŚCIE: lista loginów w serwisie WYJŚCIE: posortowana lista użytkowników, którzy mają więcej niż 18 lat
  • 49. logins .map{ |login| User.select_by_login(login)} .find_all{ |user| user != nil && user.age > 18 } .sort_by{ |user| [user.surname, user.name] }
  • 50. logins .map{ |login| User.select_by_login(login)} .find_all{ |user| user != nil && user.age > 18 } .sort_by{ |user| [user.surname, user.name] }
  • 51. logins .map{ |login| User.select_by_login(login)} .find_all{ |user| user != nil && user.age > 18 } .sort_by{ |user| [user.surname, user.name] }
  • 52. logins .map{ |login| User.select_by_login(login)} .find_all{ |user| user != nil && user.age > 18 } .sort_by{ |user| [user.surname, user.name] }
  • 53. PIERWSZA PRÓBA List<String> logins = ...; List<User> users = new ArrayList(); for (String login : logins) { if (!Strings.isNullOrEmpty(login)) { User user = userDao.selectByLogin(login); if (user != null && user.getAge() >= 18) { users.add(user); } } } Collections.sort(users, new Comparator<User>() { @Override public int compare(User u1, User u2) { int result = u1.getSurname().compareTo(u2.getSurname()); if (result != 0) { return result; } return u1.getName().compareTo(u2.getName()); }});
  • 54. PIERWSZA PRÓBA List<String> logins = ...; List<User> users = new ArrayList(); for (String login : logins) { if (!Strings.isNullOrEmpty(login)) { User user = userDao.selectByLogin(login); if (user != null && user.getAge() >= 18) { users.add(user); } } } Collections.sort(users, new Comparator<User>() { @Override public int compare(User u1, User u2) { int result = u1.getSurname().compareTo(u2.getSurname()); if (result != 0) { return result; } return u1.getName().compareTo(u2.getName()); }});
  • 55. PIERWSZA PRÓBA List<String> logins = ...; List<User> users = new ArrayList(); for (String login : logins) { if (!Strings.isNullOrEmpty(login)) { User user = userDao.selectByLogin(login); if (user != null && user.getAge() >= 18) { users.add(user); } } } Collections.sort(users, new Comparator<User>() { @Override public int compare(User u1, User u2) { int result = u1.getSurname().compareTo(u2.getSurname()); if (result != 0) { return result; } return u1.getName().compareTo(u2.getName()); }});
  • 56. PIERWSZA PRÓBA List<String> logins = ...; List<User> users = new ArrayList(); for (String login : logins) { if (!Strings.isNullOrEmpty(login)) { User user = userDao.selectByLogin(login); if (user != null && user.getAge() >= 18) { users.add(user); } } } Collections.sort(users, new Comparator<User>() { @Override public int compare(User u1, User u2) { int result = u1.getSurname().compareTo(u2.getSurname()); if (result != 0) { return result; } return u1.getName().compareTo(u2.getName()); }});
  • 57. PIERWSZA PRÓBA List<String> logins = ...; List<User> users = new ArrayList(); for (String login : logins) { if (!Strings.isNullOrEmpty(login)) { User user = userDao.selectByLogin(login); if (user != null && user.getAge() >= 18) { users.add(user); } } } Collections.sort(users, new Comparator<User>() { @Override public int compare(User u1, User u2) { int result = u1.getSurname().compareTo(u2.getSurname()); if (result != 0) { return result; } return u1.getName().compareTo(u2.getName()); }});
  • 58. PIERWSZA PRÓBA List<String> logins = ...; List<User> users = new ArrayList(); for (String login : logins) { if (!Strings.isNullOrEmpty(login)) { User user = userDao.selectByLogin(login); if (user != null && user.getAge() >= 18) { users.add(user); } } } Collections.sort(users, new Comparator<User>() { @Override public int compare(User u1, User u2) { int result = u1.getSurname().compareTo(u2.getSurname()); if (result != 0) { return result; } return u1.getName().compareTo(u2.getName()); }});
  • 59. PIERWSZA PRÓBA List<String> logins = ...; List<User> users = new ArrayList(); for (String login : logins) { if (!Strings.isNullOrEmpty(login)) { User user = userDao.selectByLogin(login); if (user != null && user.getAge() >= 18) { users.add(user); } } } Collections.sort(users, new Comparator<User>() { @Override public int compare(User u1, User u2) { int result = u1.getSurname().compareTo(u2.getSurname()); if (result != 0) { return result; } return u1.getName().compareTo(u2.getName()); }});
  • 60. PIERWSZA PRÓBA List<String> logins = ...; List<User> users = new ArrayList(); for (String login : logins) { if (!Strings.isNullOrEmpty(login)) { User user = userDao.selectByLogin(login); if (user != null && user.getAge() >= 18) { users.add(user); } } } Collections.sort(users, new Comparator<User>() { @Override public int compare(User u1, User u2) { int result = u1.getSurname().compareTo(u2.getSurname()); if (result != 0) { return result; } return u1.getName().compareTo(u2.getName()); }});
  • 61. PIERWSZA PRÓBA List<String> logins = ...; List<User> users = new ArrayList(); for (String login : logins) { if (!Strings.isNullOrEmpty(login)) { User user = userDao.selectByLogin(login); if (user != null && user.getAge() >= 18) { users.add(user); } } } Collections.sort(users, new Comparator<User>() { @Override public int compare(User u1, User u2) { int result = u1.getSurname().compareTo(u2.getSurname()); if (result != 0) { return result; } return u1.getName().compareTo(u2.getName()); }});
  • 62. FUNKCJE com.google.common.base.Function public interface Function<F, T> { T apply(@Nullable F from); }
  • 63. FUNKCJE com.google.common.base.Function static class FetchUsers implements Function<String, User> { private final UserDao userDao; public FetchUsers(UserDao userDao) { this.userDao = userDao; } @Override public User apply(String login) { if (Strings.isNullOrEmpty(login)) { return null; } return userDao.selectByLogin(login); } }
  • 64. FUNKCJE com.google.common.base.Function static class FetchUsers implements Function<String, User> { private final UserDao userDao; public FetchUsers(UserDao userDao) { this.userDao = userDao; } @Override public User apply(String login) { if (Strings.isNullOrEmpty(login)) { return null; } return userDao.selectByLogin(login); } }
  • 65. FUNKCJE com.google.common.base.Function static class FetchUsers implements Function<String, User> { private final UserDao userDao; public FetchUsers(UserDao userDao) { this.userDao = userDao; } @Override public User apply(String login) { if (Strings.isNullOrEmpty(login)) { return null; } return userDao.selectByLogin(login); } }
  • 66. FUNKCJE com.google.common.base.Function static class FetchUsers implements Function<String, User> { private final UserDao userDao; public FetchUsers(UserDao userDao) { this.userDao = userDao; } @Override public User apply(String login) { if (Strings.isNullOrEmpty(login)) { return null; } return userDao.selectByLogin(login); } }
  • 67. FUNKCJE com.google.common.base.Function static class FetchUsers implements Function<String, User> { private final UserDao userDao; public FetchUsers(UserDao userDao) { this.userDao = userDao; } @Override public User apply(String login) { if (Strings.isNullOrEmpty(login)) { return null; } return userDao.selectByLogin(login); } }
  • 68. PREDYKATY com.google.common.base.Predicate public interface Predicate<T> { boolean apply(@Nullable T input); }
  • 69. PREDYKATY com.google.common.base.Predicate static final Predicate<User> OVER_18 = new Predicate<User>() { @Override public boolean apply(User user) { return user.getAge() >= 18; } };
  • 70. PREDYKATY com.google.common.base.Predicate static final Predicate<User> OVER_18 = new Predicate<User>() { @Override public boolean apply(User user) { return user.getAge() >= 18; } };
  • 71. PREDYKATY com.google.common.base.Predicate static final Predicate<User> OVER_18 = new Predicate<User>() { @Override public boolean apply(User user) { return user.getAge() >= 18; } };
  • 72. PREDYKATY com.google.common.base.Predicate static final Predicate<User> OVER_18 = new Predicate<User>() { @Override public boolean apply(User user) { return user.getAge() >= 18; } };
  • 73. ŁADNY KOMPARATOR com.google.common.collect.ComparisonChain static final Comparator<User> NAME_ASC = new Comparator<User>() { @Override public int compare(User u1, User u2) { return ComparisonChain.start() .compare(u1.getSurname(), u2.getSurname()) .compare(u1.getName(), u2.getName()) .result(); } };
  • 74. ŁADNY KOMPARATOR com.google.common.collect.ComparisonChain static final Comparator<User> NAME_ASC = new Comparator<User>() { @Override public int compare(User u1, User u2) { return ComparisonChain.start() .compare(u1.getSurname(), u2.getSurname()) .compare(u1.getName(), u2.getName()) .result(); } };
  • 75. ŁADNY KOMPARATOR com.google.common.collect.ComparisonChain static final Comparator<User> NAME_ASC = new Comparator<User>() { @Override public int compare(User u1, User u2) { return ComparisonChain.start() .compare(u1.getSurname(), u2.getSurname()) .compare(u1.getName(), u2.getName()) .result(); } };
  • 76. ŁADNY KOMPARATOR com.google.common.collect.ComparisonChain static final Comparator<User> NAME_ASC = new Comparator<User>() { @Override public int compare(User u1, User u2) { return ComparisonChain.start() .compare(u1.getSurname(), u2.getSurname()) .compare(u1.getName(), u2.getName()) .result(); } };
  • 77. ŁADNY KOMPARATOR com.google.common.collect.ComparisonChain static final Comparator<User> NAME_ASC = new Comparator<User>() { @Override public int compare(User u1, User u2) { return ComparisonChain.start() .compare(u1.getSurname(), u2.getSurname()) .compare(u1.getName(), u2.getName()) .result(); } };
  • 78. ŁADNY KOMPARATOR com.google.common.collect.ComparisonChain static final Comparator<User> NAME_ASC = new Comparator<User>() { @Override public int compare(User u1, User u2) { return ComparisonChain.start() .compare(u1.getSurname(), u2.getSurname()) .compare(u1.getName(), u2.getName()) .result(); } };
  • 79. DRUGA PRÓBA com.google.common.collect.Iterables import static com.google.common.collect.Iterables.*; Iterable<User> users = transform(logins, new FetchUsers(userDao)); Iterable<User> notNullUsers = filter(users, Predicates.notNull()); Iterable<User> matureUsers = filter(notNullUsers, OVER_18); List<User> result = com.google.common.collect.Ordering .from(NAME_ASC) .reverse() .immutableSortedCopy(matureUsers);
  • 80. DRUGA PRÓBA com.google.common.collect.Iterables import static com.google.common.collect.Iterables.*; Iterable<User> users = transform(logins, new FetchUsers(userDao)); Iterable<User> notNullUsers = filter(users, Predicates.notNull()); Iterable<User> matureUsers = filter(notNullUsers, OVER_18); List<User> result = com.google.common.collect.Ordering .from(NAME_ASC) .reverse() .immutableSortedCopy(matureUsers);
  • 81. DRUGA PRÓBA com.google.common.collect.Iterables import static com.google.common.collect.Iterables.*; Iterable<User> users = transform(logins, new FetchUsers(userDao)); Iterable<User> notNullUsers = filter(users, Predicates.notNull()); Iterable<User> matureUsers = filter(notNullUsers, OVER_18); List<User> result = com.google.common.collect.Ordering .from(NAME_ASC) .reverse() .immutableSortedCopy(matureUsers);
  • 82. DRUGA PRÓBA com.google.common.collect.Iterables import static com.google.common.collect.Iterables.*; Iterable<User> users = transform(logins, new FetchUsers(userDao)); Iterable<User> notNullUsers = filter(users, Predicates.notNull()); Iterable<User> matureUsers = filter(notNullUsers, OVER_18); List<User> result = com.google.common.collect.Ordering .from(NAME_ASC) .reverse() .immutableSortedCopy(matureUsers);
  • 83. DRUGA PRÓBA com.google.common.collect.Iterables import static com.google.common.collect.Iterables.*; Iterable<User> users = transform(logins, new FetchUsers(userDao)); Iterable<User> notNullUsers = filter(users, Predicates.notNull()); Iterable<User> matureUsers = filter(notNullUsers, OVER_18); List<User> result = com.google.common.collect.Ordering .from(NAME_ASC) .reverse() .immutableSortedCopy(matureUsers);
  • 84. DRUGA PRÓBA com.google.common.collect.Iterables import static com.google.common.collect.Iterables.*; Iterable<User> users = transform(logins, new FetchUsers(userDao)); Iterable<User> notNullUsers = filter(users, Predicates.notNull()); Iterable<User> matureUsers = filter(notNullUsers, OVER_18); List<User> result = com.google.common.collect.Ordering .from(NAME_ASC) .reverse() .immutableSortedCopy(matureUsers);
  • 85. DRUGA PRÓBA com.google.common.collect.Iterables import static com.google.common.collect.Iterables.*; Iterable<User> users = transform(logins, new FetchUsers(userDao)); Iterable<User> notNullUsers = filter(users, Predicates.notNull()); Iterable<User> matureUsers = filter(notNullUsers, OVER_18); List<User> result = com.google.common.collect.Ordering .from(NAME_ASC) .reverse() .immutableSortedCopy(matureUsers);
  • 86. DRUGA PRÓBA com.google.common.collect.Iterables import static com.google.common.collect.Iterables.*; Iterable<User> users = transform(logins, new FetchUsers(userDao)); Iterable<User> notNullUsers = filter(users, Predicates.notNull()); Iterable<User> matureUsers = filter(notNullUsers, OVER_18); List<User> result = com.google.common.collect.Ordering .from(NAME_ASC) .reverse() .immutableSortedCopy(matureUsers);
  • 87. DRUGA PRÓBA com.google.common.collect.Iterables import static com.google.common.collect.Iterables.*; Iterable<User> users = transform(logins, new FetchUsers(userDao)); Iterable<User> notNullUsers = filter(users, Predicates.notNull()); Iterable<User> matureUsers = filter(notNullUsers, OVER_18); List<User> result = com.google.common.collect.Ordering .from(NAME_ASC) .reverse() .immutableSortedCopy(matureUsers);
  • 88. TRZECIA PRÓBA ImmutableList<User> result = FluentIterable .with(logins) .transform(new FetchUsers(userDao)) .filter(Predicates.notNull()) .filter(OVER_18) .sort(NAME_DESC) .immutableCopy();
  • 89. TRZECIA PRÓBA ImmutableList<User> result = FluentIterable .with(logins) .transform(new FetchUsers(userDao)) .filter(Predicates.notNull()) .filter(OVER_18) .sort(NAME_DESC) .immutableCopy();
  • 90. TRZECIA PRÓBA ImmutableList<User> result = FluentIterable .with(logins) .transform(new FetchUsers(userDao)) .filter(Predicates.notNull()) .filter(OVER_18) .sort(NAME_DESC) .immutableCopy();
  • 91. TRZECIA PRÓBA ImmutableList<User> result = FluentIterable .with(logins) .transform(new FetchUsers(userDao)) .filter(Predicates.notNull()) .filter(OVER_18) .sort(NAME_DESC) .immutableCopy();
  • 92. TRZECIA PRÓBA ImmutableList<User> result = FluentIterable .with(logins) .transform(new FetchUsers(userDao)) .filter(Predicates.notNull()) .filter(OVER_18) .sort(NAME_DESC) .immutableCopy();
  • 93. TRZECIA PRÓBA ImmutableList<User> result = FluentIterable .with(logins) .transform(new FetchUsers(userDao)) .filter(Predicates.notNull()) .filter(OVER_18) .sort(NAME_DESC) .immutableCopy();
  • 94. TRZECIA PRÓBA ImmutableList<User> result = FluentIterable .with(logins) .transform(new FetchUsers(userDao)) .filter(Predicates.notNull()) .filter(OVER_18) .sort(NAME_DESC) .immutableCopy();
  • 95. Czytelność Funkcyjność
  • 96. Pytania? Wiktor Gworek • Javarsovia 2010 • Google

Hinweis der Redaktion

  1. Cze&amp;#x15B;&amp;#x107; wszystkim. Ciesz&amp;#x119; si&amp;#x119;, &amp;#x17C;e jest was tutaj tak du&amp;#x17C;o. Zastanawiam si&amp;#x119;, czy przyszli&amp;#x15B;cie na prezentacje zwabieni jej tytu&amp;#x142;em, czy bardziej przyci&amp;#x105;gn&amp;#x105;&amp;#x142; was fakt, &amp;#x17C;e pracuj&amp;#x119; dla firmy Google. Tadaaa. Witam na prezentacji Lekcja Stylu, czyli czy w Javie mo&amp;#x17C;na jeszcze dostrzec pi&amp;#x119;kno, czy da si&amp;#x119; jeszcze &amp;#x142;adnie i rado&amp;#x15B;nie programowa&amp;#x107;.
  2. Nazywam si&amp;#x119; Wiktor Gworek. Tak wygl&amp;#x105;da m&amp;#xF3;j obecny avatar, gdyby&amp;#x15B;cie mnie szukali. A znale&amp;#x17A;&amp;#x107; mo&amp;#x17C;ecie mnie na Twitterze oraz na Blipie. Od czasu do czasu co&amp;#x15B; ciekawego napisz&amp;#x119; na swoim blogu.
  3. Pracuj&amp;#x119; przy serwisie Blogger.com. Blogger jest najwi&amp;#x119;ksz&amp;#x105; platform&amp;#x105; blogow&amp;#x105; na &amp;#x15B;wiecie, gdzie 275 tysi&amp;#x119;cy s&amp;#x142;&amp;#xF3;w jest pisanych w ci&amp;#x105;gu ka&amp;#x17C;dej minuty. Jest to serwis w ca&amp;#x142;o&amp;#x15B;ci napisany w Javie. Od pierwszego dnia. Co wi&amp;#x119;cej, w sierpniu sko&amp;#x144;czy on 11 lat. By&amp;#x142; on 7 lat temu przepisany na technologie Google&amp;#x2019;owe. Mo&amp;#x17C;ecie sobie wyobrazi&amp;#x107;, &amp;#x17C;e przez ten szmat czasu wiele, na prawd&amp;#x119; wiele in&amp;#x17C;ynier&amp;#xF3;w pracowa&amp;#x142;o przy Bloggerze. Potrzeba by&amp;#x142;o w&amp;#x142;o&amp;#x17C;y&amp;#x107; w niego bardzo du&amp;#x17C;o wysi&amp;#x142;ku, aby kolejni dochodz&amp;#x105;cy do niego in&amp;#x17C;ynierowie mogli efektywnie pracowa&amp;#x107;.
  4. Pracuj&amp;#x119; przy serwisie Blogger.com. Blogger jest najwi&amp;#x119;ksz&amp;#x105; platform&amp;#x105; blogow&amp;#x105; na &amp;#x15B;wiecie, gdzie 275 tysi&amp;#x119;cy s&amp;#x142;&amp;#xF3;w jest pisanych w ci&amp;#x105;gu ka&amp;#x17C;dej minuty. Jest to serwis w ca&amp;#x142;o&amp;#x15B;ci napisany w Javie. Od pierwszego dnia. Co wi&amp;#x119;cej, w sierpniu sko&amp;#x144;czy on 11 lat. By&amp;#x142; on 7 lat temu przepisany na technologie Google&amp;#x2019;owe. Mo&amp;#x17C;ecie sobie wyobrazi&amp;#x107;, &amp;#x17C;e przez ten szmat czasu wiele, na prawd&amp;#x119; wiele in&amp;#x17C;ynier&amp;#xF3;w pracowa&amp;#x142;o przy Bloggerze. Potrzeba by&amp;#x142;o w&amp;#x142;o&amp;#x17C;y&amp;#x107; w niego bardzo du&amp;#x17C;o wysi&amp;#x142;ku, aby kolejni dochodz&amp;#x105;cy do niego in&amp;#x17C;ynierowie mogli efektywnie pracowa&amp;#x107;.
  5. Do Bloggera przyszed&amp;#x142;em p&amp;#xF3;&amp;#x142;tora roku, jako &amp;#x15B;wie&amp;#x17C;ak prosto ze studi&amp;#xF3;w. My&amp;#x15B;la&amp;#x142;em, &amp;#x17C;e potrafi&amp;#x119; programowa&amp;#x107;. Bardzo si&amp;#x119; myli&amp;#x142;em. Lekcja stylu, to moja historia, kt&amp;#xF3;r&amp;#x105; wam przedstawi&amp;#x119;, jak poznawa&amp;#x142;em Jav&amp;#x119; i ma&amp;#x142;ymi krokami dostrzega&amp;#x142;em jej pi&amp;#x119;kno. Chc&amp;#x119;, &amp;#x17C;eby ta prezentacja by&amp;#x142;a dla was inspiracj&amp;#x105;, &amp;#x17C;eby pisa&amp;#x107; &amp;#x142;adniejszy kod, ale tak&amp;#x17C;e &amp;#x17C;eby to by&amp;#x142;a dla was zach&amp;#x119;ta, &amp;#x17C;eby bawi&amp;#x107; si&amp;#x119; z kodem. 1) Pi&amp;#x119;kny kod to taki, kt&amp;#xF3;ry &amp;#x142;atwo si&amp;#x119; czyta. To taki kod, w kt&amp;#xF3;rym brak jest szelmowskich sztuczek piekielnie zdolnego programisty. 2) pozbywanie si&amp;#x119; nisko poziomowego zb&amp;#x119;dnego kodu (tzw. boilerplate code). przyk&amp;#x142;adem dla mnie jest JDBC, gdzie ilo&amp;#x15B;&amp;#x107; nadmiarowego kodu to oko&amp;#x142;o 80%. Mimo to, je&amp;#x15B;li chcemy skorzysta&amp;#x107; z JDBC ten kod musimy napisa&amp;#x107;. 3) to taki kod, kt&amp;#xF3;ry mo&amp;#x17C;na &amp;#x142;atwo testowa&amp;#x107;, gdzie wszystkie zale&amp;#x17C;no&amp;#x15B;ci obiektu s&amp;#x105; jasno zdefiniowane -- tak aby mo&amp;#x17C;na by&amp;#x142;o wstrzykn&amp;#x105;&amp;#x107; do niego obiekty mockuj&amp;#x105;ce sprawdzaj&amp;#x105;ce poprawne zachowanie obiektu. 4) to taki kod, kt&amp;#xF3;ry wykorzystuje typowanie statyczne, aby jak najwcze&amp;#x15B;niej wykrywa&amp;#x107; b&amp;#x142;&amp;#x119;dy w kodzie. Je&amp;#x15B;li piszemy ju&amp;#x17C; w Javie to wykorzystujmy moc, kt&amp;#xF3;r&amp;#x105; nam daje kompilator. 5) A tak&amp;#x17C;e pi&amp;#x119;kny kod mo&amp;#x17C;na uzyskiwa&amp;#x107; poprzez u&amp;#x17C;ywanie odpowiednich narz&amp;#x119;dzi, kt&amp;#xF3;re spowoduj&amp;#x105;, &amp;#x17C;e pisanie kodu stanie si&amp;#x119; &amp;#x142;atwiejsze
  6. Narz&amp;#x119;dzia, kt&amp;#xF3;re stosuje ka&amp;#x17C;dego dnia podczas mojej pracy to Guava (open-sourceowany wycinek wewn&amp;#x119;trzych wsp&amp;#xF3;lnych bibliotek Googleowych), Guice (aby nada&amp;#x107; aplikacji architektoniczny porz&amp;#x105;dek) oraz Mockito - do testowania. Czyli 2 biblioteki Google&amp;#x2019;owe oraz jedna krakowska :). Wymienione tutaj biblioteki upraszczaj&amp;#x105; tw&amp;#xF3;j kod. Z nimi jest &amp;#x142;atwiej pisa&amp;#x107;, czyta&amp;#x107; i utrzymywa&amp;#x107; kod w projekcie. Chocia&amp;#x17C; mogliby&amp;#x15B;my przetrwa&amp;#x107; bez nich i rzeczy, kt&amp;#xF3;re one wprowadzaj&amp;#x105;, to jednak zwi&amp;#x119;ksz&amp;#x105; one moj&amp;#x105; produktywno&amp;#x15B;&amp;#x107; jako programisty. Redukuj&amp;#x105; one spor&amp;#x105; ilo&amp;#x15B;&amp;#x107; zb&amp;#x119;dnego nisko poziomowego kodu, kt&amp;#xF3;ry musia&amp;#x142;bym napisa&amp;#x107;. Zosta&amp;#x142;a tutaj wymieniona biblioteka wspomagaj&amp;#x105;ca mockowanie Mockito. Z dum&amp;#x105; mog&amp;#x119; powiedzie&amp;#x107;, &amp;#x17C;e w Bloggerze wi&amp;#x119;kszo&amp;#x15B;&amp;#x107; test&amp;#xF3;w jest oparta o Mockito. Na tej prezentacji skupi&amp;#x119; si&amp;#x119; na tej pierwszej - Guava.
  7. Prezentacj&amp;#x119; podzieli&amp;#x142;em na 2 cz&amp;#x119;&amp;#x15B;ci. - Na pocz&amp;#x105;tku poka&amp;#x17C;&amp;#x119;, jak ma&amp;#x142;ymi kroczkami b&amp;#x119;dziemy modyfikowa&amp;#x107; nasz kod, aby stawa&amp;#x142; si&amp;#x119; bardziej czytelny. - a nast&amp;#x119;pnie zaprezentuj&amp;#x119;, w jaki spos&amp;#xF3;b mo&amp;#x17C;na si&amp;#x119; bawi&amp;#x107; z Jav&amp;#x105; na przyk&amp;#x142;adzie programowania funkcyjnego. Do dzie&amp;#x142;a.
  8. Zacznijmy od poprawiania kodu. Wyznaczmy sobie jaki&amp;#x15B; cel, do kt&amp;#xF3;rego b&amp;#x119;dziemy d&amp;#x105;&amp;#x17C;y&amp;#x107;.
  9. Oto nasz cel. Miejmy ten cytat w g&amp;#x142;owie i zaczynajmy.
  10. Tre&amp;#x15B;&amp;#x107; tre&amp;#x15B;ci&amp;#x105;, ale tak&amp;#x17C;e trzeba dba&amp;#x107; o form&amp;#x119; prezentacji. Styl kodowania jest prawie zgodny z Sunowskim stylem kodowania w Javie. Czyli: * szeroko&amp;#x15B;&amp;#x107; linii to 100 znak&amp;#xF3;w, nie ma wyj&amp;#x105;tk&amp;#xF3;w - ciekawostka a propos 80 znak&amp;#xF3;w i os&amp;#xF3;b niedowidz&amp;#x105;cych * (pami&amp;#x119;tajcie, &amp;#x17C;e z&amp;#x142;o czai si&amp;#x119; wsz&amp;#x119;dzie) bezwzgl&amp;#x119;dny zakaz u&amp;#x17C;ywania tabulator&amp;#xF3;w * wci&amp;#x119;cia w blokach kodu stosujemy 2 znaki, a nie 4 znaki; kod w&amp;#xF3;wczas optycznie jest mniej rozwleczony, lepiej si&amp;#x119; go czyta * oraz zawsze nawiasujemy, nawet w przypadku instrukcji warunkowych, pod kt&amp;#xF3;rymi jest tylko jedna instrukcja.
  11. Tre&amp;#x15B;&amp;#x107; tre&amp;#x15B;ci&amp;#x105;, ale tak&amp;#x17C;e trzeba dba&amp;#x107; o form&amp;#x119; prezentacji. Styl kodowania jest prawie zgodny z Sunowskim stylem kodowania w Javie. Czyli: * szeroko&amp;#x15B;&amp;#x107; linii to 100 znak&amp;#xF3;w, nie ma wyj&amp;#x105;tk&amp;#xF3;w - ciekawostka a propos 80 znak&amp;#xF3;w i os&amp;#xF3;b niedowidz&amp;#x105;cych * (pami&amp;#x119;tajcie, &amp;#x17C;e z&amp;#x142;o czai si&amp;#x119; wsz&amp;#x119;dzie) bezwzgl&amp;#x119;dny zakaz u&amp;#x17C;ywania tabulator&amp;#xF3;w * wci&amp;#x119;cia w blokach kodu stosujemy 2 znaki, a nie 4 znaki; kod w&amp;#xF3;wczas optycznie jest mniej rozwleczony, lepiej si&amp;#x119; go czyta * oraz zawsze nawiasujemy, nawet w przypadku instrukcji warunkowych, pod kt&amp;#xF3;rymi jest tylko jedna instrukcja.
  12. Tre&amp;#x15B;&amp;#x107; tre&amp;#x15B;ci&amp;#x105;, ale tak&amp;#x17C;e trzeba dba&amp;#x107; o form&amp;#x119; prezentacji. Styl kodowania jest prawie zgodny z Sunowskim stylem kodowania w Javie. Czyli: * szeroko&amp;#x15B;&amp;#x107; linii to 100 znak&amp;#xF3;w, nie ma wyj&amp;#x105;tk&amp;#xF3;w - ciekawostka a propos 80 znak&amp;#xF3;w i os&amp;#xF3;b niedowidz&amp;#x105;cych * (pami&amp;#x119;tajcie, &amp;#x17C;e z&amp;#x142;o czai si&amp;#x119; wsz&amp;#x119;dzie) bezwzgl&amp;#x119;dny zakaz u&amp;#x17C;ywania tabulator&amp;#xF3;w * wci&amp;#x119;cia w blokach kodu stosujemy 2 znaki, a nie 4 znaki; kod w&amp;#xF3;wczas optycznie jest mniej rozwleczony, lepiej si&amp;#x119; go czyta * oraz zawsze nawiasujemy, nawet w przypadku instrukcji warunkowych, pod kt&amp;#xF3;rymi jest tylko jedna instrukcja.
  13. Tre&amp;#x15B;&amp;#x107; tre&amp;#x15B;ci&amp;#x105;, ale tak&amp;#x17C;e trzeba dba&amp;#x107; o form&amp;#x119; prezentacji. Styl kodowania jest prawie zgodny z Sunowskim stylem kodowania w Javie. Czyli: * szeroko&amp;#x15B;&amp;#x107; linii to 100 znak&amp;#xF3;w, nie ma wyj&amp;#x105;tk&amp;#xF3;w - ciekawostka a propos 80 znak&amp;#xF3;w i os&amp;#xF3;b niedowidz&amp;#x105;cych * (pami&amp;#x119;tajcie, &amp;#x17C;e z&amp;#x142;o czai si&amp;#x119; wsz&amp;#x119;dzie) bezwzgl&amp;#x119;dny zakaz u&amp;#x17C;ywania tabulator&amp;#xF3;w * wci&amp;#x119;cia w blokach kodu stosujemy 2 znaki, a nie 4 znaki; kod w&amp;#xF3;wczas optycznie jest mniej rozwleczony, lepiej si&amp;#x119; go czyta * oraz zawsze nawiasujemy, nawet w przypadku instrukcji warunkowych, pod kt&amp;#xF3;rymi jest tylko jedna instrukcja.
  14. Pierwsza porada. Zacznijcie kodowa&amp;#x107; defensywnie. Jasno zapisujcie warunki wej&amp;#x15B;cia do metod. Co prawda mogliby&amp;#x15B;cie zapisa&amp;#x107; te rzeczy w JavaDocach, to jednak nie jest wystarczaj&amp;#x105;ce, gdy&amp;#x17C; kompilator nie patrzy na JavaDoci i ich nie rozumie.
  15. Jak w takim razie kodowanie defensywne mo&amp;#x17C;e wygl&amp;#x105;da&amp;#x107;? Tadaaa. W jasny i precyzyjny spos&amp;#xF3;b zacz&amp;#x105;&amp;#x142;em definiowa&amp;#x107; wej&amp;#x15B;cie do metody. Mo&amp;#x17C;na co prawda by wykorzysta&amp;#x107; metody assert, kt&amp;#xF3;re istniej&amp;#x105; w Javie - to jednak nie s&amp;#x105; one domy&amp;#x15B;lnie w&amp;#x142;&amp;#x105;czone. Co uzyskujemy przez to? - bardziej czytelny kod - moj kod wowczas mniej sie wywala, - latwiej dostrzec przypadki brzegowe.
  16. Ale czy da si&amp;#x119; to lepiej zapisa&amp;#x107;? Tak, w Guavie znajdziemy klas&amp;#x119; Preconditions. Jest to zbi&amp;#xF3;r metod statycznych, kt&amp;#xF3;re mo&amp;#x17C;na u&amp;#x17C;ywa&amp;#x107; do zdefiniowania wej&amp;#x15B;cia do metody. Dzi&amp;#x119;ki temu otrzymujemy zachowanie fail-fast i wyj&amp;#x105;tek, kt&amp;#xF3;ry mo&amp;#x17C;emy otrzyma&amp;#x107; jest bardzo czytelny. Jaka jest r&amp;#xF3;&amp;#x17C;nica pomi&amp;#x119;dzy poprzednim zapisem a u&amp;#x17C;yciem Preconditions? &amp;#x17B;adna! Natomiast czytelno&amp;#x15B;&amp;#x107; kodu zosta&amp;#x142;a zwi&amp;#x119;kszona.
  17. Albo czy czasem nie macie do&amp;#x15B;&amp;#x107; pisania zb&amp;#x119;dnego kodu? Czy w waszych g&amp;#x142;owach nie zapala si&amp;#x119; &amp;#x15B;wiat&amp;#x142;o ostrzegawcze, kiedy piszecie co&amp;#x15B;, co w waszym prze&amp;#x15B;wiadczeniu powinno by&amp;#x107; du&amp;#x17C;o prostsze?
  18. Dla mnie takim zb&amp;#x119;dnym kodem podczas codziennej pracy to inicjalizacja kolekcji. Guava w interesuj&amp;#x105;cy spos&amp;#xF3;b rozprawia si&amp;#x119; z tym problemem. Dostarcza wielu bardzo warto&amp;#x15B;ciowych metod. Fajne, no nie? Dzi&amp;#x119;ki typom generycznym i por&amp;#x119;cznym metodom wytw&amp;#xF3;rczym (factory method) wygl&amp;#x105;da to ju&amp;#x17C; o niebo lepiej. Nie musimy pisa&amp;#x107; nudnego kodu, kt&amp;#xF3;ry Java powinna rozumie&amp;#x107; od pocz&amp;#x105;tku. Powy&amp;#x17C;sze metody wytw&amp;#xF3;rcze maj&amp;#x105; zosta&amp;#x107; wprowadzone w JDK 7 i b&amp;#x119;dzie to &amp;#x15B;wietne. Ale po co czeka&amp;#x107; na nie teraz?
  19. Przejd&amp;#x17A;my do konceptu niemodyfikowalnych obiekt&amp;#xF3;w. Uwaga: je&amp;#x15B;li chcia&amp;#x142;bym, &amp;#x17C;eby&amp;#x15B;cie zapami&amp;#x119;tali z tej prezentacji jedn&amp;#x105; rzecz to w&amp;#x142;a&amp;#x15B;nie koncept niemodyfikowalnych obiekt&amp;#xF3;w. Ok, co to s&amp;#x105; niemodyfikowalne obiekty?
  20. (1) Nie dostarczaj metod modyfikuj&amp;#x105;cych stan obiektu. Settery. (2) Oznacz wszystkie pola klasy jako final. To jasno i precyzyjnie okre&amp;#x15B;la twoje intencje. Java w czasie kompilacji jest w stanie to sprawdzi&amp;#x107;. W ten spos&amp;#xF3;b nowo utworzony obiekt jest w pe&amp;#x142;ni zainicjalizowany i nie potrzeba &amp;#x17C;adnego ekstra kodu do jego inicjalizacji. Przynajmniej tak powinno by&amp;#x107;. Obiekty niemodyfikowalne s&amp;#x105; proste, z natury bezpieczne w&amp;#x105;tkowo, nie wymagaj&amp;#x105; &amp;#x17C;adnej synchronizacji i mog&amp;#x105; by&amp;#x107; dowolnie wsp&amp;#xF3;&amp;#x142;dzielone. Jest to bardzo wa&amp;#x17C;na cecha. Poniewa&amp;#x17C; w komputerach mamy coraz wi&amp;#x119;cej rdzeni, a wi&amp;#x119;c jeste&amp;#x15B;my w stanie rozproszy&amp;#x107; obliczenia. &amp;#x17B;eby to robi&amp;#x107; efektywnie, wsp&amp;#xF3;&amp;#x142;dzielone obiekty nie powinny zmienia&amp;#x107; swojego stanu, jako &amp;#x17C;e problemy wsp&amp;#xF3;&amp;#x142;bie&amp;#x17C;ne b&amp;#x119;d&amp;#x105; krzycze&amp;#x107; na produkcji. --- Jedyn&amp;#x105; wad&amp;#x105; takich obiekt&amp;#xF3;w jest to, &amp;#x17C;e wymagaj&amp;#x105; osobnego obiektu, kiedy jego stan si&amp;#x119; zmienia. -- kiedy jeszcze raz bedziesz chcial napisac metoda zaczynajaca sie na set* - zastanow sie
  21. Wygl&amp;#x105;da kod znajomo? Taki kod cz&amp;#x119;sto mo&amp;#x17C;na spotka&amp;#x107; podczas pisania test&amp;#xF3;w, kiedy chcemy dostarczy&amp;#x107; testowanej klasie jakie&amp;#x15B; dane. Lub kiedy chcemy stworzy&amp;#x107; sta&amp;#x142;y zbi&amp;#xF3;r warto&amp;#x15B;ci. Zazwyczaj piszemy pole, kt&amp;#xF3;re jest public static final. Nadajemy nazw&amp;#x119;. Nast&amp;#x119;pnie wype&amp;#x142;niamy zbi&amp;#xF3;r elementami. Mamy 2 metody do dyspozycji: albo zawo&amp;#x142;a&amp;#x107; metod&amp;#x119; statyczn&amp;#x105; albo zainicjalizowa&amp;#x107; pol&amp;#x119; w bloku statycznym. Drugie rozwi&amp;#x105;zanie jest najbardziej popularne. Tak&amp;#x17C;e tworzymy zbi&amp;#xF3;r, wype&amp;#x142;niamy go elementami, a nast&amp;#x119;pnie tworzymy z tego niezmienialny zbi&amp;#xF3;r. Zaskakuj&amp;#x105;ce jest, jak cz&amp;#x119;sto zapomina si&amp;#x119; o ostatniej linijce. W&amp;#xF3;wczas mamy zbi&amp;#xF3;r, kt&amp;#xF3;ry mo&amp;#x17C;na zmodyfikowa&amp;#x107; w polu public static final.
  22. Kr&amp;#xF3;tsze, ale u&amp;#x17C;ywa a&amp;#x17C; czterech klas. Co&amp;#x15B; jest nie tak.
  23. To co na prawd&amp;#x119; w&amp;#xF3;wczas chcesz to niemodyfikowalna kolekcja wype&amp;#x142;niona danymi. I &amp;#x17C;eby to zgrabnie wygl&amp;#x105;da&amp;#x142;o. Teraz kod m&amp;#xF3;wi dok&amp;#x142;adnie to, co mamy na my&amp;#x15B;li. + jest to du&amp;#x17C;o wydajne
  24. To co na prawd&amp;#x119; w&amp;#xF3;wczas chcesz to niemodyfikowalna kolekcja wype&amp;#x142;niona danymi. I &amp;#x17C;eby to zgrabnie wygl&amp;#x105;da&amp;#x142;o. Teraz kod m&amp;#xF3;wi dok&amp;#x142;adnie to, co mamy na my&amp;#x15B;li. + jest to du&amp;#x17C;o wydajne
  25. To co na prawd&amp;#x119; w&amp;#xF3;wczas chcesz to niemodyfikowalna kolekcja wype&amp;#x142;niona danymi. I &amp;#x17C;eby to zgrabnie wygl&amp;#x105;da&amp;#x142;o. Teraz kod m&amp;#xF3;wi dok&amp;#x142;adnie to, co mamy na my&amp;#x15B;li. + jest to du&amp;#x17C;o wydajne
  26. Wygl&amp;#x105;da kod znajomo? Czy nigdy nie potrzebowa&amp;#x142;e&amp;#x15B; mapy, kt&amp;#xF3;ra mo&amp;#x17C;e przechowywa&amp;#x107; wiele warto&amp;#x15B;ci dla jednego klucza? Czy za ka&amp;#x17C;dym razem piszesz taki kod? Kod do&amp;#x15B;&amp;#x107; cz&amp;#x119;sto pisany przez programist&amp;#xF3;w, kiedy ich zadaniem jest pogrupowanie element&amp;#xF3;w z wej&amp;#x15B;cia.
  27. Wygl&amp;#x105;da kod znajomo? Czy nigdy nie potrzebowa&amp;#x142;e&amp;#x15B; mapy, kt&amp;#xF3;ra mo&amp;#x17C;e przechowywa&amp;#x107; wiele warto&amp;#x15B;ci dla jednego klucza? Czy za ka&amp;#x17C;dym razem piszesz taki kod? Kod do&amp;#x15B;&amp;#x107; cz&amp;#x119;sto pisany przez programist&amp;#xF3;w, kiedy ich zadaniem jest pogrupowanie element&amp;#xF3;w z wej&amp;#x15B;cia.
  28. Wygl&amp;#x105;da kod znajomo? Czy nigdy nie potrzebowa&amp;#x142;e&amp;#x15B; mapy, kt&amp;#xF3;ra mo&amp;#x17C;e przechowywa&amp;#x107; wiele warto&amp;#x15B;ci dla jednego klucza? Czy za ka&amp;#x17C;dym razem piszesz taki kod? Kod do&amp;#x15B;&amp;#x107; cz&amp;#x119;sto pisany przez programist&amp;#xF3;w, kiedy ich zadaniem jest pogrupowanie element&amp;#xF3;w z wej&amp;#x15B;cia.
  29. Wygl&amp;#x105;da kod znajomo? Czy nigdy nie potrzebowa&amp;#x142;e&amp;#x15B; mapy, kt&amp;#xF3;ra mo&amp;#x17C;e przechowywa&amp;#x107; wiele warto&amp;#x15B;ci dla jednego klucza? Czy za ka&amp;#x17C;dym razem piszesz taki kod? Kod do&amp;#x15B;&amp;#x107; cz&amp;#x119;sto pisany przez programist&amp;#xF3;w, kiedy ich zadaniem jest pogrupowanie element&amp;#xF3;w z wej&amp;#x15B;cia.
  30. Wygl&amp;#x105;da kod znajomo? Czy nigdy nie potrzebowa&amp;#x142;e&amp;#x15B; mapy, kt&amp;#xF3;ra mo&amp;#x17C;e przechowywa&amp;#x107; wiele warto&amp;#x15B;ci dla jednego klucza? Czy za ka&amp;#x17C;dym razem piszesz taki kod? Kod do&amp;#x15B;&amp;#x107; cz&amp;#x119;sto pisany przez programist&amp;#xF3;w, kiedy ich zadaniem jest pogrupowanie element&amp;#xF3;w z wej&amp;#x15B;cia.
  31. Jest to przyk&amp;#x142;ad multimap w Google Collections, czyli takich map, gdzie dla danego klucza mo&amp;#x17C;na trzyma&amp;#x107; wiele warto&amp;#x15B;ci. W przypadku ListMultimap, kolejno&amp;#x15B;&amp;#x107; dodawanych warto&amp;#x15B;ci dla danego klucza zostanie zachowana. Zach&amp;#x119;cam do zapoznania si&amp;#x119; si&amp;#x119; z com.google.common.collect, jako &amp;#x17C;e czekaj&amp;#x105; tam prawdziwe pere&amp;#x142;ki.
  32. Jest to przyk&amp;#x142;ad multimap w Google Collections, czyli takich map, gdzie dla danego klucza mo&amp;#x17C;na trzyma&amp;#x107; wiele warto&amp;#x15B;ci. W przypadku ListMultimap, kolejno&amp;#x15B;&amp;#x107; dodawanych warto&amp;#x15B;ci dla danego klucza zostanie zachowana. Zach&amp;#x119;cam do zapoznania si&amp;#x119; si&amp;#x119; z com.google.common.collect, jako &amp;#x17C;e czekaj&amp;#x105; tam prawdziwe pere&amp;#x142;ki.
  33. Jest to przyk&amp;#x142;ad multimap w Google Collections, czyli takich map, gdzie dla danego klucza mo&amp;#x17C;na trzyma&amp;#x107; wiele warto&amp;#x15B;ci. W przypadku ListMultimap, kolejno&amp;#x15B;&amp;#x107; dodawanych warto&amp;#x15B;ci dla danego klucza zostanie zachowana. Zach&amp;#x119;cam do zapoznania si&amp;#x119; si&amp;#x119; z com.google.common.collect, jako &amp;#x17C;e czekaj&amp;#x105; tam prawdziwe pere&amp;#x142;ki.
  34. Jest to przyk&amp;#x142;ad multimap w Google Collections, czyli takich map, gdzie dla danego klucza mo&amp;#x17C;na trzyma&amp;#x107; wiele warto&amp;#x15B;ci. W przypadku ListMultimap, kolejno&amp;#x15B;&amp;#x107; dodawanych warto&amp;#x15B;ci dla danego klucza zostanie zachowana. Zach&amp;#x119;cam do zapoznania si&amp;#x119; si&amp;#x119; z com.google.common.collect, jako &amp;#x17C;e czekaj&amp;#x105; tam prawdziwe pere&amp;#x142;ki.
  35. Stosowanie p&amp;#x142;ynnych interfejs&amp;#xF3;w (tzw. fluent interface) to spos&amp;#xF3;b implementacji API w j&amp;#x119;zykach obiektowych, kt&amp;#xF3;rych celem jest zwi&amp;#x119;kszenie czytelno&amp;#x15B;ci kodu. Chodzi o to, &amp;#x17C;eby osoba czytaj&amp;#x105;ca mia&amp;#x142;a wra&amp;#x17C;enie, jakby czyta&amp;#x142;a zdanie w j&amp;#x119;zyku naturalnym. Jedn&amp;#x105; z technik&amp;#x105; uzyskania p&amp;#x142;ynnego interfejsu jest method chaining, czyli &amp;#x142;a&amp;#x144;cuszek metod. Zobaczmy to na przyk&amp;#x142;adach z Google Guava.
  36. Stosowanie p&amp;#x142;ynnych interfejs&amp;#xF3;w (tzw. fluent interface) to spos&amp;#xF3;b implementacji API w j&amp;#x119;zykach obiektowych, kt&amp;#xF3;rych celem jest zwi&amp;#x119;kszenie czytelno&amp;#x15B;ci kodu. Chodzi o to, &amp;#x17C;eby osoba czytaj&amp;#x105;ca mia&amp;#x142;a wra&amp;#x17C;enie, jakby czyta&amp;#x142;a zdanie w j&amp;#x119;zyku naturalnym. Jedn&amp;#x105; z technik&amp;#x105; uzyskania p&amp;#x142;ynnego interfejsu jest method chaining, czyli &amp;#x142;a&amp;#x144;cuszek metod. Zobaczmy to na przyk&amp;#x142;adach z Google Guava.
  37. Stosowanie p&amp;#x142;ynnych interfejs&amp;#xF3;w (tzw. fluent interface) to spos&amp;#xF3;b implementacji API w j&amp;#x119;zykach obiektowych, kt&amp;#xF3;rych celem jest zwi&amp;#x119;kszenie czytelno&amp;#x15B;ci kodu. Chodzi o to, &amp;#x17C;eby osoba czytaj&amp;#x105;ca mia&amp;#x142;a wra&amp;#x17C;enie, jakby czyta&amp;#x142;a zdanie w j&amp;#x119;zyku naturalnym. Jedn&amp;#x105; z technik&amp;#x105; uzyskania p&amp;#x142;ynnego interfejsu jest method chaining, czyli &amp;#x142;a&amp;#x144;cuszek metod. Zobaczmy to na przyk&amp;#x142;adach z Google Guava.
  38. Java nie jest j&amp;#x119;zykiem funkcyjnym. Mo&amp;#x17C;na natomiast z funkcyjno&amp;#x15B;ci&amp;#x105; eksperymentowa&amp;#x107;. Jest to bardzo udana zabawa zw&amp;#x142;aszcza z kolekcjami. Java i programowanie funkcyjne to trudna mi&amp;#x142;o&amp;#x15B;&amp;#x107;. Jednak poszukiwanie dostarcza du&amp;#x17C;o rado&amp;#x15B;ci. Zobaczmy.
  39. Funkcja to operacja, kt&amp;#xF3;ra transformuje jest obiekt w drugi. Na przyk&amp;#x142;ad wyobra&amp;#x17A;my sobie funkcj&amp;#x119;, kt&amp;#xF3;ra transformuje &amp;#x142;a&amp;#x144;cuch znak&amp;#xF3;w do liczb, czyli dla &amp;#x142;a&amp;#x144;cucha &amp;#x201C;22&amp;#x201D; zwracana jest liczba ca&amp;#x142;kowita 22. Funkcja transformuj&amp;#x105;ca nie musi zwraca&amp;#x107; obiektu innego typu. Przyk&amp;#x142;adem niech b&amp;#x119;dzie funkcja konwertuj&amp;#x105;ca stopnie w farenheicie do stopni w celsiuszu. &amp;#x17B;adnych, ale to &amp;#x17C;adnych efekt&amp;#xF3;w ubocznych.
  40. Predykat to rodzaj funkcji, kt&amp;#xF3;ry dla wej&amp;#x15B;cia zwraca prawd&amp;#x119; lub fa&amp;#x142;sz. W JDK korzystamy z wyra&amp;#x17C;e&amp;#x144; regularnych do&amp;#x15B;&amp;#x107; cz&amp;#x119;sto. Wyobra&amp;#x17A;my sobie predykat wykorzystuj&amp;#x105;cy wyra&amp;#x17C;enie regularne. Dla danego &amp;#x142;a&amp;#x144;cucha znak&amp;#xF3;w zwraca prawd&amp;#x119;, je&amp;#x15B;li wyra&amp;#x17C;enie regularne pokrywa &amp;#x142;a&amp;#x144;cuch znak&amp;#xF3;w. Tak samo jak w przypadku funkcji: &amp;#x17C;adnych, ale to &amp;#x17C;adnych efekt&amp;#xF3;w ubocznych.
  41. Podsumowuj&amp;#x105;c, pokaza&amp;#x142;em wam, w jaki spos&amp;#xF3;b przekonywa&amp;#x142;em siebie, &amp;#x17C;e w Javie mo&amp;#x17C;na dostrzec &amp;#x142;adny programowania. Rozpocz&amp;#x105;&amp;#x142;em swoj&amp;#x105; przygod&amp;#x119; poprawiaj&amp;#x105;c sw&amp;#xF3;j kod ma&amp;#x142;ymi krokami. Gdy nast&amp;#x119;pnie nabra&amp;#x142;em rozp&amp;#x119;du - zacz&amp;#x105;&amp;#x142;em eksperymentowa&amp;#x107;, do czego was bardzo zach&amp;#x119;cam.