Java Streams

A few minutes ago my wife called me up to the kitchen to help her. She needed Grand Maniere for an Italian nonna’s apple cake she was making. In addition to the apples, she likes to add raisins soaked in liquor. She decided to use Grand Maniere because she found a large bottle in the liquor cabinet. She could not remove the cork so she called me for help. As I was attempting to open the bottle I asked if she remembered when we got it. It seems that we bought the bottle when we lived in Maryland; that was many years ago.

The cork disintegrated when I was opening the bottle. The bottle was standing up and with the years the cork dried up. We keep our wines in an angle in our cellar, but the hard liquor in our cabinet is standing right side up. We seldom consume hard liquor. The Grand Maniere smelled fine and my wife was able to soak the raisins. Each time she fixes this dessert she tries to make it a little different. In my opinion, apples, raisins and walnuts go very well together. Will let you know in my next post how this cake turned out.

Over the weekend I read the post “Don’t like loops? Try Java Streams” by Chris Hermansen. I read and liked the article because on my post “The Full Counting Sort” HackerRank used in the testing scaffolding Java Streams to collect data. It turned out that if you used the scaffolding which after collecting data made a call for the solution, all test cases would pass with the exception of one which would time out. If you are interested please read my previous post.

Java Streams provide functional programming to the Java language. Like any other functional programming language, when you go from imperative to functional, you need to change your frame of mind. I had just finished “The Full Counting Sort” and run across the article “Don’t like loops? Try Java Streams” so I had to write about Java Streams.

I read a couple additional articles and watched three YouTube videos. The video that I liked and used as basis for my experimentation for this post is “Java Streams Tutorial | 2020”.

If you are not familiar with functional programming you can read about it in Wikipedia. If you are not familiar with Java Streams, which were introduced in Java 8, you can read about it here.

If I feel inclined and I finish something from work today or tomorrow, I might go back to my previous post “The Full Counting Sort” and update the code using Java Streams. The issue that I have is that it takes time to come up with a reasonably good implementation and then is the time associated with the post. Will see hos the next couple days go.

While reading and watching videos about Java Streams I put together the following points of interest:

  1. Streams provide a good way to move from imperative to declarative programming. About three years ago I purchased, read the book “Learn You a Haskell for Great Good” and experimented with Haskell. Haskell is a declarative programming language.
  2. Stream allows you work with Collections/Lists using less code. The code is easy to alter if you need to add functionality.
  3. Streams give you as a developer an API where you can ask what you want instead of defining the full implementation for the thing you want.
# **** contents of my workspace7 folder ****
C:\Users\John\workspace7>dir
02/20/2020  08:08 AM    <DIR>          .
02/20/2020  08:08 AM    <DIR>          ..
01/30/2020  01:32 PM    <DIR>          .metadata
01/31/2020  09:02 AM    <DIR>          .vscode
01/05/2020  07:15 AM    <DIR>          3DSurfaceArea
01/06/2020  11:52 AM    <DIR>          AlmostSorted
02/06/2020  07:16 AM    <DIR>          AndProduct
01/24/2020  12:49 PM    <DIR>          AStarSearch
12/05/2019  01:23 PM    <DIR>          BiggerIsGreater
02/14/2020  03:00 PM    <DIR>          Cipher
12/22/2019  08:35 AM    <DIR>          DeterminingDNAHealth
01/08/2020  07:07 AM    <DIR>          EmasSupercomputer
02/12/2020  02:46 PM    <DIR>          FirstDuplicate
02/03/2020  09:07 AM    <DIR>          FlippingBits
02/20/2020  08:14 AM    <DIR>          FullCountingSort
02/16/2020  09:09 AM    <DIR>          GitHubTest
01/31/2020  02:57 PM    <DIR>          guava-mini
01/31/2020  10:44 AM    <DIR>          HelloMaven
02/17/2020  10:43 AM         2,339,925 ij.jar
02/17/2020  10:52 AM    <DIR>          ImageJ
02/04/2020  02:04 PM    <DIR>          JumpingOnTheClouds
01/23/2020  08:05 AM    <DIR>          LarrysArray
12/03/2019  04:26 PM    <DIR>          MatrixLayerRotation
02/03/2020  10:42 AM    <DIR>          MiniMaxSum
01/25/2020  08:07 AM    <DIR>          PriorityQ
01/30/2020  01:42 PM    <DIR>          rtree2
02/03/2020  01:44 PM    <DIR>          SansaXOR
01/19/2020  09:16 AM    <DIR>          StacksReverseOrder
02/19/2020  08:08 AM    <DIR>          SumOfTwo
01/04/2020  07:51 AM    <DIR>          TheGridSearch
12/11/2019  10:09 AM    <DIR>          ToTrieOrNotToTrie

