比较和排序列表中的参数化类型



我正在试验一个简单的程序,它创建了一个银行账户,并与之绑定了交易。当我使用基本类型时,它可以完美地工作,但是我包含了添加String操作的可能性(例如撤回时的ERROR),现在我不确定如何对列表进行排序,以便字符串操作在打印时根本不出现,如果过滤,或者在排序时出现在底部。

完整源代码:

public static void main(String[] args) {
    BankAccount bankAccount = new BankAccount();
    bankAccount.addTransaction(2, TransactionType.DEPOSIT);
    bankAccount.addTransaction(100.66, TransactionType.DEPOSIT);
    bankAccount.addTransaction(2, TransactionType.WITHDRAW);
    bankAccount.addTransaction("ERROR", TransactionType.WITHDRAW);
    List<Transaction> transactions = bankAccount.getTransactions();
    List<Transaction> collect = transactions.stream()
            //Error appears over here, probably due to wrong syntax of the two next lines.
            .sorted(Comparator.comparing((Transaction tr) -> tr.getAmount()).reversed()) 
            .filter(tr -> tr.getAmount() > 0)
            .collect(toList());
    collect.forEach(tr -> System.out.println(tr));
}
private static class BankAccount {
    private List<Transaction> transactions = new ArrayList<>();
    public <T> void addTransaction(T amount, TransactionType transactionType) {
        Transaction transaction = new Transaction(amount, transactionType);
        transactions.add(transaction);
        //return 0;
    }
    public List<Transaction> getTransactions() {
        return Collections.unmodifiableList(transactions);
    }
    @Override
    public String toString() {
        return "BankAccount{" +
                "transactions=" + transactions +
                '}';
    }
}
private static class Transaction<T> {
    private final T amount;
    private final TransactionType transactionType;
    private final Date dateCreated;
    public Transaction(T amount, TransactionType transactionType) {
        this.amount = amount;
        this.transactionType = transactionType;
        this.dateCreated = new Date();
    }
    public T getAmount() {
        return amount;
    }
    public TransactionType getTransactionType() {
        return transactionType;
    }
    public Date getDateCreated() {
        return dateCreated;
    }
    @Override
    public String toString() {
        return "Transaction{" +
                "amount=" + amount +
                ", transactionType=" + transactionType +
                ", dateCreated=" + dateCreated +
                '}';
    }
}
private static enum TransactionType {
    DEPOSIT, WITHDRAW;
}

}

你的问题是,当你把Transaction<Double>Transaction<String>混合在一起时,你是在比较苹果和橙子。你的BankAccount只能容纳一种Transaction。它们要么都是Transaction<Double>要么都是Transaction<String>

现在,因为你没有你的BankAccount类参数化,它对待它像Transaction<Object>

解决方案是适当地参数化BankAccount和相应的代码。这是一个使用BankAccount<String>编码的版本。

注意:示例依赖于String数字比较,这不是一个合理的策略。我移动了filter()调用,首先删除"ERROR"事务。然后,您将需要考虑解析回传递给comparing()的函数中的数字。

    public static void main(String[] args) {
    BankAccount<String> bankAccount = new BankAccount<>();
    bankAccount.addTransaction(Double.toString(2.00), TransactionType.DEPOSIT);
    bankAccount.addTransaction(Double.toString(100.66), TransactionType.DEPOSIT);
    bankAccount.addTransaction(Double.toString(2.00), TransactionType.WITHDRAW);
    bankAccount.addTransaction("ERROR", TransactionType.WITHDRAW);
    List<Transaction<String>> transactions = bankAccount.getTransactions();
    List<Transaction<String>> collect = transactions.stream()
            .filter(tr -> !tr.getAmount().equals("ERROR"))
            .sorted(Comparator.<Transaction<String>, String> comparing(transaction -> transaction.getAmount()).reversed())
            .collect(Collectors.toList());
    collect.forEach(tr -> System.out.println(tr.getAmount() + " " + tr.getType().name()));
}
public static class BankAccount<T> {
    private List<Transaction<T>> transactions = new ArrayList<>();
    public void addTransaction(T amount, TransactionType transactionType) {
        Transaction<T> transaction = new Transaction <>(amount, transactionType);
        transactions.add(transaction);
    }
    public List<Transaction<T>> getTransactions() {
        return Collections.unmodifiableList(transactions);
    }
}
public static class Transaction<T> {
    private final T amount;
    private final TransactionType transactionType;
    private final Date dateCreated;
    public Transaction(T amount, TransactionType transactionType) {
        this.amount = amount;
        this.transactionType = transactionType;
        this.dateCreated = new Date();
    }
    public T getAmount() {
        return amount;
    }
    public TransactionType getType(){
        return transactionType;
    }
    public Date getDateCreated(){
        return dateCreated;
    }
}
public enum TransactionType {
    DEPOSIT, WITHDRAW;
}

如果你想比较(排序)不同类型的对象,为什么不为它编写自己的比较器呢?

的例子:

List<Transaction> collect = transactions.stream()
    .sorted((t1, t2) -> {
        if (t1.getAmount() instanceof String && t2.getAmount() instanceof String) {
            return String.class.cast(t1.getAmount()).compareTo(String.class.cast(t2.getAmount()));
        } else if (t1.getAmount() instanceof String) {
            return 1;
        } else if (t2.getAmount() instanceof String) {
            return -1;
        } else {
            return new BigDecimal(t1.getAmount().toString()).compareTo(new BigDecimal(t2.getAmount().toString())); //ugly hack
        }
    })
    .filter(tr -> tr.getAmount() instanceof Number && Number.class.cast(tr.getAmount()).doubleValue() > 0) //next ugly hack
    .collect(Collectors.toList());
collect.forEach(System.out::println);

最新更新