I consider a very easy task parse a nested object asnwered by a soap webservice using Java 8 streams. Nevertheless, I am quite confused when I think about the correct or most appropriate approach to use. I know it will depend on circunstances and there will never be a simple recipe. I have been reading for the last two weeks where and how to use stream but I couldn't reach a final conclusion about few options. I put bellow four approaches I would appreciatte if someone could give technical opnion if I understood correctly the real application based on very common requirements when dealing with soap client.
I am not loking for a simple answer like "Here I do successfully this way so you can copy and paste similar idea". I am really interested to understand if I am applying properly what I have read so far.
Firstly, my nested objects answered by web service:
//first level
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "OndernemingAlgemeenType", propOrder = {
    "adressen",
    ... others properties
})
@XmlSeeAlso({
    Onderneming20Type.class
})
public class OndernemingAlgemeenType
{
    @XmlElement(name = "Adressen")
    protected AdresOndernemingLijstType adressen;
    ... others elements
}   
//second level that returns a list
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AdresOndernemingLijstType", propOrder = {
    "adres"
})
public class AdresOndernemingLijstType {
    @XmlElement(name = "Adres", required = true)
    protected List<AdresOndernemingType> adres; 
    ...
}
// third level used to filter the list and return just one AdresOndernemingType
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AdresOndernemingType", propOrder = {
    "type"
})
public class AdresOndernemingType
    extends AdresOndernemingBasisType{
    @XmlElement(name = "Type", required = true)
    protected TypeAdresOndernemingType type;
}
// fourth level
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AdresOndernemingBasisType", propOrder = {
   ... not relevant for this question
})
@XmlSeeAlso({
    AdresOndernemingType.class
})
public class AdresOndernemingBasisType
    extends AdresBasisType
{
       ... not relevant for this question
}
// fifth level and finally, the desired fields (street and city)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AdresBasisType", propOrder = {
    "straat", //street
    "gemeente" //city
})
@XmlSeeAlso({
    AdresOndernemingDeelnemingInType.class,
    AdresOndernemingBasisType.class
})
public class AdresBasisType {
    @XmlElement(name = "Straat")
    protected StraatRR20Type straat;
    @XmlElement(name = "Gemeente")
    protected GemeenteOptioneel20Type gemeente;
// Approaches with its understanding
Approach 1: I understand that this is null exception safe. I mean, in case either getAdressen or getAdres is null there will be no exception at all and no address printed.
private void printOptionalDidactic(){
        Optional<AdresOndernemingLijstType> op = Optional.ofNullable(onderneming.getAdressen());
        op.map(AdresOndernemingLijstType::getAdres).get().stream().filter(Objects::nonNull)
        .filter(o -> "001".equals(o.getType().getCode().getValue().getValue()))
        .map(x -> System.out.println("My street is: ".concat(x.getStraat())));
}       
Approach 2: Assuming that there will be never a null element (minOccurs="1" in xsd for all) so using Optional would be pointless
private void printNoOptionalDidactic(){     
        onderneming.getAdressen().getAdres().stream()
        .filter(o -> "001".equals(o.getType().getCode().getValue().getValue()))
        .map(x -> System.out.println("My street is: ".concat(x.getStraat())));
}
Approach 3: Assuming I want to print all streets and I don't care about filtering, I understand there is no advantage at all to use flatMap before forEach Replace nested loop with Java 8 flatmap
private void printForEachDidactic(){
        onderneming.getAdressen().getAdres().stream()
        .forEach(x -> System.out.println("My street is: ".concat(x.getStraat())));
}       
Approach 4 Since no shared resource is used by the predicates and functions used in the process, I understand I could use parallelism. Nevertheless, provided that it is little data so I have no real gain on it Should I always use a parallel stream when possible?
private void printParallelDidactic(){
        onderneming.getAdressen().getAdres().parallelStream()
        .filter(o -> "001".equals(o.getType().getCode().getValue().getValue()))
        .map(x -> System.out.println("My street is: ".concat(x.getStraat())));
}
 
    