# **** clone my new and almost empty repository ****
C:\Users\John\workspace7>git clone https://github.com/JohnCanessa/JavaStreams.git
Cloning into 'JavaStreams'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.

# **** change directory to the new folder ****
C:\Users\John\workspace7>cd JavaStreams

# **** list it's contents ****
C:\Users\John\workspace7\JavaStreams>dir /A
02/22/2020  07:08 AM    <DIR>          .
02/22/2020  07:08 AM    <DIR>          ..
02/22/2020  07:08 AM    <DIR>          .git
02/22/2020  07:08 AM               175 README.md

As I have mentioned in the past few posts, I use GitHub and git to post associated code in an accessible repository. I start on my Windows 10 machine by looking at the contents of my workspace7 folder.

I then moved to GitHub and created the JavaStreams repository. In it I just created a simple README.md file which as usual will be updated after this post is published and I have a URL for it.

I cloned the GitHub repo to my machine. Went to the new folder JavaStreams created in my workspace7 folder. The README.md file was cloned.

  /**
   * Return a list of people.
   */
  private static List<Person> getPeople() {

    // **** create array of people ****
    final Person[] people = {
                            new Person("James Bond", 42, Gender.MALE),
                            new Person("Antonio Banderas", 58, Gender.MALE), 
                            new Person("Alina Smith", 33, Gender.FEMALE),
                            new Person("Helen White", 57, Gender.FEMALE), 
                            new Person("Alex Boz", 14, Gender.MALE),
                            new Person("Jamie Goa", 41, Gender.MALE), 
                            new Person("Money Penny", 42, Gender.FEMALE),
                            new Person("Anna Cook", 27, Gender.FEMALE), 
                            new Person("Zelda Brown", 35, Gender.FEMALE),
                            new Person("Dr. No", 42, Gender.MALE)
                            };

    // **** return list of people ****
    return Arrays.asList(people);
  }

The code in this post is written in Java 8. I used the Visual Studio Code IDE. I have been using VSCode over Eclipse and IntelliJ for the past six months. I would say it is getting very powerful but on some special cases it still needs some features.

The getPeople() method is used to return a random set of people that is defined by a name, an age and a gender. I should be more sensitive and update the Gender.java file to include additional options. I will leave it as an exercise for anyone that wishes to update the associated code. If you do so, the “15 Gender Identity Terms You Need to Know to Build an Inclusive Workplace” article could be of help.


    // **** get list of people ****
    final List<Person> people = getPeople();

    // **** **** IMPERATIVE programming approach **** ****

    // **** generate list of females ****
    List<Person> females = new ArrayList<Person>();
    for (Person p : people) {
      if (p.getGender().equals(Gender.FEMALE)) {
        females.add(p);
      }
    }

    // **** display list of females (1) ****
    System.out.println("main <<< females " + females.size() + ": " + females.toString());
    System.out.println();

    // **** display list of females (2) ****
    for (Person f : females) {
      System.out.println("main <<< f: " + f.toString());
    }
    System.out.println();

    // **** display list of females (3) ****
    females.forEach(System.out::println);
    System.out.println();

The last code snippet is part of the main() function in the code. It illustrates the imperative approach to display the list of females. As we will see in a few, is you need to be more selective, the amount of imperative code will grow considerable more than if we use a declarative approach.

