/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
	public static void main (String[] args) throws java.lang.Exception
	{
		List<Exon> listExon = new ArrayList<>(List.of(
                new Exon(1L, new IncomeCode("45"), LocalDate.of(2021, 1, 1), "4"),
                new Exon(2L, new IncomeCode("21"), LocalDate.of(2022, 1, 1), "5"),
                new Exon(3L, new IncomeCode("33"), LocalDate.of(2023, 1, 1), "2"),
                new Exon(4L, new IncomeCode("45"), LocalDate.of(2021, 1, 1), "4")
        ));

        List<Sup> listSup = new ArrayList<>(List.of(
                new Sup(1L, new IncomeCode("45"), null, LocalDate.of(2021, 1, 1), "4"),
                new Sup(2L, new IncomeCode("21"), null, LocalDate.of(2022, 1, 1), "5"),
                new Sup(3L, new IncomeCode("33"), null, LocalDate.of(2023, 1, 1), "2")
        ));

        List<List<Object>> listRes = new ArrayList<>(Stream.concat(listExon.stream(), listSup.stream())
                .collect(Collectors.groupingBy(obj -> {
                    if (obj instanceof Exon) {
                        Exon exon = (Exon) obj;
                        return String.format("%s-%s-%s", exon.getIncomeCode(), exon.getEndDate(), exon.getCodeRef());
                    }
                    Sup sup = (Sup) obj;
                    return String.format("%s-%s-%s", sup.getIncomeCode(), sup.getEndDate(), sup.getCodeRef());
                })).values());

        for(List<Object> l: listRes){
            System.out.println(l);
        }
	}
	
	static class Exon  {
        private Long id;
        private IncomeCode incomeCode;
        private LocalDate endDate;
        String codeRef;

        public Exon(Long id, IncomeCode incomeCode, LocalDate endDate, String codeRef) {
            this.id = id;
            this.incomeCode = incomeCode;
            this.endDate = endDate;
            this.codeRef = codeRef;
        }

        public Long getId() {
            return id;
        }

        public IncomeCode getIncomeCode() {
            return incomeCode;
        }

        public LocalDate getEndDate() {
            return endDate;
        }

        public String getCodeRef() {
            return codeRef;
        }

        @Override
        public String toString() {
            return String.format("%s{%s %s %s}", getClass().getSimpleName(), incomeCode, endDate, codeRef);
        }
    }

    static class Sup {
        private Long id;
        private IncomeCode incomeCode;
        private LocalDate startDate;
        private LocalDate endDate;
        String codeRef;

        public Sup(Long id, IncomeCode incomeCode, LocalDate startDate, LocalDate endDate, String codeRef) {
            this.id = id;
            this.incomeCode = incomeCode;
            this.startDate = startDate;
            this.endDate = endDate;
            this.codeRef = codeRef;
        }

        public Long getId() {
            return id;
        }

        public IncomeCode getIncomeCode() {
            return incomeCode;
        }

        public LocalDate getStartDate() {
            return startDate;
        }

        public LocalDate getEndDate() {
            return endDate;
        }

        public String getCodeRef() {
            return codeRef;
        }

        @Override
        public String toString() {
            return String.format("%s{%s %s %s}", getClass().getSimpleName(), incomeCode, endDate, codeRef);
        }
    }

    static class IncomeCode {
        private String code;

        public IncomeCode(String code) {
            this.code = code;
        }

        public String getCode() {
            return code;
        }

        @Override
        public String toString() {
            return code;
        }
    }
}