Prpaa
Prpaa

Reputation: 245

Java Stream code improvement

I have a map of cars Map<String, List<Car>> which can be returned by getCarsMap() method where key is model of car , and value is list of cars of same model.

I would like to improve Car addCar(Car car) function. For now I wrote this a bit ugly peace of code

public Car addCar(Car car) {
    if(getCarsMap().entrySet().stream().anyMatch(es -> es.getKey().equals(car.getModel()))){
        if(!getCarsMap().get(car.getModel()).contains(car)){
            getCarsMap().get(car.getModel()).add(car);
        }
    }else{
        List<Car> tmpList = new ArrayList<Car>();
        tmpList.add(car);
        getCarsMap().put(car.getModel(), tmpList) ;
    }
    return car;
}

Also, need to write something similar for removeCar(Car car) but hope it's gonna be easier with some nice addCar method as a template.

Upvotes: 1

Views: 155

Answers (3)

Daniel Rodriguez
Daniel Rodriguez

Reputation: 617

The tips:

  • Use Set instead of List because Set doesn't allow duplicates.

  • Use contains to check if an element is in a collection, regardless of whether it's a List or a Set. (Car class must have a equals method that compares the field values.)

  • Return a boolean to indicate if the collection was modified as a result of the operation. This is what Java collections do.

The code:

public boolean addCar(Car car) {
    Map<String, Set<Car>> carsMap = getCarsMap();
    if (!carsMap.containsKey(car.getModel())) {
        carsMap.put(car.getModel(), new HashSet<>(Arrays.asList(car)));
        return true;
    }
    if (!carsMap.get(car.getModel()).contains(car)) {
        return carsMap.get(car.getModel()).add(car);
    }
    return false;
}

Upvotes: 1

Sergii Getman
Sergii Getman

Reputation: 4381

My idea - rely on compute method of Map.

So my method populateMapWith process current map according to your case:

  • if value list is empty - create new one, add element, add to map

  • if present, just add element to current list

as well as removeFromMap according to removing.

I illustrated it with Object class, just to simplify the case

public class BaseTest {

    private Map<String, List<Object>> myMap = new HashMap<>();

    @Test
    public void testName() throws Exception {
        Object car1 = new Object() {
            @Override
            public String toString() {
                return "car1";
            }
        };

        Object car2 = new Object() {
            @Override
            public String toString() {
                return "car1";
            }
        };

        populateMap(car1);
        populateMap(car2);

        assertEquals(2, myMap.get("car1").size());

        removeFromMap(car2);

        assertEquals(1, myMap.get("car1").size());
    }

    private void populateMap(Object o) {
        myMap.computeIfAbsent(o.toString(), key -> new ArrayList<>()).add(o);
    }

    private void removeFromMap(Object o) {
        myMap.computeIfPresent(o.toString(), (key,list) -> { list.remove(o); return list;});
    }
}

UPD : improved methods after discussion with Holger

Upvotes: 1

Amita
Amita

Reputation: 974

if(!getCarsMap().get(car.getModel()).contains(car))

It seems that you do not wish to have duplicates. So instead of a List, you must use a Set, that does not add duplicate elements, like:

Map<String, Set<Car>> carmap = getCarsMap();

getBoatsMap().put(car.getModel(), tmpList) ;

This doesn't make sense. Putting a car in a map that is supposed to have boats is bewildering. However, I assume to go with it.

So we can have:

Set<Cars> tempcar = new HashSet<>();
tempcar.add(car);
getBoatsMap().put(car.getModel(),tempcar);

public Car addCar(Car car)

The return type of addCar method. A method returns the object that it manipulates. Here, the map is manipulated and not the object. It should be something like:

public Map<String,Set<Car>> addCar(Car car)

So we can have the following code:

 public HashMap<String,Set<Car>> addCar(Car car){
        Map<String, Set<Car>> carmap = getCarsMap();
        if(carmap.containsKey(car.getModel())){
            HashSet<Car> carset = carmap.get(car.getModel());
            carset.add(car);
            map.put(car.getModel(),carset);
        }else{
            carmap = getBoatsMap();
            Set<Cars> tempcar = new HashSet<>();
            tempcar.add(car);
            carmap.put(car.getModel(),tempcar);
        }
        return carmap;
   }

This can be the basic template for you to move on. However, this also can be further optimized. A deeper study of Java Collections API and Java 8 can provide you with better ideas.

For, removeCar(), the method signature can be:

public Car removeCar(Car) 

UPDATE I see in comment that getBoatsMap() is a mistake. So the code is:

public Map<String, Set<Car>> addCar(Car car){
    Map<String, Set<Car>> carmap = getCarsMap();
    if(carmap.containsKey(car.getModel())){
        HashSet<Car> carset = carmap.get(car.getModel());
        carset.add(car);
        map.put(car.getModel(),carset);
    }else{
        Set<Cars> tempcar = new HashSet<>();
        tempcar.add(car);
        carmap.put(car.getModel(),tempcar);
    }
    return carmap;
}

Upvotes: 1

Related Questions