main <<< females 5: [Person{name ==>Alina Smith<== age: 33 gender: FEMALE}, Person{name ==>Helen White<== age: 57 gender: FEMALE}, Person{name ==>Money Penny<== age: 42 gender: FEMALE}, Person{name ==>Anna Cook<== age: 27 gender: FEMALE}, Person{name ==>Zelda Brown<== age: 35 gender: FEMALE}]

main <<< f: Person{name ==>Alina Smith<== age: 33 gender: FEMALE}
main <<< f: Person{name ==>Helen White<== age: 57 gender: FEMALE}
main <<< f: Person{name ==>Money Penny<== age: 42 gender: FEMALE}
main <<< f: Person{name ==>Anna Cook<== age: 27 gender: FEMALE}
main <<< f: Person{name ==>Zelda Brown<== age: 35 gender: FEMALE} Person{name ==>Alina Smith<== age: 33 gender: FEMALE} Person{name ==>Helen White<== age: 57 gender: FEMALE} Person{name ==>Money Penny<== age: 42 gender: FEMALE} Person{name ==>Anna Cook<== age: 27 gender: FEMALE} Person{name ==>Zelda Brown<== age: 35 gender: FEMALE}

When executed, the above code gets the list of people and then generates a new list with only female people. The list is displayed three times using slightly different approaches.

Let’s change gears and use a functional / declarative approach using Java Streams. In this first code snippet we get all females using a filter and decide to put the results in a list of Person. Once done we display the contents of our list of females.

    // **** **** FUNCTIONAL / DECLARATIVE programming approach **** ****

    // **** generate list of females ****
    List<Person> femaleList = people.stream()                       // abstraction
        .filter(person -> person.getGender().equals(Gender.FEMALE)) // filter
        .collect(Collectors.toList());                              // collect

    // **** display list of females ****
    femaleList.forEach(System.out::println);
    System.out.println();

The code generates the following output:

Person{name ==>Alina Smith<== age: 33 gender: FEMALE} Person{name ==>Helen White<== age: 57 gender: FEMALE} Person{name ==>Money Penny<== age: 42 gender: FEMALE} Person{name ==>Anna Cook<== age: 27 gender: FEMALE} Person{name ==>Zelda Brown<== age: 35 gender: FEMALE}

We collect five people from our initial list matching the criteria that they all must be females. Note that we will always start processing streams with the people.stream() abstraction. In our case people is the list that was returned from our function call. Such data may come from different sources and methods.

    // **** generate list of people sorted by age ****
    List<Person> ageList = people.stream()            // abstraction
        .sorted(Comparator.comparing(Person::getAge)  // person age
            .thenComparing(Person::getGender)         // person gender
            .reversed())                              // reversed sort
        .collect(Collectors.toList());                // collect

    // **** display list sorted by age ****
    ageList.forEach(System.out::println);
    System.out.println();

Our requirements are to generate a list ordered by age. When people have the same age they need to be sorted by gender first (females before males). The results should be place in a new list. For convenience and to make sure we processed the list correctly, we display the resulting list.

Person{name ==>Antonio Banderas<== age: 58 gender: MALE} Person{name ==>Helen White<== age: 57 gender: FEMALE} Person{name ==>Money Penny<== age: 42 gender: FEMALE}   <=== Person{name ==>James Bond<== age: 42 gender: MALE}      <=== Person{name ==>Dr. No<== age: 42 gender: MALE}          <=== Person{name ==>Jamie Goa<== age: 41 gender: MALE} Person{name ==>Zelda Brown<== age: 35 gender: FEMALE} Person{name ==>Alina Smith<== age: 33 gender: FEMALE} Person{name ==>Anna Cook<== age: 27 gender: FEMALE} Person{name ==>Alex Boz<== age: 14 gender: MALE}

