我有一堂課,其中幾個方法回圈遍歷產品串列。
我想知道是否有辦法減少回圈數量,因為它們真的只做一次檢查?
某種方式來實作一個函式并傳遞一個謂詞?我昨天發現了Lambdas,但不確定它是否適用于這里。
public class Stock {
private ArrayList<Products> _productList;
public Stock(){}
public Boolean addProduct(Products product){
return _productList.contains(product) && _productList.add(product);
}
public int obtainPos(int code){
for(int i=0; i < _productList.size(); i )
if(_productList.get(i).getCode() == code)
return i;
return -1;
}
public void removeProduct(int code){
int pos = obtainPos(code);
if(pos >=0)
_productList.remove(pos);
else
System.out.println("Error - Product not found.");
}
public int productAmount(){ return _productList.size(); }
public int amountType(String type){
int i = 0;
for(Products pr : _productList)
if(pr.getClass().getSimpleName().equals(type))
i ;
return i;
}
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
for(Products pr : _productList)
sb.append(pr.getName()).append(" \n");
return sb.toString();
}
public void itemsToRemove(String reason){
StringBuilder st = new StringBuilder();
for(Products pr : _productList)
st.append(pr.getName()).append(" - ").append(pr.withdraw(reason)).append("\n");
System.out.println(st.toString());
}
}
uj5u.com熱心網友回復:
一種減少回圈數量的方法
某種方式來實作一個函式并傳遞謂詞?我昨天發現了 Lambdas,但不確定它是否適用于此。
如果您正在考慮使用lambdas作為可能的選項,則可以使此代碼更加簡潔。
它只需要關于Java 8 lambda 運算式和流主題的非常基本的知識。作為第一步,我建議您熟悉本教程。
讓我們一一重構這些方法。
removeProduct()
您可以使用介面的方法替換方法內的所有代碼并用removeProduct()一行obtainPos()代碼,如下所示:removeIf()Collection
products.removeIf(product -> product.getCode() == code);
方法removeIf()需要一個Predicate(產生布林值的函式),它將洗掉與給定謂詞匹配的每個元素。
true如果集合被修改或否則,此方法回傳false。
getAmountByType()
此方法可以通過使用僅包含兩個操作的微小流來實作:filter()和count().
為了創建以產品串列作為源的流,您必須呼叫stream()串列上的方法。
方法filter()是一種中間操作(產生新流的操作)。除了removeIf()期望predicate 之外,相反,removeIf()它將在結果流中僅保留與給定 predicate 匹配的元素。
方法count()是終端操作(關閉流并回傳值或執行最終操作的操作,如 forEach),將流中的元素數回傳為long。
toString()
此方法還歸結為包含兩個操作的流map():和collect()。
方法map()是一種中間操作。它需要一個Function(一個接受一個物件并產生另一個物件的函式,通常是不同型別的)。我們可以使用 lambda 運算式(如下面的代碼所示)或方法參考 Product::getName來實作從產品中提取名稱的函式。
所以在這種情況下,map()會將產品Stream<Product>流轉換為產品名稱流Stream<String>。
Method count() is terminal operation, that expects a Collector (a special object that populates a mutable container with elements of the stream and produces a result of the execution of the stream pipeline).
Here we can use a built-in collector Collectors.joining() which is designed to join String elements into a single string.
addProduct()
Although this method is capable of adding new products, there's a logical flow in it:
- It will return
trueif the list of products already contains the given product, andfalsefor a new product (that's a bit counterintuitive). - It will always add the given product to the list, regardless whether it's a duplicate or not. Because of that, the process of checking if the given product already exists in the list becomes pointless.
To fix it, the method could be reimplemented in two ways:
- allow duplicates and add every given product;
- discard duplicated products.
In both cases implementation is a single statement:
return products.add(product);
但是為了拒絕重復,您需要將基礎集合設為 a HashSet(請注意,此更改無論如何都不會影響此處列出的其余代碼)。假設hashCode/equals合約在Product類中正確實作,方法add將false在重復的情況下回傳,并且true如果一個集合被修改(即產品被成功添加)。
public class ProductInStock {
private Set<Product> products = new HashSet<>(); // if you change it to List<Products> products = new ArrayList<>(); nothing will break
public boolean addProduct(Product product) {
return products.add(product);
}
public boolean removeProduct(int code){
return products.removeIf(product -> product.getCode() == code);
}
public int productAmount(){
return products.size();
}
public int getAmountByType(String type) {
return (int) products.stream()
.filter(product -> product.getType().equals(type))
.count();
}
@Override
public String toString() {
return products.stream()
.map(product -> product.getName())
.collect(Collectors.joining("\n"));
}
}
main()- 一個小演示。
public static void main(String[] args) {
ProductInStock productInStock = new ProductInStock();
productInStock.addProduct(new Product("Milk", 11, "dairyProducts"));
productInStock.addProduct(new Product("Milk", 11, "dairyProducts")); // duplicate
productInStock.addProduct(new Product("Milk", 11, "dairyProducts")); // duplicate
productInStock.addProduct(new Product("Cottage cheese", 12, "dairyProducts"));
productInStock.addProduct(new Product("Cream cheese", 13, "dairyProducts"));
productInStock.addProduct(new Product("Bread", 21, "bakedProducts"));
productInStock.addProduct(new Product("Muffin", 22, "bakedProducts"));
productInStock.addProduct(new Product("Cookies", 23, "bakedProducts"));
System.out.println("Amount by type");
System.out.println("Baked Products:\t" productInStock.getAmountByType("bakedProducts"));
System.out.println("Dairy Products:\t" productInStock.getAmountByType("dairyProducts"));
productInStock.removeProduct(12);
productInStock.removeProduct(21);
System.out.println("\nProduct Stock after removal:\n" productInStock);
}
輸出
Amount by type
Baked Products: 3
Dairy Products: 3
Product Stock after removal:
Muffin
Cookies
Milk
Cream cheese
旁注:
_如果 Java 中變數名的前面不符合命名約定,則使用下劃線。在需要區分同名的引數和欄位時,我們有關鍵字this。- 使產品型別由 an 表示
enum而不是依賴于字串值會更方便。
uj5u.com熱心網友回復:
您可以在所需的單個回圈中使用類似 if 陳述句的內容來決定您要采取的操作,例如:
public void loopClass(int decision) {
for(Products pr : _productList) {
if (decision == choice1) {
//do something
}
if (decision == choice2) {
//do something else
}
//etc etc
}
}
查看您的代碼,我認為您設定回圈的方式沒有任何問題。您現在設定它的方式似乎非常簡潔明了。我建議保持原樣。
uj5u.com熱心網友回復:
您可以使用 aHashMap<Integer,Products>而不是ArrayList<Products>. 這將允許您消除obtainPos和減少O(1) 操作addProduct。removeProduct
uj5u.com熱心網友回復:
正如您提到的 lambdas,是的,Stream或者List.removeIf它們有幫助。不幸的是,它們是一項高級功能,可能稍后會處理。為了展示它會對你的 for 回圈做什么:
public class Stock {
private final List<Product> productList = new ArrayList<>();
public Stock() {
}
public Stock(List<Product> productList) {
this.productList.addAll(productList);
}
public boolean addProduct(Product product) {
return productList.contains(product) || productList.add(product);
}
//public int obtainPos(int code){
public Optional<Product> obtainByCode(int code) {
productList.stream()
.filter(pr -> pr.getCode() == code)
.findAny();
}
public void removeProduct(int code) {
obtainByCode(code).ifPresentOrElse(pr -> productList.remove(pr),
() -> System.out.println("Error - Product not found."));
}
public int productAmount() {
return productList.size();
}
public int amountType(String type) {
return (int) productList.stream()
.filter(pr -> pr.getClass().getSimpleName().equals(type))
.count();
}
@Override
public String toString() {
return productList.stream()
.map(Product::getName)
.map(nm -> nm " \n")
.collect(Collectors.joining());
// return productList.stream()
// .map(Product::getName)
// .collect(Collectors.joining(" \n"); // At the end without \n.
}
public void itemsToRemove(String reason) {
String items = productList.stream()
.map(Product::getName)
.map(nm -> String.format("%s - %s\n", nm, reason))
.collect(Collectors.joining(" \n");
System.out.println(items);
}
}
評論:
- 我認為這個名字
Products應該是Product。 addProduct&&在我認為您的意思是 OR (ELSE) 的地方使用了 AND (THEN )||。當產品已經存在時,添加的產品將被丟棄。不確定是否需要。AProduct.equals(on code?) 必須存在。obtainPos引入了一個內部動態特性(當removeProduct被呼叫時)。更好的回傳Optional<Product>,這是一個型別安全的包裝器;見ifPresent。- 像下劃線這樣的前綴在java中不是用法。您可以使用相同的命名引數來消除歧義
this.field。 - 未更改(=未替換)的欄位可以是
final. - 針對介面 (
List) 而不是實作類 (ArrayList) 進行編程更具表現力。 - There are primitive types like
int, boolean, char, long. And there are wrapper classesInteger, Boolean, Character, Long. Use the primitive types as more logical. Only for generic parameter types this cannot be done:List<Integer>. - A lambda is either
pr -> pr.getName()or a method referenceProduct::getName.
Already mentioned is that Map<Integer, Product> productsByCode = new HashMap<>(); would prove a fast access of a Product by code.
The for loops you have are all quite different, so much gain is implausible. However a Stream isolates conditions and such, and might be more flexible.
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/451790.html
上一篇:Pyhton3-在某些情況下可以使用for回圈更改您正在回圈的容器嗎?
下一篇:在for回圈中組合資料框列的函式
