0

I have been doing some performance checks on mutable and inmutable lists. I have created following test. The test is very simple and I would like to have a notion on what aspects should I take in account to improve the lambda expressions to have a performance that is the closest or better to the for loop.

Util now, I have made a list of some of them:

  1. Sorted lists will improve the performance.
  2. Inmutable collections also improves the performance.
  3. Use of optional decreases the performance.

What other aspects would affect?

Enhanced For - Elapsed time: 141

For - Elapsed time: 109

Iterator - Elapsed time: 125

Stream - Elapsed time: 172

Parallel Stream - Elapsed time: 94

Optional Stream - Elapsed time: 156

Optional Parallel Stream - Elapsed time: 140

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

class MyObject {
    private Integer id;
    private String name;
    private String message;
    private MySecondObject object;
    public MyObject(Integer id, String name, String message, MySecondObject object) {
        this.id = id;
        this.name = name;
        this.message = message;
        this.object = object;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    public MySecondObject getObject() {
        return object;
    }
    public void setObject(MySecondObject object) {
        this.object = object;
    }
    @Override
    public int hashCode() {
        int hash = 8;
        hash = 14 * hash + Objects.hashCode(this.id);
        hash = 14 * hash + Objects.hashCode(this.name);
        hash = 14 * hash + Objects.hashCode(this.message);
        hash = 14 * hash + Objects.hashCode(this.object);
        return hash;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final MyObject other = (MyObject) obj;
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        if (!Objects.equals(this.message, other.message)) {
            return false;
        }
        if (!Objects.equals(this.id, other.id)) {
            return false;
        }
        return Objects.equals(this.object, other.object);
    }
    @Override
    public String toString() {
        return "\nMyObject{" + "id=" + id + ", name=" + name + ", message=" + message + ", object=" + object + '}';
    }
}

class MySecondObject {
    private Integer id;
    private String name;
    private String message;
    public MySecondObject(Integer id, String name, String message) {
        this.id = id;
        this.name = name;
        this.message = message;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }
    @Override
    public int hashCode() {
        int hash = 7;
        hash = 13 * hash + Objects.hashCode(this.id);
        hash = 13 * hash + Objects.hashCode(this.name);
        hash = 13 * hash + Objects.hashCode(this.message);
        return hash;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final MySecondObject other = (MySecondObject) obj;
        if (!Objects.equals(this.name, other.name)) {
            return false;
        }
        if (!Objects.equals(this.message, other.message)) {
            return false;
        }
        return Objects.equals(this.id, other.id);
    }
    @Override
    public String toString() {
        return "MySecondObject{" + "id=" + id + ", name=" + name + ", message=" + message + '}';
    }
}

class MyObjectUtil {
    private MyObjectUtil() {
    }
    public static List<?> getList() {
        List<MyObject> myObjectList = new ArrayList<>();
        final ThreadLocalRandom r = ThreadLocalRandom.current();
        for (int i = 0; i < 1_000_000; i++) {
            myObjectList.add(new MyObject(r.nextInt(), "Name " + i, "Message " + i, new MySecondObject(r.nextInt(), "Second Object " + i, "Message " + i)));
        }
        myObjectList.add(new MyObject(r.nextInt(), "Name " + 0, "Message " + 0, null));
        myObjectList.sort((a, b) -> a.getId().equals(b.getId()) ? 0 : a.getId()> b.getId()? 1 : -1);
        return Collections.unmodifiableList(myObjectList);
        //return myObjectList;
    }
}

public class MyObjectListTest {

    public static void main(String[] args) {
        List<MyObject> myObjectList = (List<MyObject>) MyObjectUtil.getList();

        long begin = System.currentTimeMillis();
        List<Integer> idList = new ArrayList<>();
        if (myObjectList != null) {
            for (MyObject object : myObjectList) {
                if (object != null && object.getObject() != null) {
                    idList.add(object.getObject().getId());
                }
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("\nEnhanced For - Elapsed time: " + (end - begin));

        idList = null;
        begin = System.currentTimeMillis();
        idList = new ArrayList<>();
        if (myObjectList != null) {
            for (int i = 0; i < myObjectList.size(); i++) {
                MyObject o = myObjectList.get(i);
                if (o != null && o.getObject() != null) {
                    idList.add(o.getObject().getId());
                }
            }
        }
        end = System.currentTimeMillis();
        System.out.println("\nFor - Elapsed time: " + (end - begin));

        idList = null;
        begin = System.currentTimeMillis();
        idList = new ArrayList<>();
        if (myObjectList != null) {
            for (Iterator<MyObject> it = myObjectList.iterator(); it.hasNext();) {
                MyObject m = it.next();
                if (m.getObject() != null) {
                    idList.add(m.getObject().getId());
                }
            }
        }
        end = System.currentTimeMillis();
        System.out.println("\nIterator - Elapsed time: " + (end - begin));

        idList = null;
        begin = System.currentTimeMillis();
        if (myObjectList != null) {
            idList = myObjectList
                    .stream()
                    .map(MyObject::getObject)
                    .filter(Objects::nonNull)
                    .map(MySecondObject::getId)
                    .collect(Collectors.toList());
        }
        end = System.currentTimeMillis();
        System.out.println("\nStream - Elapsed time: " + (end - begin));

        idList = null;
        begin = System.currentTimeMillis();
        if (myObjectList != null) {
            idList = myObjectList
                    .parallelStream()
                    .map(MyObject::getObject)
                    .filter(Objects::nonNull)
                    .map(MySecondObject::getId)
                    .collect(Collectors.toList());
        }
        end = System.currentTimeMillis();
        System.out.println("\nParallel Stream - Elapsed time: " + (end - begin));

        idList = null;
        begin = System.currentTimeMillis();
        idList = Optional.ofNullable(myObjectList)
                .orElseGet(Collections::emptyList)
                .stream()
                .map(MyObject::getObject)
                .filter(Objects::nonNull)
                .map(MySecondObject::getId)
                .collect(Collectors.toList());
        end = System.currentTimeMillis();
        System.out.println("\nOptional Stream - Elapsed time: " + (end - begin));

        idList = null;
        begin = System.currentTimeMillis();
        idList = Optional.ofNullable(myObjectList)
                .orElseGet(Collections::emptyList)
                .parallelStream()
                .map(MyObject::getObject)
                .filter(Objects::nonNull)
                .map(MySecondObject::getId)
                .collect(Collectors.toList());
        end = System.currentTimeMillis();
        System.out.println("\nOptional Parallel Stream - Elapsed time: " + (end - begin));
    }
}

Thanks.

ouribeb930
  • 63
  • 4
  • I'm just trying to measure the performance between the different approaches. All the different scenarios do the same process. I'm trying to compare. It seems that the lambda expressions perform better when there is more data. – ouribeb930 May 28 '18 at 20:22
  • Compare they separated, since the VM will be "hot" continuing the code – Marcos Vasconcelos May 28 '18 at 20:27
  • @MarcosVasconcelos Hi, thanks for the tip. I think I did not phrased correctly the question. So I will edit it. – ouribeb930 May 28 '18 at 20:29
  • Any Java performance measurement taking less than one second is a nonsense. Doing anything but using JMH is wasting time and risking wrong results. Anyway, I'm rather sure, I've seen a lint benchmarking question on SO already. – maaartinus May 29 '18 at 13:07

0 Answers0