As expected, the resulting list is sorted by age in descending order. We could have done it in ascending order if required. There are three people with age 42. The females are listed before the male. The arrows were added during editing. There is no code to generate them.

    // **** determine if all people are equal or over ager 14 ****
    boolean allMatch = people.stream()                          // abstraction
        .allMatch(p -> p.getAge() >= 14);                       // all match

    // **** display result ****
    System.out.println("main <<< allMatch: " + allMatch); // **** determine if there are matches when people are older than 60 **** boolean anyMatch = people.stream() // abstraction .anyMatch(p -> p.getAge() > 60);                        // any match

    // **** display result ****
    System.out.println("main <<< anyMatch: " + anyMatch); // **** check if we have do not have a person with the specified name **** boolean noneMatch = people.stream() // abstraction .noneMatch(p -> p.getName().equals("James Candy"));     // none match

    // **** display result ****
    System.out.println("main <<< noneMatch: " + noneMatch);
    System.out.println();

We have three different matches. In the first case we want to know if all people are older or equal to 14 years of age. The answer should be true.

In the second case, we are interesting in determining if there are people in our list older than 60 years of age. The results should be false. Our oldest person is age 57.

In our third case we are interested in finding is a specified person (James Candy) is in our list. Such person was not part of the list. Since we use the noneMatch operator, the answer should be true.

main <<< allMatch: true
main <<< anyMatch: false
main <<< noneMatch: true

The actual results confirm our expectations. Note that if we decide to write some code to perform these operations we would need some type of loop and a test condition.

   // **** find oldest person (what if such person does not exist?) ****
    Optional<Person> max = people.stream()                      // abstraction
      .max(Comparator.comparing(Person::getAge));               // max age
    System.out.println("main <<< oldest: " + max); // **** find oldest person; if found display element **** people.stream() // abstraction .max(Comparator.comparing(Person::getAge)) // max age .ifPresent(p -> {                                         // if found
        System.out.println(p);                                  // display the person
      });
    System.out.println();

I this snippet we are interested in finding the oldest person in the collection. We need to take into account for the possibility that such person is not in the list. This is by we use the Optional<Person> type. If the person exists the information would be displayed.

The second part of the snippet does the same but it finds the person and if found it displays the information.

main <<< oldest: Optional[Person{name ==>Antonio Banderas<== age: 58 gender: MALE}] Person{name ==>Antonio Banderas<== age: 58 gender: MALE}

The output for both approaches returns the same record.

    // **** find youngest person; if found display element ****
    people.stream()                                             // abstraction
      .min(Comparator.comparing(Person::getAge))                // min age
      .ifPresent(p -> {
        System.out.println("main <<< youngest: " + p);          // display the person
      });
    System.out.println();  

In this case we are looking for the youngest person in our collection.

main <<< youngest: Person{name ==>Alex Boz<== age: 14 gender: MALE}

The information for the youngest person is displayed.

    // **** group ****
    Map<Gender, List<Person>> groupByGender = people.stream()   // abstraction
      .collect(Collectors.groupingBy(Person::getGender));       // group
    
    // **** display results ****
    for (Map.Entry<Gender, List<Person>> entry : groupByGender.entrySet()) {
      Gender gender = entry.getKey();
      System.out.println(gender);
      List<Person> list = entry.getValue();
      for (Person p : list) {
        System.out.println(p.toString());
      }
    }
    System.out.println();

    // **** display same results ****
    groupByGender.forEach((gender, p) -> {
      System.out.println(gender);
      p.forEach(System.out::println);
    });
    System.out.println();

In this case we are interested in grouping people by gender. In the first section we obtained a map of people grouped by gender. We then display the contents of the map.

In the second part of the code we display the contents of the map using simpler code. Both approaches used should display the same data.

