1

I have these two functions which are basically the same:

private Order getOrder( List<Order> orders, String gcsId )
{
    Predicate<Order> predicate = c -> c.getGcsId().equals( gcsId );
    Order obj = orders.stream().filter( predicate ).findFirst().get();
    return obj;
}

private OrderLine getOrderLine( List<OrderLine> orderLines, String gcsId )
{
    Predicate<OrderLine> predicate = c -> c.getGcsId().equals( gcsId );
    OrderLine obj = orderLines.stream().filter( predicate ).findFirst().get();
    return obj;
}

The only difference is the type of the first parameter. How can I create a single function with the first parameter having a variable type?

Edit: This is how I call those functions in another method of the same class:

Order order = getOrder( orders, orderId );
OrderLine orderLine = getOrderLine( order.getOrderLines(), orderLineId );
7
  • 1
    Can you create an interface that both classes implent, then use the interface as the parameter type? Commented Jun 8, 2017 at 6:36
  • Do OrderLine and Order share any common super class or interface? Commented Jun 8, 2017 at 6:37
  • @luk2302 No, they don't have any interface now. Commented Jun 8, 2017 at 6:38
  • Well, from the name is it necessary ? they seems to share the same variable, so is there any relation between those ? (I believe they should) Commented Jun 8, 2017 at 6:38
  • @AxelH an order (got from the first function) includes a list of orderLines Commented Jun 8, 2017 at 6:39

5 Answers 5

3

First you should create an interface like that and your classes should implement this interface:

public interface IOrder {

   String getGcsId();
}

public class Order implements IOrder {
  // Content of your class
}

public class OrderLine implements IOrder {
  // Content of your class
}

After that you can write your method like that using generics:

private <T extends IOrder> T getOrder( List<T> orders, String gcsId )
{
    Predicate<T> predicate = c -> c.getGcsId().equals( gcsId );
    T obj = orders.stream().filter( predicate ).findFirst().get();
    return obj;
}
Sign up to request clarification or add additional context in comments.

Comments

2

Either make them implement a common interface, which defined the getGcsId() method, and use

private <T extends CommonInterface> T getFirstWithGcsId(List<T> orders, String gcsId) {
    Predicate<T> predicate = c -> c.getGcsId().equals(gcsId);
    T obj = orders.stream().filter(predicate).findFirst().get();
    return obj;
}

Or change the signature of the method to pass it a function which knows how to extract the gcsId:

private <T> T getFirstWithGcsId(List<T> orders, String gcsId, Function<T, String> gcsIdExtractor) {
    Predicate<T> predicate = c -> gcsIdExtractor.apply(c).equals(gcsId);
    T obj = orders.stream().filter(predicate).findFirst().get();
    return obj;
}

But this method is so simple that, frankly, if you don't have any common interface, I would just inline it. It's basically one line of code:

Order firstOrder = orders.stream().filter(o -> o.getGcsId().equals(gcsId)).findFirst().get();

You should also avoid calling get() on an Optional in general. Rather prefer something like

Order firstOrder = orders.stream().filter(o -> o.getGcsId().equals(gcsId)).findFirst().orElseThrow(() -> new IllegalStateException("no first order with gcsId " + gcsId));

Comments

1

If you give a List of Order you return an Ornder, if you give an define a generic method instead:

private <T extends Foo> T getOrder(List<T > orders, String gcsId) {
    Predicate<T> predicate = c -> c.getGcsId().equals(gcsId);
    T obj = orders.stream().filter(predicate).findFirst().get();
    return obj;
}

where Foo interface is

interface Foo {
    String getGcsId();
}

class OrderLine implements Foo {

    @Override
    public String getGcsId() {
        return something;
    }

}

class Order implements Foo {

    @Override
    public String getGcsId() {
        return something;
    }

}

Comments

1

You should create an Interface. See below:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class SomeFunctionsRefactored {

    public static void main(String[] args) {
        Order simpleOrder = new SimpleOrder();
        Order lineOrder = new LineOrder();
        String gcsId;
        List<Order> simpleOrders = new ArrayList(Arrays.asList(simpleOrder));
        List<Order> lineOrders = new ArrayList(Arrays.asList(lineOrder));

        Order order = getOrder(simpleOrders, "Hi I'm a simple order");
        System.out.println(order.getGcsId());  // Hi I'm a simple order

        order = getOrder(lineOrders, "Hi I'm a line order");
        System.out.println(order.getGcsId());  // Hi I'm a line order

    }

    private static Order getOrder(List<Order> orders, String gcsId) {
        Predicate<Order> predicate = c -> c.getGcsId().equals(gcsId);
        return orders.stream().filter(predicate).findFirst().get();
    }

The interface:

interface Order {
    public String getGcsId();
}

class SimpleOrder implements Order {
    String gcsId = "Hi I'm a simple order";

    public String getGcsId() {
        return gcsId;
    }

}

class LineOrder implements Order {
    String gcsId = "Hi I'm a line order";

    public String getGcsId() {
        return gcsId;
    }
}

Comments

0
  • One way that you can perform instance of test after taking list as a parameter, but your List is parameterized. if you have anything that is parameterized,

    List<Foo> fooList = new ArrayList<Foo>();

The Generics information will be erased at runtime. Instead, this is what the JVM will see

   `List fooList = new ArrayList();`
  • This is called type erasure. The JVM has no parameterized type information of the List (in the example) during runtime.

    Since the JVM has no information of the Parameterized type on runtime,

    there's no way you can do an instanceof of ArrayList.

So better you keep your both function to work.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.