FEMALE
Person{name ==>Alina Smith<== age: 33 gender: FEMALE} Person{name ==>Helen White<== age: 57 gender: FEMALE} Person{name ==>Money Penny<== age: 42 gender: FEMALE} Person{name ==>Anna Cook<== age: 27 gender: FEMALE} Person{name ==>Zelda Brown<== age: 35 gender: FEMALE} MALE Person{name ==>James Bond<== age: 42 gender: MALE} Person{name ==>Antonio Banderas<== age: 58 gender: MALE} Person{name ==>Alex Boz<== age: 14 gender: MALE} Person{name ==>Jamie Goa<== age: 41 gender: MALE} Person{name ==>Dr. No<== age: 42 gender: MALE} FEMALE Person{name ==>Alina Smith<== age: 33 gender: FEMALE} Person{name ==>Helen White<== age: 57 gender: FEMALE} Person{name ==>Money Penny<== age: 42 gender: FEMALE} Person{name ==>Anna Cook<== age: 27 gender: FEMALE} Person{name ==>Zelda Brown<== age: 35 gender: FEMALE} MALE Person{name ==>James Bond<== age: 42 gender: MALE} Person{name ==>Antonio Banderas<== age: 58 gender: MALE} Person{name ==>Alex Boz<== age: 14 gender: MALE} Person{name ==>Jamie Goa<== age: 41 gender: MALE} Person{name ==>Dr. No<== age: 42 gender: MALE}

As we can see both approaches to display the results match. The second one appears to be simpler. We did not use a loop. In the first approach we used two embedded loops. The first loop is used to traverse the gender, and the inner loop to traverse the people in the specified groups.

    // **** get and display oldest female name (1) ****
    String oldestName = "";
    int oldestAge = Integer.MIN_VALUE;
    for (Person p : people) {
      if (p.getGender() == Gender.FEMALE) {
        if (p.getAge() > oldestAge) {
          oldestAge = p.getAge();
          oldestName = p.getName();
        }
      }
    }
    System.out.println("oldest female ==>" + oldestName + "<==");

    // **** get and display oldest female name (2) ****
    Optional<String> oldestFemaleAge = people.stream()          // abstratcion
      .filter(p -> p.getGender().equals(Gender.FEMALE))         // filter
      .max(Comparator.comparing(Person::getAge))                // max
      .map(Person::getName);                                    // map

    oldestFemaleAge.ifPresent(name -> System.out.println("oldest female ==>" + name + "<=="));

In this case we are required to look for the oldest female in the group and display her name. We need to define a couple of variables, one to hold the oldest age and the second to hold the name of the oldest female. Once that is done we loop through all the records. When we encounter a female person we check if this person is older. If so we update the oldest age and keep track of the name. When done we display the name.

The second approach uses a filter to only select females. We specify a comparator to get the oldest age and for results we want to get a string with the name of the person. Note that in the first approach we did not check if the name was empty or null. We do that in the second approach.

oldest female ==>Helen White<== oldest female ==>Helen White<==

As we can see, both approaches returned the same name. The second one uses less code and easier to follow.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 
 */
public class Main {

  /**
   * Return a list of people.
   */
  private static List<Person> getPeople() {

    // **** create array of people ****
    final Person[] people = {
                            new Person("James Bond", 42, Gender.MALE),
                            new Person("Antonio Banderas", 58, Gender.MALE), 
                            new Person("Alina Smith", 33, Gender.FEMALE),
                            new Person("Helen White", 57, Gender.FEMALE), 
                            new Person("Alex Boz", 14, Gender.MALE),
                            new Person("Jamie Goa", 41, Gender.MALE), 
                            new Person("Money Penny", 42, Gender.FEMALE),
                            new Person("Anna Cook", 27, Gender.FEMALE), 
                            new Person("Zelda Brown", 35, Gender.FEMALE),
                            new Person("Dr. No", 42, Gender.MALE)
                            };

    // **** return list of people ****
    return Arrays.asList(people);
  }

  /**
   * Main entry point.
   */
  public static void main(final String[] args) {

    // **** get list of people ****
    final List<Person> people = getPeople();

    // **** **** IMPERATIVE programming approach **** ****

    // **** generate list of females ****
    List<Person> females = new ArrayList<Person>();
    for (Person p : people) {
      if (p.getGender().equals(Gender.FEMALE)) {
        females.add(p);
      }
    }

    // **** display list of females (1) ****
    System.out.println("main <<< females " + females.size() + ": " + females.toString());
    System.out.println();

    // **** display list of females (2) ****
    for (Person f : females) {
      System.out.println("main <<< f: " + f.toString());
    }
    System.out.println();

    // **** display list of females (3) ****
    females.forEach(System.out::println);
    System.out.println();

    // **** **** FUNCTIONAL / DECLARATIVE programming approach **** ****

    // **** generate list of females ****
    List<Person> femaleList = people.stream()                       // abstraction
        .filter(person -> person.getGender().equals(Gender.FEMALE)) // filter
        .collect(Collectors.toList());                              // collect

    // **** display list of females ****
    femaleList.forEach(System.out::println);
    System.out.println();

    // **** generate list of people sorted by age ****
    List<Person> ageList = people.stream()            // abstraction
        .sorted(Comparator.comparing(Person::getAge)  // person age
            .thenComparing(Person::getGender)         // person gender
            .reversed())                              // reversed sort
        .collect(Collectors.toList());                // collect

    // **** display list sorted by age ****
    ageList.forEach(System.out::println);
    System.out.println();

    // **** determine if all people are equal or over ager 14 ****
    boolean allMatch = people.stream()                // abstraction
        .allMatch(p -> p.getAge() >= 14);             // all match

    // **** display result ****
    System.out.println("main <<< allMatch: " + allMatch); // **** determine if there are matches when people are older than 60 **** boolean anyMatch = people.stream() // abstraction .anyMatch(p -> p.getAge() > 60);                        // any match

    // **** display result ****
    System.out.println("main <<< anyMatch: " + anyMatch); // **** check if we have do not have a person with the specified name **** boolean noneMatch = people.stream() // abstraction .noneMatch(p -> p.getName().equals("James Candy"));     // none match

    // **** display result ****
    System.out.println("main <<< noneMatch: " + noneMatch);
    System.out.println();

    // **** find oldest person (what if such person does not exist?) ****
    Optional<Person> max = people.stream()                      // abstraction
      .max(Comparator.comparing(Person::getAge));               // max age
    System.out.println("main <<< oldest: " + max); // **** find oldest person; if found display element **** people.stream() // abstraction .max(Comparator.comparing(Person::getAge)) // max age .ifPresent(p -> {                                         // if found
        System.out.println(p);                                  // display the person
      });
    System.out.println();

    // **** find youngest person; if found display element ****
    people.stream()                                             // abstraction
      .min(Comparator.comparing(Person::getAge))                // min age
      .ifPresent(p -> {
        System.out.println("main <<< youngest: " + p);          // display the person
      });
    System.out.println();                     

    // **** group ****
    Map<Gender, List<Person>> groupByGender = people.stream()   // abstraction
      .collect(Collectors.groupingBy(Person::getGender));       // group
    
    // **** display results ****
    for (Map.Entry<Gender, List<Person>> entry : groupByGender.entrySet()) {
      Gender gender = entry.getKey();
      System.out.println(gender);
      List<Person> list = entry.getValue();
      for (Person p : list) {
        System.out.println(p.toString());
      }
    }
    System.out.println();

    // **** display same results ****
    groupByGender.forEach((gender, p) -> {
      System.out.println(gender);
      p.forEach(System.out::println);
    });
    System.out.println();

    // **** get and display oldest female name  ****
    Optional<String> oldestFemaleAge = people.stream()          // abstratcion
      .filter(p -> p.getGender().equals(Gender.FEMALE))         // filter
      .max(Comparator.comparing(Person::getAge))                // max
      .map(Person::getName);                                    // map

    oldestFemaleAge.ifPresent(name -> System.out.println("oldest female ==>" + name + "<=="));
  }
}

The core of the code is in the Main.java file.

/**
 * 
 */
public class Person {

  // **** ****
  private String name;
  private int age;
  private Gender gender;

  /**
   * constructor
   */
  public Person(String name, int age, Gender gender) {
    this.name = name;
    this.age = age;
    this.gender = gender;
  }

  /**
   * Getters.
   */
  public String getName() {
    return this.name;
  }

  public int getAge() {
    return this.age;
  }

  public Gender getGender() {
    return this.gender;
  }

  /**
   * toString
   */
  @Override
  public String toString() {
    return "Person{" +
      "name ==>" + this.name + "<==" + 
      " age: " + this.age + 
      " gender: " + this.gender + 
      "}";
  }
}

The Person class is used to define the elements of a person and the few needed methods.

/**
 * 
 */
public enum Gender {
  MALE,
  FEMALE
}

The Gender.java file holds an enumeration for the genders in our example.

Now it is time to get our code into our repository.

# **** get status to find what needs to be added ****
C:\Users\John\workspace7\JavaStreams>git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        Gender.java
        Main.java
        Person.java

nothing added to commit but untracked files present (use "git add" to track)

# **** add the files that have been created / edited ****
C:\Users\John\workspace7\JavaStreams>git add Gender.java

C:\Users\John\workspace7\JavaStreams>git add Main.java

C:\Users\John\workspace7\JavaStreams>git add Person.java

# **** get status ****
C:\Users\John\workspace7\JavaStreams>git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   Gender.java
        new file:   Main.java
        new file:   Person.java

# **** commit our changes ****
C:\Users\John\workspace7\JavaStreams>git commit -m "experiment with Java Streams (first commit)"
[master d4ea953] experiment with Java Streams (first commit)
 3 files changed, 217 insertions(+)
 create mode 100644 Gender.java
 create mode 100644 Main.java
 create mode 100644 Person.java

# **** get status ****
C:\Users\John\workspace7\JavaStreams>git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

# **** push our changes so we update our local and remote GitHub repos ****
C:\Users\John\workspace7\JavaStreams>git push origin master
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 8 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 2.14 KiB | 1.07 MiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)
To https://github.com/JohnCanessa/JavaStreams.git
   0d3b511..d4ea953  master -> master

# **** get status ****
C:\Users\John\workspace7\JavaStreams>git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

# **** check our master log ****
C:\Users\John\workspace7\JavaStreams>git log master
commit d4ea95388f0ff166649666d307698561d447ac75 (HEAD -> master, origin/master, origin/HEAD)
Author: JohnCanessa <john.canessa@gmail.com>
Date:   Mon Feb 24 09:02:41 2020 -0600

    experiment with Java Streams (first commit)

commit 0d3b51106e4313ffbea49a4531915713730dc1fa
Author: John Canessa <8019504+JohnCanessa@users.noreply.github.com>
Date:   Sat Feb 22 07:02:17 2020 -0600

    Create README.md

We start by checking git status. As expected we have edited three files so we need to add them to be included in our commit.

We check once again for git status. Seems we are ready to commit so we commit them with a descriptive message and check status.

Seems we are ready to push our changes to the GitHub repo. We do so. Once done we check status and we are up to date so all should be well. We look at our master log and find the two commits we have performed.

Hope you enjoyed and found useful this post. I have to mention that if I do not keep using something I will not become good at it or worse yet, if it is useful but I do not practice often enough, I will have to relearn the material in the future. I believe most people are like me, so I would recommend for you to try using Java Streams when possible. The more you practice be better you will get and as we have seen in this post, you will be writing shorted and easier to maintain code.

The entire code for this project can be found in my GitHub repository.

If you have comments or questions regarding this, or any other post in this blog, or if you would like for me to serve of assistance with any phase in the SDLC (Software Development Life Cycle) of a project associated with a product or service, please do not hesitate and leave me a note below. If you prefer, send me a private message using the following address:  john.canessa@gmail.com. I will reply as soon as possible.

Keep on reading and experimenting. It is the best way to learn, refresh your knowledge and enhance your developer toolset!

One last thing, thanks to all 317 subscribers!!!

John

Twitter:  @john_canessa

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.